From 143b30e099a72686ee6077b637cf5c2d8bd14e21 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Fri, 17 Nov 2023 09:31:43 +0100 Subject: [PATCH 01/24] Upgraded gateway to Chirpstack V4. Need to add tags. --- .prettierrc.js | 2 +- package-lock.json | 719 ++++++++++++++++-- package.json | 2 + resources/chirpstack-state.proto | 18 +- .../chirpstack-gateway.controller.ts | 23 +- .../chirpstack/chirpstack-mqtt-message.dto.ts | 13 +- .../dto/chirpstack/common-location.dto.ts | 16 +- .../detailed-gateway-response.dto.ts | 17 +- .../dto/chirpstack/gateway-contents.dto.ts | 2 +- .../dto/chirpstack/gateway-response.dto.ts | 26 +- .../chirpstack/gateway-stats.response.dto.ts | 4 +- .../dto/chirpstack/list-all-gateways.dto.ts | 6 +- .../chirpstack/single-gateway-response.dto.ts | 14 +- .../dto/chirpstack/update-gateway.dto.ts | 4 +- src/helpers/date.helper.ts | 17 +- .../chirpstack/gateway-boostrapper.service.ts | 40 +- .../gateway-status-history.service.ts | 15 +- .../chirpstack/network-server.service.ts | 10 +- .../chirpstack/service-profile.service.ts | 2 +- .../chirpstack-mqtt-listener.service.ts | 24 +- .../gateway-persistence.service.ts | 1 + .../data-management/search.service.ts | 44 +- .../device-management/iot-device.service.ts | 2 +- 23 files changed, 811 insertions(+), 210 deletions(-) diff --git a/.prettierrc.js b/.prettierrc.js index 22a90f6f..af9c6e78 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,7 +1,7 @@ module.exports = { trailingComma: "es5", tabWidth: 4, - printWidth: 90, + printWidth: 100, semi: true, singleQuote: false, useTabs: false, diff --git a/package-lock.json b/package-lock.json index 58a8173a..b1db2dbb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "0.0.1", "license": "Mozilla Public License Version 2.0", "dependencies": { + "@chirpstack/chirpstack-api": "^4.5.1", + "@grpc/grpc-js": "^1.9.9", "@nestjs/axios": "^2.0.0", "@nestjs/common": "^9.1.2", "@nestjs/config": "^2.2.0", @@ -798,6 +800,17 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@chirpstack/chirpstack-api": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@chirpstack/chirpstack-api/-/chirpstack-api-4.5.1.tgz", + "integrity": "sha512-GAKb2/EAodgruOs4TF7la3EpZwXrlNJq8uQASvmRRTqFA4XUXsyna1BB+2QZmXxRt/VOA1POM/BsYUY47b2KIQ==", + "dependencies": { + "@grpc/grpc-js": "^1.9.0", + "@mapbox/node-pre-gyp": "^1.0.11", + "@types/google-protobuf": "^3.15.6", + "google-protobuf": "^3.21.2" + } + }, "node_modules/@cnakazawa/watch": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", @@ -899,6 +912,63 @@ "node": "*" } }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.9", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.9.tgz", + "integrity": "sha512-vQ1qwi/Kiyprt+uhb1+rHMpyk4CVRMTGNUGGPRGS7pLNfWkdCHrGEnT6T3/JyC2VZgoOX/X1KwdoU0WYQAeYcQ==", + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", + "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.4", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/proto-loader/node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "node_modules/@grpc/proto-loader/node_modules/protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.5.tgz", @@ -1710,6 +1780,39 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@nestjs/axios": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-2.0.0.tgz", @@ -2663,6 +2766,11 @@ "integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==", "dev": true }, + "node_modules/@types/google-protobuf": { + "version": "3.15.10", + "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.10.tgz", + "integrity": "sha512-uiyKJCa8hbmPE4yxwjbkMOALaBAiOVcatW/yEGbjTqwAh4kzNgQPWRlJMNPXpB5CPUM66xsYufiSX9WKHZCE9g==" + }, "node_modules/@types/graceful-fs": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz", @@ -3701,6 +3809,11 @@ "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", "dev": true }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, "node_modules/accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -3777,7 +3890,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, "dependencies": { "debug": "4" }, @@ -3906,6 +4018,36 @@ "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -4683,6 +4825,14 @@ "node": ">= 8" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -5001,6 +5151,14 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -5112,6 +5270,11 @@ "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -5456,6 +5619,11 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -5473,6 +5641,14 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -6978,6 +7154,28 @@ "node": ">=12" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fs-monkey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", @@ -7008,6 +7206,25 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -7161,6 +7378,11 @@ "node": ">= 4" } }, + "node_modules/google-protobuf": { + "version": "3.21.2", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", + "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" + }, "node_modules/graceful-fs": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", @@ -7211,6 +7433,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "node_modules/has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -7366,7 +7593,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -7973,30 +8199,6 @@ "node": ">=8" } }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10378,6 +10580,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -10570,6 +10777,28 @@ "node": ">=12" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -10843,6 +11072,37 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -11205,6 +11465,20 @@ "node": ">=6.0.0" } }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -11238,6 +11512,17 @@ "node": ">=4" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/number-allocator": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.12.tgz", @@ -12731,8 +13016,7 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "node_modules/set-value": { "version": "2.0.1", @@ -12839,8 +13123,7 @@ "node_modules/signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, "node_modules/sisteransi": { "version": "1.0.5", @@ -13540,6 +13823,33 @@ "node": ">=6" } }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -14805,6 +15115,14 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/windows-release": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", @@ -15129,17 +15447,17 @@ } }, "node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" + "yargs-parser": "^21.1.1" }, "engines": { "node": ">=12" @@ -15173,13 +15491,16 @@ } }, "node_modules/yargs/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/yargs/node_modules/color-convert": { @@ -15821,6 +16142,17 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@chirpstack/chirpstack-api": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@chirpstack/chirpstack-api/-/chirpstack-api-4.5.1.tgz", + "integrity": "sha512-GAKb2/EAodgruOs4TF7la3EpZwXrlNJq8uQASvmRRTqFA4XUXsyna1BB+2QZmXxRt/VOA1POM/BsYUY47b2KIQ==", + "requires": { + "@grpc/grpc-js": "^1.9.0", + "@mapbox/node-pre-gyp": "^1.0.11", + "@types/google-protobuf": "^3.15.6", + "google-protobuf": "^3.21.2" + } + }, "@cnakazawa/watch": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", @@ -15902,6 +16234,52 @@ } } }, + "@grpc/grpc-js": { + "version": "1.9.9", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.9.tgz", + "integrity": "sha512-vQ1qwi/Kiyprt+uhb1+rHMpyk4CVRMTGNUGGPRGS7pLNfWkdCHrGEnT6T3/JyC2VZgoOX/X1KwdoU0WYQAeYcQ==", + "requires": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + } + }, + "@grpc/proto-loader": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", + "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "requires": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.4", + "yargs": "^17.7.2" + }, + "dependencies": { + "long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + } + } + } + }, "@humanwhocodes/config-array": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.5.tgz", @@ -16528,6 +16906,32 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "requires": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, "@nestjs/axios": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-2.0.0.tgz", @@ -17251,6 +17655,11 @@ "integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==", "dev": true }, + "@types/google-protobuf": { + "version": "3.15.10", + "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.10.tgz", + "integrity": "sha512-uiyKJCa8hbmPE4yxwjbkMOALaBAiOVcatW/yEGbjTqwAh4kzNgQPWRlJMNPXpB5CPUM66xsYufiSX9WKHZCE9g==" + }, "@types/graceful-fs": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz", @@ -18059,6 +18468,11 @@ "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", "dev": true }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -18115,7 +18529,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, "requires": { "debug": "4" } @@ -18210,6 +18623,32 @@ "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -18795,6 +19234,11 @@ } } }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, "chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -19038,6 +19482,11 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -19132,6 +19581,11 @@ "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -19395,6 +19849,11 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -19405,6 +19864,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, + "detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==" + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -20548,6 +21012,24 @@ "universalify": "^2.0.0" } }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, "fs-monkey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", @@ -20571,6 +21053,22 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -20680,6 +21178,11 @@ } } }, + "google-protobuf": { + "version": "3.21.2", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", + "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" + }, "graceful-fs": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", @@ -20718,6 +21221,11 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -20851,7 +21359,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, "requires": { "agent-base": "6", "debug": "4" @@ -21305,21 +21812,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -23124,6 +23616,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -23276,6 +23773,21 @@ "sourcemap-codec": "^1.4.8" } }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -23494,6 +24006,30 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==" + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -23797,6 +24333,14 @@ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz", "integrity": "sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q==" }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "requires": { + "abbrev": "1" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -23824,6 +24368,17 @@ "path-key": "^2.0.0" } }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "number-allocator": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.12.tgz", @@ -24960,8 +25515,7 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "set-value": { "version": "2.0.1", @@ -25046,8 +25600,7 @@ "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, "sisteransi": { "version": "1.0.5", @@ -25588,6 +26141,26 @@ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, + "tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, "terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -26447,6 +27020,14 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "windows-release": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", @@ -26680,17 +27261,17 @@ "dev": true }, "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" + "yargs-parser": "^21.1.1" }, "dependencies": { "ansi-styles": { @@ -26702,12 +27283,12 @@ } }, "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, diff --git a/package.json b/package.json index 68f4e00a..5b0973ce 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,8 @@ "typeorm-e2e": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config ./ormconfig-e2e.json" }, "dependencies": { + "@chirpstack/chirpstack-api": "4.5.1", + "@grpc/grpc-js": "1.9.9", "@nestjs/axios": "^2.0.0", "@nestjs/common": "^9.1.2", "@nestjs/config": "^2.2.0", diff --git a/resources/chirpstack-state.proto b/resources/chirpstack-state.proto index 1befa749..bdd7a0fb 100644 --- a/resources/chirpstack-state.proto +++ b/resources/chirpstack-state.proto @@ -4,13 +4,17 @@ package gw; // ConnState contains the connection state of a gateway. message ConnState { - // Gateway ID. - bytes gateway_id = 1 [json_name = "gatewayID"]; + // Gateway ID. + // Deprecated: use gateway_id. + bytes gateway_id_legacy = 1; - enum State { - OFFLINE = 0; - ONLINE = 1; - } + // Gateway ID. + string gateway_id = 3; - State state = 2; + enum State { + OFFLINE = 0; + ONLINE = 1; + } + + State state = 2; } diff --git a/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts b/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts index fa964ec9..9470ea7a 100644 --- a/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts +++ b/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts @@ -24,12 +24,15 @@ import { Read, GatewayAdmin } from "@auth/roles.decorator"; import { RolesGuard } from "@auth/roles.guard"; import { ChirpstackResponseStatus } from "@dto/chirpstack/chirpstack-response.dto"; import { CreateGatewayDto } from "@dto/chirpstack/create-gateway.dto"; -import { ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways.dto"; +import { ListAllGatewaysResponseGrpcDto } from "@dto/chirpstack/list-all-gateways.dto"; import { SingleGatewayResponseDto } from "@dto/chirpstack/single-gateway-response.dto"; import { UpdateGatewayDto } from "@dto/chirpstack/update-gateway.dto"; import { ErrorCodes } from "@enum/error-codes.enum"; import { ChirpstackGatewayService } from "@services/chirpstack/chirpstack-gateway.service"; -import { checkIfUserHasAccessToOrganization, OrganizationAccessScope } from "@helpers/security-helper"; +import { + checkIfUserHasAccessToOrganization, + OrganizationAccessScope, +} from "@helpers/security-helper"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; import { AuditLog } from "@services/audit-log.service"; import { ActionType } from "@entities/audit-log-entry"; @@ -52,7 +55,11 @@ export class ChirpstackGatewayController { @Req() req: AuthenticatedRequest, @Body() dto: CreateGatewayDto ): Promise { - checkIfUserHasAccessToOrganization(req, dto.organizationId, OrganizationAccessScope.GatewayWrite); + checkIfUserHasAccessToOrganization( + req, + dto.organizationId, + OrganizationAccessScope.GatewayWrite + ); try { const gateway = await this.chirpstackGatewayService.createNewGateway( dto, @@ -62,7 +69,7 @@ export class ChirpstackGatewayController { ActionType.CREATE, "ChirpstackGateway", req.user.userId, - dto.gateway.id, + dto.gateway.gatewayId, dto.gateway.name ); return gateway; @@ -71,7 +78,7 @@ export class ChirpstackGatewayController { ActionType.CREATE, "ChirpstackGateway", req.user.userId, - dto.gateway.id, + dto.gateway.gatewayId, dto.gateway.name ); if (err?.response?.data?.message == "object already exists") { @@ -86,7 +93,9 @@ export class ChirpstackGatewayController { @ApiProduces("application/json") @ApiOperation({ summary: "List all Chirpstack gateways" }) @Read() - async getAll(@Query() query?: ChirpstackGetAll): Promise { + async getAll( + @Query() query?: ChirpstackGetAll + ): Promise { return await this.chirpstackGatewayService.getAll(query.organizationId); } @@ -119,7 +128,7 @@ export class ChirpstackGatewayController { @Body() dto: UpdateGatewayDto ): Promise { try { - if (dto.gateway.id) { + if (dto.gateway.gatewayId) { throw new BadRequestException(ErrorCodes.GatewayIdNotAllowedInUpdate); } const gateway = await this.chirpstackGatewayService.modifyGateway( diff --git a/src/entities/dto/chirpstack/chirpstack-mqtt-message.dto.ts b/src/entities/dto/chirpstack/chirpstack-mqtt-message.dto.ts index 9136b803..fd7b7eae 100644 --- a/src/entities/dto/chirpstack/chirpstack-mqtt-message.dto.ts +++ b/src/entities/dto/chirpstack/chirpstack-mqtt-message.dto.ts @@ -1,15 +1,13 @@ export class ChirpstackMQTTMessageDto { adr: boolean; - applicationID: string; - applicationName: string; data: string; - devEUI: string; - deviceName: string; fCnt: number; fPort: number; + deviceInfo: ChirpstackMQTTMessageDeviceInfo; txInfo: ChirpstackMQTTMessageTxInfoDto; dr: number; frequency: number; + confirmed: boolean } export class ChirpstackMQTTMessageTxInfoDto { @@ -21,3 +19,10 @@ export class ChirpstackMQTTConnectionStateMessageDto { gatewayId: string; isOnline: boolean; } + +export class ChirpstackMQTTMessageDeviceInfo { + applicationID: string; + applicationName: string; + devEui: string; + deviceName: string; +} diff --git a/src/entities/dto/chirpstack/common-location.dto.ts b/src/entities/dto/chirpstack/common-location.dto.ts index 806a7319..250d5948 100644 --- a/src/entities/dto/chirpstack/common-location.dto.ts +++ b/src/entities/dto/chirpstack/common-location.dto.ts @@ -1,4 +1,5 @@ -import { ApiProperty } from "@nestjs/swagger"; +import { LocationSourceMap } from "@chirpstack/chirpstack-api/common/common_pb"; +import { ApiHideProperty, ApiProperty } from "@nestjs/swagger"; import { IsOptional, IsString, Max, Min } from "class-validator"; export class CommonLocationDto { @@ -16,17 +17,8 @@ export class CommonLocationDto { @IsOptional() altitude?: number; - @ApiProperty({ required: false }) - @IsString() - @IsOptional() - source?: - | "UNKNOWN" - | "GPS" - | "CONFIG" - | "GEO_RESOLVER_TDOA" - | "GEO_RESOLVER_RSSI" - | "GEO_RESOLVER_GNSS" - | "GEO_RESOLVER_WIFI"; + @ApiHideProperty() + source?: LocationSourceMap[keyof LocationSourceMap] @ApiProperty({ required: false }) @IsOptional() diff --git a/src/entities/dto/chirpstack/detailed-gateway-response.dto.ts b/src/entities/dto/chirpstack/detailed-gateway-response.dto.ts index b10c7ac9..960981c6 100644 --- a/src/entities/dto/chirpstack/detailed-gateway-response.dto.ts +++ b/src/entities/dto/chirpstack/detailed-gateway-response.dto.ts @@ -1,10 +1,11 @@ -import { GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto"; +import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; +import { Type } from "class-transformer"; -export class DetailedGatewayResponseDto extends GatewayResponseDto { - discoveryEnabled: boolean; - gatewayProfileID: string; - boards: any[]; - tags: { [id: string]: string | number }; - tagsString: string; - metadata: JSON; +export class DetailedGatewayResponseDto extends GatewayResponseGrpcDto { + discoveryEnabled?: boolean; + gatewayProfileID?: string; + boards?: any[]; + metadata?: JSON; + @Type(() => Array<[string, string]>) + tagsMap: Array<[string, string]>; } diff --git a/src/entities/dto/chirpstack/gateway-contents.dto.ts b/src/entities/dto/chirpstack/gateway-contents.dto.ts index 4f070748..f5fe225f 100644 --- a/src/entities/dto/chirpstack/gateway-contents.dto.ts +++ b/src/entities/dto/chirpstack/gateway-contents.dto.ts @@ -40,7 +40,7 @@ export class GatewayContentsDto { @ApiProperty({ required: true }) @IsString() @Matches(/[0-9A-Fa-f]{16}/) - id: string; + gatewayId: string; @ApiProperty({ required: false }) @ValidateNested({ each: true }) diff --git a/src/entities/dto/chirpstack/gateway-response.dto.ts b/src/entities/dto/chirpstack/gateway-response.dto.ts index 1da87f4e..ce9d7c30 100644 --- a/src/entities/dto/chirpstack/gateway-response.dto.ts +++ b/src/entities/dto/chirpstack/gateway-response.dto.ts @@ -1,22 +1,16 @@ -import { CommonLocationDto } from "@dto/chirpstack/common-location.dto"; +import { Location } from "@chirpstack/chirpstack-api/common/common_pb"; +import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; -export class GatewayResponseDto { - id: string; +export class GatewayResponseGrpcDto { + gatewayId: string; name: string; description: string; - organizationID: string; - networkServerID: string; - location: CommonLocationDto; - tags: { [id: string]: string | number }; - tagsString: string; - - networkServerName?: string; - createdAt?: string; - updatedAt?: string; - firstSeenAt?: string; - lastSeenAt?: string; - - internalOrganizationId: number; + organizationID?: string; + location?: Location.AsObject; + createdAt?: Timestamp.AsObject; + updatedAt?: Timestamp.AsObject; + lastSeenAt?: Timestamp.AsObject; + internalOrganizationId?: number; updatedBy?: number; createdBy?: number; } diff --git a/src/entities/dto/chirpstack/gateway-stats.response.dto.ts b/src/entities/dto/chirpstack/gateway-stats.response.dto.ts index 885b361a..5de3cced 100644 --- a/src/entities/dto/chirpstack/gateway-stats.response.dto.ts +++ b/src/entities/dto/chirpstack/gateway-stats.response.dto.ts @@ -1,3 +1,5 @@ +import { Metric } from "@chirpstack/chirpstack-api/common/common_pb"; + export class GatewayStatsResponseDto { result: GatewayStatsElementDto[]; } @@ -5,7 +7,5 @@ export class GatewayStatsResponseDto { export class GatewayStatsElementDto { timestamp: string; rxPacketsReceived: number; - rxPacketsReceivedOK: number; - txPacketsReceived: number; txPacketsEmitted: number; } diff --git a/src/entities/dto/chirpstack/list-all-gateways.dto.ts b/src/entities/dto/chirpstack/list-all-gateways.dto.ts index 4fa6aaf4..3b616a79 100644 --- a/src/entities/dto/chirpstack/list-all-gateways.dto.ts +++ b/src/entities/dto/chirpstack/list-all-gateways.dto.ts @@ -1,6 +1,6 @@ -import { GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto"; +import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; -export class ListAllGatewaysResponseDto { +export class ListAllGatewaysResponseGrpcDto { totalCount: number; - result: GatewayResponseDto[]; + resultList: GatewayResponseGrpcDto[]; } diff --git a/src/entities/dto/chirpstack/single-gateway-response.dto.ts b/src/entities/dto/chirpstack/single-gateway-response.dto.ts index ba28c684..261a4c6e 100644 --- a/src/entities/dto/chirpstack/single-gateway-response.dto.ts +++ b/src/entities/dto/chirpstack/single-gateway-response.dto.ts @@ -1,13 +1,11 @@ import { DetailedGatewayResponseDto } from "@dto/chirpstack/detailed-gateway-response.dto"; import { GatewayStatsElementDto } from "@dto/chirpstack/gateway-stats.response.dto"; +import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; export class SingleGatewayResponseDto { - gateway: DetailedGatewayResponseDto; - - createdAt?: string; - updatedAt?: string; - firstSeenAt?: string; - lastSeenAt?: string; - - stats: GatewayStatsElementDto[]; + gateway?: DetailedGatewayResponseDto; + createdAt?: Date; + updatedAt?: Date; + lastSeenAt?: Timestamp.AsObject; + stats?: GatewayStatsElementDto[]; } diff --git a/src/entities/dto/chirpstack/update-gateway.dto.ts b/src/entities/dto/chirpstack/update-gateway.dto.ts index bb6dae94..d8e4f1f0 100644 --- a/src/entities/dto/chirpstack/update-gateway.dto.ts +++ b/src/entities/dto/chirpstack/update-gateway.dto.ts @@ -3,9 +3,9 @@ import { ValidateNested } from "class-validator"; import { GatewayContentsDto } from "./gateway-contents.dto"; import { Type } from "class-transformer"; -export class UpdateGatewayContentsDto extends OmitType(GatewayContentsDto, ["id"]) { +export class UpdateGatewayContentsDto extends OmitType(GatewayContentsDto, ["gatewayId"]) { @ApiHideProperty() - id: string; + gatewayId: string; } export class UpdateGatewayDto { diff --git a/src/helpers/date.helper.ts b/src/helpers/date.helper.ts index 60224da5..1258e287 100644 --- a/src/helpers/date.helper.ts +++ b/src/helpers/date.helper.ts @@ -1,3 +1,5 @@ +import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; + export const subtractHours = (date: Date, hours = 1): Date => { const newDate = new Date(); newDate.setTime(date.getTime() - 1000 * (60 * 60 * hours)); @@ -14,4 +16,17 @@ export const subtractYears = (date: Date, years = 1): Date => { const newDate = new Date(); newDate.setDate(date.getDate() - years * 365); return newDate; -} +}; + +export const dateToTimestamp = (date: Date): Timestamp => { + const timestamp = new Timestamp(); + timestamp.fromDate(date); + return timestamp; +}; + +export const timestampToDate = (timestamp: Timestamp.AsObject): Date => { + const seconds = timestamp.seconds; + const nanoseconds = timestamp.nanos / 1e6; // Convert nanoseconds to milliseconds + const milliseconds = seconds * 1000 + nanoseconds; + return new Date(milliseconds); +}; diff --git a/src/services/chirpstack/gateway-boostrapper.service.ts b/src/services/chirpstack/gateway-boostrapper.service.ts index 3943d6f3..2fbc52b8 100644 --- a/src/services/chirpstack/gateway-boostrapper.service.ts +++ b/src/services/chirpstack/gateway-boostrapper.service.ts @@ -1,8 +1,9 @@ -import { ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways.dto"; +import { ListAllGatewaysResponseGrpcDto } from "@dto/chirpstack/list-all-gateways.dto"; import { GatewayStatusHistory } from "@entities/gateway-status-history.entity"; import { Inject, OnApplicationBootstrap } from "@nestjs/common"; import { ChirpstackGatewayService } from "./chirpstack-gateway.service"; import { GatewayStatusHistoryService } from "./gateway-status-history.service"; +import { timestampToDate } from "@helpers/date.helper"; /** * Verify if any gateways exist on chirpstack and haven't been loaded into the database. @@ -17,10 +18,14 @@ export class GatewayBootstrapperService implements OnApplicationBootstrap { ) {} async onApplicationBootstrap(): Promise { - const chirpstackGatewaysPromise = this.chirpstackGatewayService.getAll(); - const latestStatusHistories = await this.statusHistoryService.findLatestPerGateway(); - const gateways = await chirpstackGatewaysPromise; - await this.seedGatewayStatus(gateways, latestStatusHistories); + try { + const chirpstackGatewaysPromise = this.chirpstackGatewayService.getAll(); + const latestStatusHistories = await this.statusHistoryService.findLatestPerGateway(); + const gateways = await chirpstackGatewaysPromise; + await this.seedGatewayStatus(gateways, latestStatusHistories); + } catch (e) { + throw e; + } } /** @@ -29,7 +34,7 @@ export class GatewayBootstrapperService implements OnApplicationBootstrap { * @param statusHistories Existing status histories to check against */ private async seedGatewayStatus( - gateways: ListAllGatewaysResponseDto, + gateways: ListAllGatewaysResponseGrpcDto, statusHistories: GatewayStatusHistory[] ) { const now = new Date(); @@ -37,18 +42,21 @@ export class GatewayBootstrapperService implements OnApplicationBootstrap { errorTime.setSeconds(errorTime.getSeconds() - 150); // Don't overwrite ones which already have a status history - const newHistoriesForMissingGateways = gateways.result.reduce( + const newHistoriesForMissingGateways = gateways.resultList.reduce( (res: GatewayStatusHistory[], gateway) => { - if (!statusHistories.some(history => history.mac === gateway.id)) { + if (!statusHistories.some(history => history.mac === gateway.gatewayId)) { // Best fit is to imitate the status logic from Chirpstack. - const lastSeenDate = new Date(gateway.lastSeenAt); - const wasOnline = errorTime.getTime() < lastSeenDate.getTime(); - - res.push({ - mac: gateway.id, - timestamp: now, - wasOnline, - } as GatewayStatusHistory); + if (gateway.lastSeenAt) { + const lastSeenDate = timestampToDate(gateway.lastSeenAt); + + const wasOnline = errorTime.getTime() < lastSeenDate.getTime(); + + res.push({ + mac: gateway.gatewayId, + timestamp: now, + wasOnline, + } as GatewayStatusHistory); + } } return res; diff --git a/src/services/chirpstack/gateway-status-history.service.ts b/src/services/chirpstack/gateway-status-history.service.ts index 4c5739c5..d356344f 100644 --- a/src/services/chirpstack/gateway-status-history.service.ts +++ b/src/services/chirpstack/gateway-status-history.service.ts @@ -14,7 +14,7 @@ import { In, MoreThanOrEqual, Repository } from "typeorm"; import { ChirpstackGatewayService } from "./chirpstack-gateway.service"; import { nameof } from "@helpers/type-helper"; -type GatewayId = { id: string; name: string }; +type GatewayId = { gatewayId: string; name: string }; @Injectable() export class GatewayStatusHistoryService { @@ -31,7 +31,7 @@ export class GatewayStatusHistoryService { // Very expensive operation. Since no gateway data is stored on the backend database, we need // to get them from Chirpstack. There's no filter by tags support so we must fetch all gateways. const gateways = await this.chirpstackGatewayService.getAll(query.organizationId); - const gatewayIds = gateways.result.map(gateway => gateway.id); + const gatewayIds = gateways.resultList.map(gateway => gateway.gatewayId); const fromDate = gatewayStatusIntervalToDate(query.timeInterval); if (!gatewayIds.length) { @@ -44,7 +44,6 @@ export class GatewayStatusHistoryService { timestamp: MoreThanOrEqual(fromDate), }, }); - // To know the status of each gateway up till the first status since the start date, // we must fetch the previous status const latestStatusHistoryPerGatewayBeforePeriod = await this.fetchLatestStatusBeforeDate(gatewayIds, fromDate); @@ -56,7 +55,7 @@ export class GatewayStatusHistoryService { ); const data: GatewayStatus[] = this.mapStatusHistoryToGateways( - gateways.result, + gateways.resultList, statusHistories ); @@ -74,12 +73,12 @@ export class GatewayStatusHistoryService { const statusHistoriesInPeriod = await this.gatewayStatusHistoryRepository.find({ where: { - mac: gateway.id, + mac: gateway.gatewayId, timestamp: MoreThanOrEqual(fromDate), }, }); - const latestStatusHistoryPerGatewayBeforePeriod = await this.fetchLatestStatusBeforeDate([gateway.id], fromDate); + const latestStatusHistoryPerGatewayBeforePeriod = await this.fetchLatestStatusBeforeDate([gateway.gatewayId], fromDate); const statusHistories = this.mergeStatusHistories( fromDate, @@ -151,7 +150,7 @@ export class GatewayStatusHistoryService { ) { const statusTimestamps = statusHistories.reduce( (res: GatewayStatus["statusTimestamps"], history) => { - if (history.mac === gateway.id) { + if (history.mac === gateway.gatewayId) { res.push({ timestamp: history.timestamp, wasOnline: history.wasOnline, @@ -164,7 +163,7 @@ export class GatewayStatusHistoryService { ); return { - id: gateway.id, + id: gateway.gatewayId, name: gateway.name, statusTimestamps, }; diff --git a/src/services/chirpstack/network-server.service.ts b/src/services/chirpstack/network-server.service.ts index 02cce160..290cf8ab 100644 --- a/src/services/chirpstack/network-server.service.ts +++ b/src/services/chirpstack/network-server.service.ts @@ -5,19 +5,13 @@ import { CreateNetworkServerDto } from "@dto/chirpstack/create-network-server.dt import { ListAllNetworkServerResponseDto } from "@dto/chirpstack/list-all-network-server-response.dto"; import { NetworkServerDto } from "@dto/chirpstack/network-server.dto"; -import { GenericChirpstackConfigurationService } from "./generic-chirpstack-configuration.service"; +import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; import { ListAllAdrAlgorithmsResponseDto } from "@dto/chirpstack/list-all-adr-algorithms-response.dto"; @Injectable() -export class ChirpstackSetupNetworkServerService - extends GenericChirpstackConfigurationService - implements OnModuleInit { +export class ChirpstackSetupNetworkServerService extends GenericChirpstackConfigurationService { networkServerName = "OS2iot"; - async onModuleInit(): Promise { - await this.bootstrapChirpstackNetworkServerConfiguration(); - } - public async bootstrapChirpstackNetworkServerConfiguration(): Promise { const networkServers = await this.getNetworkServers(100, 0); const alreadyCreated = networkServers.result.some(networkServer => { diff --git a/src/services/chirpstack/service-profile.service.ts b/src/services/chirpstack/service-profile.service.ts index cfdf9a50..fd1286a3 100644 --- a/src/services/chirpstack/service-profile.service.ts +++ b/src/services/chirpstack/service-profile.service.ts @@ -5,7 +5,7 @@ import { CreateServiceProfileDto } from "@dto/chirpstack/create-service-profile. import { ListAllServiceProfilesResponseDto } from "@dto/chirpstack/list-all-service-profiles-response.dto"; import { UpdateServiceProfileDto } from "@dto/chirpstack/update-service-profile.dto"; -import { GenericChirpstackConfigurationService } from "./generic-chirpstack-configuration.service"; +import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; import { ChirpstackApplicationResponseDto } from "@dto/chirpstack/chirpstack-application-response.dto"; import { ListAllChirpstackApplicationsResponseDto } from "@dto/chirpstack/list-all-applications-response.dto"; import { ErrorCodes } from "@enum/error-codes.enum"; diff --git a/src/services/data-management/chirpstack-mqtt-listener.service.ts b/src/services/data-management/chirpstack-mqtt-listener.service.ts index b04147c0..ef454199 100644 --- a/src/services/data-management/chirpstack-mqtt-listener.service.ts +++ b/src/services/data-management/chirpstack-mqtt-listener.service.ts @@ -51,9 +51,7 @@ export class ChirpstackMQTTListenerService implements OnApplicationBootstrap { this.client.subscribe(this.CHIRPSTACK_MQTT_GATEWAY_TOPIC); this.client.on("message", async (topic, message) => { - this.logger.debug( - `Received MQTT - Topic: '${topic}' - message: '${message}'` - ); + this.logger.debug(`Received MQTT - Topic: '${topic}' - message: '${message}'`); if (topic.startsWith(this.CHIRPSTACK_MQTT_DEVICE_DATA_PREFIX)) { await this.receiveMqttMessage(message.toString()); @@ -77,12 +75,12 @@ export class ChirpstackMQTTListenerService implements OnApplicationBootstrap { async receiveMqttMessage(message: string): Promise { const dto: ChirpstackMQTTMessageDto = JSON.parse(message); const iotDevice = await this.iotDeviceService.findLoRaWANDeviceByDeviceEUI( - dto.devEUI + dto.deviceInfo.devEui ); if (!iotDevice) { this.logger.warn( - `Chirpstack sent MQTT message for devEUI ${dto.devEUI}, but that's not registered in OS2IoT` + `Chirpstack sent MQTT message for devEUI ${dto.deviceInfo.devEui}, but that's not registered in OS2IoT` ); return; } @@ -94,27 +92,19 @@ export class ChirpstackMQTTListenerService implements OnApplicationBootstrap { ); } - async receiveMqttGatewayStatusMessage( - message: Record - ): Promise { + async receiveMqttGatewayStatusMessage(message: Record): Promise { if ( message && - hasProps( - message, - nameof("gatewayId") - ) && + hasProps(message, nameof("gatewayId")) && typeof message.gatewayId === "string" ) { const dto: ChirpstackMQTTConnectionStateMessageDto = { - gatewayId: Buffer.from(message.gatewayId, "base64").toString("hex"), + gatewayId: message.gatewayId, isOnline: message.state === "ONLINE", }; const jsonDto = JSON.stringify(dto); - await this.receiveDataService.sendRawGatewayStateToKafka( - dto.gatewayId, - jsonDto - ); + await this.receiveDataService.sendRawGatewayStateToKafka(dto.gatewayId, jsonDto); } else { this.logger.error( `Gateway status message is not properly formatted. Gateway id, if any, is ${message?.id}` diff --git a/src/services/data-management/gateway-persistence.service.ts b/src/services/data-management/gateway-persistence.service.ts index bd9ca523..1cff17a6 100644 --- a/src/services/data-management/gateway-persistence.service.ts +++ b/src/services/data-management/gateway-persistence.service.ts @@ -54,6 +54,7 @@ export class GatewayPersistenceService extends AbstractKafkaConsumer { messageState: ChirpstackMQTTConnectionStateMessageDto ) { const statusHistory = new GatewayStatusHistory(); + dto.gatewayId statusHistory.mac = dto.gatewayId; statusHistory.timestamp = dto.unixTimestamp ? new Date(dto.unixTimestamp) diff --git a/src/services/data-management/search.service.ts b/src/services/data-management/search.service.ts index e00930ed..900e26be 100644 --- a/src/services/data-management/search.service.ts +++ b/src/services/data-management/search.service.ts @@ -1,9 +1,13 @@ -import { ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways.dto"; +import { GatewayServiceClient } from "@chirpstack/chirpstack-api/api/gateway_grpc_pb"; +import { ListGatewaysRequest } from "@chirpstack/chirpstack-api/api/gateway_pb"; +import { ListAllGatewaysResponseGrpcDto } from "@dto/chirpstack/list-all-gateways.dto"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; import { ListAllSearchResultsResponseDto } from "@dto/list-all-search-results-response.dto"; import { SearchResultDto, SearchResultType } from "@dto/search-result.dto"; import { Application } from "@entities/application.entity"; import { IoTDevice } from "@entities/iot-device.entity"; +import { credentials } from "@grpc/grpc-js"; +import { timestampToDate } from "@helpers/date.helper"; import { Injectable, Logger } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { ChirpstackGatewayService } from "@services/chirpstack/chirpstack-gateway.service"; @@ -38,9 +42,7 @@ export class SearchService { const devicePromise = this.findDevicesAndMapType(req, trimmedQuery); const results = _.filter( - _.flatMap( - await Promise.all([applicationPromise, devicePromise, gatewayPromise]) - ), + _.flatMap(await Promise.all([applicationPromise, devicePromise, gatewayPromise])), x => x != null ); @@ -91,26 +93,35 @@ export class SearchService { } private async findGateways(trimmedQuery: string): Promise { + const gatewayClient = new GatewayServiceClient( + this.gatewayService.baseUrlGRPC, + credentials.createInsecure() + ); const escapedQuery = encodeURI(trimmedQuery); - const gateways = await this.gatewayService.getAllWithPagination( + const req = new ListGatewaysRequest(); + + req.setSearch(escapedQuery); + const gateways = await this.gatewayService.getAllWithPagination( `gateways?search=${escapedQuery}`, 1000, - 0 + 0, + gatewayClient, + req ); const mapped = await Promise.all( - gateways.result.map(async x => { - const createdAt = new Date(Date.parse(x.createdAt)); - const updatedAt = new Date(Date.parse(x.updatedAt)); + gateways.resultList.map(async x => { + const createdAt = timestampToDate(x.createdAt); + const updatedAt = timestampToDate(x.updatedAt); const resultDto = new SearchResultDto( x.name, - x.id, + x.gatewayId, createdAt, updatedAt, - x.id + x.gatewayId ); - const detailedInfo = await this.gatewayService.getOne(x.id); + const detailedInfo = await this.gatewayService.getOne(x.gatewayId); resultDto.organizationId = detailedInfo.gateway.internalOrganizationId; return resultDto; @@ -229,12 +240,9 @@ export class SearchService { if (req.user.permissions.getAllApplicationsWithAtLeastRead().length == 0) { return []; } - qb = qb.andWhere( - `"${alias}"."${applicationIdColumn}" IN (:...allowedApplications)`, - { - allowedApplications: req.user.permissions.getAllApplicationsWithAtLeastRead(), - } - ); + qb = qb.andWhere(`"${alias}"."${applicationIdColumn}" IN (:...allowedApplications)`, { + allowedApplications: req.user.permissions.getAllApplicationsWithAtLeastRead(), + }); } const toSelect = [ diff --git a/src/services/device-management/iot-device.service.ts b/src/services/device-management/iot-device.service.ts index ad6ae808..43149c53 100644 --- a/src/services/device-management/iot-device.service.ts +++ b/src/services/device-management/iot-device.service.ts @@ -1235,7 +1235,7 @@ export class IoTDeviceService { private async mapMQTTExternalBrokerDevice( iotDeviceDto: CreateIoTDeviceDto, cast: MQTTExternalBrokerDevice, - isUpdate: boolean = false + isUpdate = false ): Promise { const settings = iotDeviceDto.mqttExternalBrokerSettings; validateMQTTExternalBroker(settings); From 9276f8022cd724ab942898d0d3330c470297c06e Mon Sep 17 00:00:00 2001 From: August Andersen Date: Wed, 29 Nov 2023 17:01:14 +0100 Subject: [PATCH 02/24] Chirpstack updates. --- package-lock.json | 4 +- .../chirpstack/device-profile.controller.ts | 48 +- .../chirpstack/network-server.controller.ts | 36 - .../chirpstack/service-profile.controller.ts | 171 ---- .../admin-controller/iot-device.controller.ts | 83 +- .../admin-controller/multicast.controller.ts | 2 +- src/entities/application.entity.ts | 2 + .../chirpstack-application-response.dto.ts | 4 +- .../chirpstack/chirpstack-application.dto.ts | 3 +- .../chirpstack-device-contents.dto.ts | 15 +- .../chirpstack-device-keys-response.dto.ts | 1 - .../chirpstack-device-metrics.dto.ts | 13 + .../chirpstack-multicast-contents.dto.ts | 7 +- ...k-multicast-downlink-queue-response.dto.ts | 5 +- .../chirpstack/create-device-profile.dto.ts | 8 +- .../chirpstack/create-network-server.dto.ts | 12 - .../chirpstack/create-service-profile.dto.ts | 12 - .../dto/chirpstack/device-profile.dto.ts | 67 +- .../device/lorawan-stats.response.dto.ts | 3 - .../dto/chirpstack/gateway-contents.dto.ts | 7 +- .../list-all-device-profiles-response.dto.ts | 12 +- .../list-all-network-server-response.dto.ts | 6 - .../list-all-service-profiles-response.dto.ts | 6 - .../dto/chirpstack/network-server.dto.ts | 70 -- .../dto/chirpstack/service-profile.dto.ts | 80 -- .../dto/chirpstack/update-gateway.dto.ts | 4 + .../chirpstack/update-network-server.dto.ts | 3 - .../chirpstack/update-service-profile.dto.ts | 3 - src/entities/dto/create-application.dto.ts | 5 + .../dto/create-lorawan-settings.dto.ts | 1 - src/entities/dto/update-multicast.dto.ts | 6 +- .../enum/device-profile-enums.enum.ts | 17 + src/entities/enum/error-codes.enum.ts | 3 +- ...ck-network-server-send-status.interface.ts | 4 - .../chirpstack-post-return.interface.ts | 3 + src/entities/lorawan-device.entity.ts | 2 +- src/helpers/message-payload.helper.ts | 6 +- ...anged-chirpstackapplicationid-to-string.ts | 52 ++ ...83869-added-chirpstackId-to-application.ts | 14 + .../chirpstack-administration.module.ts | 15 +- .../lorawan-gateway.module.ts | 2 - .../device-management/multicast.module.ts | 2 +- .../chirpstack-application.service.ts | 58 ++ .../chirpstack/chirpstack-device.service.ts | 786 +++++++++++++----- .../chirpstack/chirpstack-gateway.service.ts | 363 +++++--- .../chirpstack/device-profile.service.ts | 318 +++++-- ...eneric-chirpstack-configuration.service.ts | 372 ++++----- .../multicast.service.ts | 403 +++++---- .../chirpstack/network-server.service.ts | 71 -- .../chirpstack/service-profile.service.ts | 89 -- src/services/csv-generator.service.ts | 5 - .../device-integration-persistence.service.ts | 2 +- .../device-management/application.service.ts | 130 ++- .../iot-device-downlink.service.ts | 9 +- .../device-management/iot-device.service.ts | 198 ++--- 55 files changed, 1953 insertions(+), 1670 deletions(-) delete mode 100644 src/controllers/admin-controller/chirpstack/network-server.controller.ts delete mode 100644 src/controllers/admin-controller/chirpstack/service-profile.controller.ts create mode 100644 src/entities/dto/chirpstack/chirpstack-device-metrics.dto.ts delete mode 100644 src/entities/dto/chirpstack/create-network-server.dto.ts delete mode 100644 src/entities/dto/chirpstack/create-service-profile.dto.ts delete mode 100644 src/entities/dto/chirpstack/list-all-network-server-response.dto.ts delete mode 100644 src/entities/dto/chirpstack/list-all-service-profiles-response.dto.ts delete mode 100644 src/entities/dto/chirpstack/network-server.dto.ts delete mode 100644 src/entities/dto/chirpstack/service-profile.dto.ts delete mode 100644 src/entities/dto/chirpstack/update-network-server.dto.ts delete mode 100644 src/entities/dto/chirpstack/update-service-profile.dto.ts create mode 100644 src/entities/enum/device-profile-enums.enum.ts delete mode 100644 src/entities/interfaces/chirpstack-network-server-send-status.interface.ts create mode 100644 src/entities/interfaces/chirpstack-post-return.interface.ts create mode 100644 src/migration/1701075072037-changed-chirpstackapplicationid-to-string.ts create mode 100644 src/migration/1701260283869-added-chirpstackId-to-application.ts create mode 100644 src/services/chirpstack/chirpstack-application.service.ts rename src/services/{device-management => chirpstack}/multicast.service.ts (61%) delete mode 100644 src/services/chirpstack/network-server.service.ts delete mode 100644 src/services/chirpstack/service-profile.service.ts diff --git a/package-lock.json b/package-lock.json index b1db2dbb..ac3da10e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,8 @@ "version": "0.0.1", "license": "Mozilla Public License Version 2.0", "dependencies": { - "@chirpstack/chirpstack-api": "^4.5.1", - "@grpc/grpc-js": "^1.9.9", + "@chirpstack/chirpstack-api": "4.5.1", + "@grpc/grpc-js": "1.9.9", "@nestjs/axios": "^2.0.0", "@nestjs/common": "^9.1.2", "@nestjs/config": "^2.2.0", diff --git a/src/controllers/admin-controller/chirpstack/device-profile.controller.ts b/src/controllers/admin-controller/chirpstack/device-profile.controller.ts index e406db01..f7811dfc 100644 --- a/src/controllers/admin-controller/chirpstack/device-profile.controller.ts +++ b/src/controllers/admin-controller/chirpstack/device-profile.controller.ts @@ -26,7 +26,6 @@ import { import { Read, ApplicationAdmin } from "@auth/roles.decorator"; import { RolesGuard } from "@auth/roles.guard"; -import { CreateChirpstackProfileResponseDto } from "@dto/chirpstack/create-chirpstack-profile-response.dto"; import { CreateDeviceProfileDto } from "@dto/chirpstack/create-device-profile.dto"; import { ListAllDeviceProfilesResponseDto } from "@dto/chirpstack/list-all-device-profiles-response.dto"; import { UpdateDeviceProfileDto } from "@dto/chirpstack/update-device-profile.dto"; @@ -34,10 +33,15 @@ import { DeleteResponseDto } from "@dto/delete-application-response.dto"; import { ErrorCodes } from "@enum/error-codes.enum"; import { DeviceProfileService } from "@services/chirpstack/device-profile.service"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; -import { checkIfUserHasAccessToOrganization, OrganizationAccessScope } from "@helpers/security-helper"; +import { + checkIfUserHasAccessToOrganization, + OrganizationAccessScope, +} from "@helpers/security-helper"; import { AuditLog } from "@services/audit-log.service"; import { ActionType } from "@entities/audit-log-entry"; import { ComposeAuthGuard } from "@auth/compose-auth.guard"; +import { ListAllAdrAlgorithmsResponseDto } from "@dto/chirpstack/list-all-adr-algorithms-response.dto"; +import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; @ApiTags("Chirpstack") @Controller("chirpstack/device-profiles") @@ -58,8 +62,12 @@ export class DeviceProfileController { async create( @Req() req: AuthenticatedRequest, @Body() createDto: CreateDeviceProfileDto - ): Promise { - checkIfUserHasAccessToOrganization(req, createDto.internalOrganizationId, OrganizationAccessScope.ApplicationWrite); + ): Promise { + checkIfUserHasAccessToOrganization( + req, + createDto.internalOrganizationId, + OrganizationAccessScope.ApplicationWrite + ); try { const result = await this.deviceProfileService.createDeviceProfile( @@ -71,11 +79,11 @@ export class DeviceProfileController { ActionType.CREATE, "ChirpstackDeviceProfile", req.user.userId, - result.data.id, + result.id, createDto.deviceProfile.name ); - return result.data; + return result; } catch (err) { AuditLog.fail( ActionType.CREATE, @@ -130,6 +138,14 @@ export class DeviceProfileController { } } + @Get("adr-algorithms") + @ApiProduces("application/json") + @ApiOperation({ summary: "Find all ADR algorithms for the default network server" }) + @Read() + async getAllAdrAlgorithms(): Promise { + return await this.deviceProfileService.getAdrAlgorithmsForChirpstack(); + } + @Get(":id") @ApiProduces("application/json") @ApiOperation({ summary: "Find one DeviceProfile by id" }) @@ -181,25 +197,11 @@ export class DeviceProfileController { @Param("id") id: string ): Promise { try { - const result = await this.deviceProfileService.deleteDeviceProfile(id, req); - - if (!result) { - throw new NotFoundException(ErrorCodes.IdDoesNotExists); - } - AuditLog.success( - ActionType.DELETE, - "ChirpstackDeviceProfile", - req.user.userId, - id - ); + await this.deviceProfileService.deleteDeviceProfile(id, req); + AuditLog.success(ActionType.DELETE, "ChirpstackDeviceProfile", req.user.userId, id); return new DeleteResponseDto(1); } catch (err) { - AuditLog.fail( - ActionType.DELETE, - "ChirpstackDeviceProfile", - req.user.userId, - id - ); + AuditLog.fail(ActionType.DELETE, "ChirpstackDeviceProfile", req.user.userId, id); if (err?.message == this.CHIRPSTACK_IN_USE_ERROR) { throw new BadRequestException(ErrorCodes.IsUsed); } diff --git a/src/controllers/admin-controller/chirpstack/network-server.controller.ts b/src/controllers/admin-controller/chirpstack/network-server.controller.ts deleted file mode 100644 index 4016f3a8..00000000 --- a/src/controllers/admin-controller/chirpstack/network-server.controller.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { ComposeAuthGuard } from '@auth/compose-auth.guard'; -import { - Controller, - Get, - Logger, - UseGuards, -} from "@nestjs/common"; -import { - ApiBearerAuth, - ApiOperation, - ApiProduces, - ApiTags, -} from "@nestjs/swagger"; - -import { Read, ApplicationAdmin } from "@auth/roles.decorator"; -import { RolesGuard } from "@auth/roles.guard"; -import { ChirpstackSetupNetworkServerService } from "@services/chirpstack/network-server.service"; -import { ListAllAdrAlgorithmsResponseDto } from "@dto/chirpstack/list-all-adr-algorithms-response.dto"; - -@ApiTags("Chirpstack") -@Controller("chirpstack/network-server") -@UseGuards(ComposeAuthGuard, RolesGuard) -@ApiBearerAuth() -@ApplicationAdmin() -export class NetworkServerController { - constructor(private networkServerService: ChirpstackSetupNetworkServerService) {} - private readonly logger = new Logger(NetworkServerController.name); - - @Get("adr-algorithms") - @ApiProduces("application/json") - @ApiOperation({ summary: "Find all ADR algorithms for the default network server" }) - @Read() - async getAllAdrAlgorithms(): Promise { - return await this.networkServerService.getAdrAlgorithmsForDefaultNetworkServer(); - } -} diff --git a/src/controllers/admin-controller/chirpstack/service-profile.controller.ts b/src/controllers/admin-controller/chirpstack/service-profile.controller.ts deleted file mode 100644 index 2f1b1412..00000000 --- a/src/controllers/admin-controller/chirpstack/service-profile.controller.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { ComposeAuthGuard } from '@auth/compose-auth.guard'; -import { - BadRequestException, - Body, - Controller, - Delete, - Get, - HttpCode, - InternalServerErrorException, - Logger, - NotFoundException, - Param, - Post, - Put, - Query, - Req, - UseGuards, -} from "@nestjs/common"; -import { - ApiBadRequestResponse, - ApiBearerAuth, - ApiNotFoundResponse, - ApiOperation, - ApiProduces, - ApiTags, -} from "@nestjs/swagger"; - -import { Read, ApplicationAdmin } from "@auth/roles.decorator"; -import { RolesGuard } from "@auth/roles.guard"; -import { CreateChirpstackProfileResponseDto } from "@dto/chirpstack/create-chirpstack-profile-response.dto"; -import { CreateServiceProfileDto } from "@dto/chirpstack/create-service-profile.dto"; -import { ListAllServiceProfilesResponseDto } from "@dto/chirpstack/list-all-service-profiles-response.dto"; -import { UpdateServiceProfileDto } from "@dto/chirpstack/update-service-profile.dto"; -import { DeleteResponseDto } from "@dto/delete-application-response.dto"; -import { ErrorCodes } from "@enum/error-codes.enum"; -import { ServiceProfileService } from "@services/chirpstack/service-profile.service"; -import { AuditLog } from "@services/audit-log.service"; -import { ActionType } from "@entities/audit-log-entry"; -import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; - -@ApiTags("Chirpstack") -@Controller("chirpstack/service-profiles") -@UseGuards(ComposeAuthGuard, RolesGuard) -@ApiBearerAuth() -@ApplicationAdmin() -export class ServiceProfileController { - constructor(private serviceProfileService: ServiceProfileService) {} - private readonly logger = new Logger(ServiceProfileController.name); - - @Post() - @ApiProduces("application/json") - @ApiOperation({ summary: "Create a new ServiceProfile" }) - @ApiBadRequestResponse() - @ApplicationAdmin() - async create( - @Req() req: AuthenticatedRequest, - @Body() createDto: CreateServiceProfileDto - ): Promise { - const res = await this.serviceProfileService.createServiceProfile(createDto); - AuditLog.success( - ActionType.CREATE, - "ChirpstackServiceProfile", - req.user.userId, - res.data.id, - createDto.serviceProfile.name - ); - return res.data; - } - - @Put(":id") - @ApiProduces("application/json") - @ApiOperation({ summary: "Update an existing ServiceProfile" }) - @ApiBadRequestResponse() - @HttpCode(204) - @ApplicationAdmin() - async update( - @Req() req: AuthenticatedRequest, - @Param("id") id: string, - @Body() updateDto: UpdateServiceProfileDto - ): Promise { - const result = await this.serviceProfileService.updateServiceProfile( - updateDto, - id - ); - - if (result.status != 200) { - AuditLog.fail( - ActionType.UPDATE, - "ChirpstackServiceProfile", - req.user.userId, - updateDto.serviceProfile.id, - updateDto.serviceProfile.name - ); - throw new InternalServerErrorException(result.data); - } - AuditLog.success( - ActionType.UPDATE, - "ChirpstackServiceProfile", - req.user.userId, - updateDto.serviceProfile.id, - updateDto.serviceProfile.name - ); - return; - } - - @Get(":id") - @ApiProduces("application/json") - @ApiOperation({ summary: "Find one ServiceProfile by id" }) - @ApiNotFoundResponse() - @Read() - async findOne(@Param("id") id: string): Promise { - return await this.serviceProfileService.findOneServiceProfileById(id); - } - - @Get() - @ApiProduces("application/json") - @ApiOperation({ summary: "Find all ServiceProfile" }) - @Read() - async getAll( - @Query("limit") limit: number, - @Query("offset") offset: number - ): Promise { - this.logger.debug(`Limit: '${limit}' Offset:'${offset}'`); - const res = await this.serviceProfileService.findAllServiceProfiles( - limit || 50, - offset || 0 - ); - - return res; - } - - @Delete(":id") - @ApiOperation({ summary: "Delete one ServiceProfile by id" }) - @ApiNotFoundResponse() - @ApplicationAdmin() - async deleteOne( - @Req() req: AuthenticatedRequest, - @Param("id") id: string - ): Promise { - try { - const result = await this.serviceProfileService.deleteServiceProfile(id); - if (!result) { - throw new NotFoundException(ErrorCodes.IdDoesNotExists); - } - AuditLog.success( - ActionType.DELETE, - "ChirpstackServiceProfile", - req.user.userId, - id - ); - - return new DeleteResponseDto(1); - } catch (err) { - this.logger.error( - `Error occured during delete: '${JSON.stringify(err?.response?.data)}'` - ); - if ( - err?.message == "this object is used by other objects, remove them first" - ) { - throw new BadRequestException(ErrorCodes.IsUsed); - } - AuditLog.fail( - ActionType.DELETE, - "ChirpstackServiceProfile", - req.user.userId, - id - ); - throw err; - } - } -} diff --git a/src/controllers/admin-controller/iot-device.controller.ts b/src/controllers/admin-controller/iot-device.controller.ts index 7069a32f..7922877f 100644 --- a/src/controllers/admin-controller/iot-device.controller.ts +++ b/src/controllers/admin-controller/iot-device.controller.ts @@ -62,6 +62,7 @@ import { DeviceStatsResponseDto } from "@dto/chirpstack/device/device-stats.resp import { GenericHTTPDevice } from "@entities/generic-http-device.entity"; import { MQTTInternalBrokerDeviceDTO } from "@dto/mqtt-internal-broker-device.dto"; import { MQTTExternalBrokerDeviceDTO } from "@dto/mqtt-external-broker-device.dto"; +import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; @ApiTags("IoT Device") @Controller("iot-device") @@ -94,10 +95,7 @@ export class IoTDeviceController { > { let result = undefined; try { - result = await this.iotDeviceService.findOneWithApplicationAndMetadata( - id, - true - ); + result = await this.iotDeviceService.findOneWithApplicationAndMetadata(id, true); } catch (err) { this.logger.error(`Error occured during findOne: '${JSON.stringify(err)}'`); } @@ -106,11 +104,7 @@ export class IoTDeviceController { throw new NotFoundException(ErrorCodes.IdDoesNotExists); } - checkIfUserHasAccessToApplication( - req, - result.application.id, - ApplicationAccessScope.Read - ); + checkIfUserHasAccessToApplication(req, result.application.id, ApplicationAccessScope.Read); return result; } @@ -123,10 +117,7 @@ export class IoTDeviceController { ): Promise { let device = undefined; try { - device = await this.iotDeviceService.findOneWithApplicationAndMetadata( - id, - true - ); + device = await this.iotDeviceService.findOneWithApplicationAndMetadata(id, true); } catch (err) { this.logger.error(`Error occured during findOne: '${JSON.stringify(err)}'`); } @@ -134,16 +125,12 @@ export class IoTDeviceController { if (!device) { throw new NotFoundException(ErrorCodes.IdDoesNotExists); } - checkIfUserHasAccessToApplication( - req, - device.application.id, - ApplicationAccessScope.Read - ); - if (device.type == IoTDeviceType.LoRaWAN) { + checkIfUserHasAccessToApplication(req, device.application.id, ApplicationAccessScope.Read); + if (device.type === IoTDeviceType.LoRaWAN) { return this.chirpstackDeviceService.getDownlinkQueue( (device as LoRaWANDevice).deviceEUI ); - } else if (device.type == IoTDeviceType.SigFox) { + } else if (device.type === IoTDeviceType.SigFox) { return this.iotDeviceService.getDownlinkForSigfox(device as SigFoxDevice); } else { throw new BadRequestException(ErrorCodes.OnlyAllowedForLoRaWANAndSigfox); @@ -159,11 +146,7 @@ export class IoTDeviceController { @Param("id", new ParseIntPipe()) id: number ): Promise { const device = await this.iotDeviceService.findOne(id); - checkIfUserHasAccessToApplication( - req, - device.application.id, - ApplicationAccessScope.Read - ); + checkIfUserHasAccessToApplication(req, device.application.id, ApplicationAccessScope.Read); return this.iotDeviceService.findStats(device); } @@ -194,9 +177,7 @@ export class IoTDeviceController { } catch (err) { AuditLog.fail(ActionType.CREATE, IoTDevice.name, req.user.userId); this.logger.error( - `Failed to create IoTDevice from dto: ${JSON.stringify( - createDto - )}. Error: ${err}` + `Failed to create IoTDevice from dto: ${JSON.stringify(createDto)}. Error: ${err}` ); throw err; } @@ -210,11 +191,9 @@ export class IoTDeviceController { @Req() req: AuthenticatedRequest, @Param("id", new ParseIntPipe()) id: number, @Body() dto: CreateIoTDeviceDownlinkDto - ): Promise { + ): Promise { try { - const device = await this.iotDeviceService.findOneWithApplicationAndMetadata( - id - ); + const device = await this.iotDeviceService.findOneWithApplicationAndMetadata(id); if (!device) { throw new NotFoundException(); } @@ -265,11 +244,7 @@ export class IoTDeviceController { throw err; } - const iotDevice = await this.iotDeviceService.update( - id, - updateDto, - req.user.userId - ); + const iotDevice = await this.iotDeviceService.update(id, updateDto, req.user.userId); AuditLog.success( ActionType.UPDATE, IoTDevice.name, @@ -297,15 +272,10 @@ export class IoTDeviceController { ) ); - const devices = await this.iotDeviceService.createMany( - createDto.data, - req.user.userId - ); + const devices = await this.iotDeviceService.createMany(createDto.data, req.user.userId); // Iterate through the devices once, splitting it into a tuple with the data we want to log - const { deviceIds, deviceNames } = buildIoTDeviceCreateUpdateAuditData( - devices - ); + const { deviceIds, deviceNames } = buildIoTDeviceCreateUpdateAuditData(devices); if (!deviceIds.length) { AuditLog.fail(ActionType.CREATE, IoTDevice.name, req.user.userId); @@ -322,9 +292,7 @@ export class IoTDeviceController { } catch (err) { AuditLog.fail(ActionType.CREATE, IoTDevice.name, req.user.userId); this.logger.error( - `Failed to create IoTDevice from dto: ${JSON.stringify( - createDto - )}. Error: ${err}` + `Failed to create IoTDevice from dto: ${JSON.stringify(createDto)}. Error: ${err}` ); throw err; } @@ -346,12 +314,7 @@ export class IoTDeviceController { try { validDevices.data = updateDto.data.reduce( - ensureIoTDeviceUpdatePayload( - validDevices, - oldIotDevices, - devicesNotFound, - req - ), + ensureIoTDeviceUpdatePayload(validDevices, oldIotDevices, devicesNotFound, req), [] ); } catch (err) { @@ -422,9 +385,7 @@ export class IoTDeviceController { ); if (oldIotDevice.type !== IoTDeviceType.GenericHttp) { - throw new BadRequestException( - "The requested device is not a generic HTTP device" - ); + throw new BadRequestException("The requested device is not a generic HTTP device"); } const result = await this.iotDeviceService.resetHttpDeviceApiKey( @@ -450,14 +411,8 @@ export class IoTDeviceController { @Param("applicationId", new ParseIntPipe()) applicationId: number ): Promise { try { - checkIfUserHasAccessToApplication( - req, - applicationId, - ApplicationAccessScope.Read - ); - const csvFile = await this.iotDeviceService.getDevicesMetadataCsv( - applicationId - ); + checkIfUserHasAccessToApplication(req, applicationId, ApplicationAccessScope.Read); + const csvFile = await this.iotDeviceService.getDevicesMetadataCsv(applicationId); return new StreamableFile(csvFile); } catch (err) { this.logger.error(err); diff --git a/src/controllers/admin-controller/multicast.controller.ts b/src/controllers/admin-controller/multicast.controller.ts index 59c94b45..b8eda2bb 100644 --- a/src/controllers/admin-controller/multicast.controller.ts +++ b/src/controllers/admin-controller/multicast.controller.ts @@ -15,7 +15,6 @@ import { ParseIntPipe, Logger, } from "@nestjs/common"; -import { MulticastService } from "../../services/device-management/multicast.service"; import { CreateMulticastDto } from "../../entities/dto/create-multicast.dto"; import { UpdateMulticastDto } from "../../entities/dto/update-multicast.dto"; import { @@ -44,6 +43,7 @@ import { DeleteResponseDto } from "@dto/delete-application-response.dto"; import { MulticastDownlinkQueueResponseDto } from "@dto/chirpstack/chirpstack-multicast-downlink-queue-response.dto"; import { CreateMulticastDownlinkDto } from "@dto/create-multicast-downlink.dto"; import { CreateChirpstackMulticastQueueItemResponse } from "@dto/chirpstack/create-chirpstack-multicast-queue-item.dto"; +import { MulticastService } from "@services/chirpstack/multicast.service"; @ApiTags("Multicast") @UseGuards(ComposeAuthGuard, RolesGuard) diff --git a/src/entities/application.entity.ts b/src/entities/application.entity.ts index f02a8726..97f77d13 100644 --- a/src/entities/application.entity.ts +++ b/src/entities/application.entity.ts @@ -113,4 +113,6 @@ export class Application extends DbBaseEntity { cascade: true, }) deviceTypes?: ApplicationDeviceType[]; + @Column({ nullable: true }) + chirpstackId?: string; } diff --git a/src/entities/dto/chirpstack/chirpstack-application-response.dto.ts b/src/entities/dto/chirpstack/chirpstack-application-response.dto.ts index c058724e..cfb77375 100644 --- a/src/entities/dto/chirpstack/chirpstack-application-response.dto.ts +++ b/src/entities/dto/chirpstack/chirpstack-application-response.dto.ts @@ -2,7 +2,5 @@ export class ChirpstackApplicationResponseDto { id: string; name: string; description: string; - organizationID: string; - serviceProfileID: string; - serviceProfileName: string; + tenantId: string; } diff --git a/src/entities/dto/chirpstack/chirpstack-application.dto.ts b/src/entities/dto/chirpstack/chirpstack-application.dto.ts index f5517355..ddde7e39 100644 --- a/src/entities/dto/chirpstack/chirpstack-application.dto.ts +++ b/src/entities/dto/chirpstack/chirpstack-application.dto.ts @@ -1,6 +1,5 @@ export class ChirpstackApplicationDto { name: string; description: string; - organizationID: string; - serviceProfileID: string; + tenantId: string; } diff --git a/src/entities/dto/chirpstack/chirpstack-device-contents.dto.ts b/src/entities/dto/chirpstack/chirpstack-device-contents.dto.ts index 47564260..57f93294 100644 --- a/src/entities/dto/chirpstack/chirpstack-device-contents.dto.ts +++ b/src/entities/dto/chirpstack/chirpstack-device-contents.dto.ts @@ -1,5 +1,5 @@ import { ApiHideProperty, ApiProperty } from "@nestjs/swagger"; -import { IsHexadecimal, IsOptional, IsString, IsUUID, Length, Matches } from "class-validator"; +import { IsHexadecimal, IsOptional, IsString, IsUUID, Length } from "class-validator"; export class ChirpstackDeviceContentsDto { @ApiHideProperty() @@ -14,17 +14,13 @@ export class ChirpstackDeviceContentsDto { @ApiProperty({ required: true }) @IsString() @IsHexadecimal() - @Length(16,16) + @Length(16, 16) devEUI: string; @ApiProperty({ required: true }) @IsUUID() deviceProfileID: string; - @ApiProperty({ required: true }) - @IsUUID() - serviceProfileID: string; - @ApiProperty({ required: false, default: false }) @IsOptional() isDisabled?: boolean; @@ -34,13 +30,10 @@ export class ChirpstackDeviceContentsDto { skipFCntCheck?: boolean; @ApiProperty({ required: false, default: {} }) - variables?: JSON; - - @ApiProperty({ required: false, default: {} }) - tags?: JSON; + variables?: Array<[string, string]>; @ApiProperty({ required: false, default: {} }) - OTAAapplicationKey: string; + tags?: Array<[string, string]>; @ApiHideProperty() deviceStatusBattery?: number; diff --git a/src/entities/dto/chirpstack/chirpstack-device-keys-response.dto.ts b/src/entities/dto/chirpstack/chirpstack-device-keys-response.dto.ts index c041b78c..7b9a7ada 100644 --- a/src/entities/dto/chirpstack/chirpstack-device-keys-response.dto.ts +++ b/src/entities/dto/chirpstack/chirpstack-device-keys-response.dto.ts @@ -6,5 +6,4 @@ export class ChirpstackDeviceKeysContentDto { devEUI: string; nwkKey: string; appKey: string; - genAppKey: string; } diff --git a/src/entities/dto/chirpstack/chirpstack-device-metrics.dto.ts b/src/entities/dto/chirpstack/chirpstack-device-metrics.dto.ts new file mode 100644 index 00000000..294642df --- /dev/null +++ b/src/entities/dto/chirpstack/chirpstack-device-metrics.dto.ts @@ -0,0 +1,13 @@ +export class DeviceMetricsDto { + [timestamp: string]: { + rssi: number; + snr: number; + rxPacketsPerDr: Record; + }; +} + +export enum MetricProperties { + rssi = "rssi", + snr = "snr", + dr = "rxPacketsPerDr", +} diff --git a/src/entities/dto/chirpstack/chirpstack-multicast-contents.dto.ts b/src/entities/dto/chirpstack/chirpstack-multicast-contents.dto.ts index d8297465..d34d258e 100644 --- a/src/entities/dto/chirpstack/chirpstack-multicast-contents.dto.ts +++ b/src/entities/dto/chirpstack/chirpstack-multicast-contents.dto.ts @@ -1,6 +1,5 @@ import { multicastGroup } from "@enum/multicast-type.enum"; import { ApiProperty } from "@nestjs/swagger"; -import { Matches } from "class-validator"; export class ChirpstackMulticastContentsDto { @ApiProperty({ required: true }) @@ -21,7 +20,7 @@ export class ChirpstackMulticastContentsDto { mcNwkSKey: string; @ApiProperty({ required: true }) name: string; - @ApiProperty({ required: false }) - pingSlotPeriod: number; - + @ApiProperty({ required: true }) + id: string; + } diff --git a/src/entities/dto/chirpstack/chirpstack-multicast-downlink-queue-response.dto.ts b/src/entities/dto/chirpstack/chirpstack-multicast-downlink-queue-response.dto.ts index 089f7189..13b8f9f6 100644 --- a/src/entities/dto/chirpstack/chirpstack-multicast-downlink-queue-response.dto.ts +++ b/src/entities/dto/chirpstack/chirpstack-multicast-downlink-queue-response.dto.ts @@ -1,13 +1,10 @@ export interface MulticastQueueItem { - devEUI?: string; - confirmed?: boolean; + multicastGroupId?: string; fCnt?: number; fPort?: number; data: string; - jsonObject?: string; } export interface MulticastDownlinkQueueResponseDto { deviceQueueItems: MulticastQueueItem[]; - totalCount: number; } diff --git a/src/entities/dto/chirpstack/create-device-profile.dto.ts b/src/entities/dto/chirpstack/create-device-profile.dto.ts index 7b631ed7..47a5d9b7 100644 --- a/src/entities/dto/chirpstack/create-device-profile.dto.ts +++ b/src/entities/dto/chirpstack/create-device-profile.dto.ts @@ -1,4 +1,4 @@ -import { ApiProperty } from "@nestjs/swagger"; +import { ApiHideProperty, ApiProperty } from "@nestjs/swagger"; import { Type } from "class-transformer"; import { ValidateNested } from "class-validator"; @@ -12,4 +12,10 @@ export class CreateDeviceProfileDto { @ApiProperty({ required: true }) internalOrganizationId: number; + + @ApiHideProperty() + createdAt: Date; + + @ApiHideProperty() + updatedAt: Date; } diff --git a/src/entities/dto/chirpstack/create-network-server.dto.ts b/src/entities/dto/chirpstack/create-network-server.dto.ts deleted file mode 100644 index 178c7771..00000000 --- a/src/entities/dto/chirpstack/create-network-server.dto.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { Type } from "class-transformer"; -import { ValidateNested } from "class-validator"; - -import { NetworkServerDto } from "./network-server.dto"; - -export class CreateNetworkServerDto { - @ApiProperty({ required: true }) - @ValidateNested({ each: true }) - @Type(() => NetworkServerDto) - networkServer: NetworkServerDto; -} diff --git a/src/entities/dto/chirpstack/create-service-profile.dto.ts b/src/entities/dto/chirpstack/create-service-profile.dto.ts deleted file mode 100644 index c6882706..00000000 --- a/src/entities/dto/chirpstack/create-service-profile.dto.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { Type } from "class-transformer"; -import { ValidateNested } from "class-validator"; - -import { ServiceProfileDto } from "./service-profile.dto"; - -export class CreateServiceProfileDto { - @ApiProperty({ required: true }) - @ValidateNested({ each: true }) - @Type(() => ServiceProfileDto) - serviceProfile: ServiceProfileDto; -} diff --git a/src/entities/dto/chirpstack/device-profile.dto.ts b/src/entities/dto/chirpstack/device-profile.dto.ts index 51df9b1c..c0fc251a 100644 --- a/src/entities/dto/chirpstack/device-profile.dto.ts +++ b/src/entities/dto/chirpstack/device-profile.dto.ts @@ -1,14 +1,9 @@ -import { ApiHideProperty, ApiProperty } from "@nestjs/swagger"; import { - IsArray, - IsInt, - IsNumber, - IsOptional, - IsString, - Length, - Min, - ValidateIf, -} from "class-validator"; + MacVersionMap, + RegParamsRevisionMap, +} from "@chirpstack/chirpstack-api/common/common_pb"; +import { ApiHideProperty, ApiProperty } from "@nestjs/swagger"; +import { IsInt, IsNotEmpty, IsOptional, IsString, Length, Min, ValidateIf } from "class-validator"; export class DeviceProfileDto { @ApiProperty({ required: true }) @@ -17,15 +12,13 @@ export class DeviceProfileDto { name: string; @ApiProperty({ required: true }) - macVersion: "1.0.0" | "1.0.1" | "1.0.2" | "1.0.3" | "1.1.0"; + @IsNotEmpty() + macVersion: MacVersionMap[keyof MacVersionMap]; @ApiProperty({ required: true }) - @IsInt() - @Min(0) - maxEIRP: number; + @IsNotEmpty() - @ApiProperty({ required: true }) - regParamsRevision: "A" | "B"; + regParamsRevision: RegParamsRevisionMap[keyof RegParamsRevisionMap]; @ApiProperty({ required: false }) @IsString() @@ -42,37 +35,12 @@ export class DeviceProfileDto { @IsInt() classCTimeout?: number; - @ApiProperty({ required: true }) - @IsInt() - @Min(0) - geolocBufferTTL: number; - - @ApiProperty({ required: true }) - @IsInt() - @Min(0) - geolocMinBufferSize: number; - - @ApiProperty({ required: false }) - maxDutyCycle?: number; - @ApiProperty({ required: false }) id?: string; - @ApiHideProperty() - networkServerID?: string; - @ApiHideProperty() organizationID?: string; - @ApiProperty({ required: false }) - payloadCodec?: string; - - @ApiProperty({ required: false }) - payloadDecoderScript?: string; - - @ApiProperty({ required: false }) - payloadEncoderScript?: string; - @ApiProperty({ required: false }) @ValidateIf((o: DeviceProfileDto) => o.supportsClassB) @Min(0) @@ -90,7 +58,7 @@ export class DeviceProfileDto { pingSlotPeriod?: number; @ApiProperty({ required: false }) - rfRegion?: string; + rfRegion?: string @ApiProperty({ required: false }) @ValidateIf((o: DeviceProfileDto) => o.supportsJoin == false) @@ -116,15 +84,6 @@ export class DeviceProfileDto { @IsInt() rxFreq2?: number; - @ApiProperty({ required: false }) - @ValidateIf((o: DeviceProfileDto) => o.supportsJoin == false) - @IsArray() - @IsNumber({ maxDecimalPlaces: 0 }, { each: true }) - factoryPresetFreqs: number[]; - - @ApiProperty({ required: false }) - supports32BitFCnt?: boolean; - @ApiProperty({ required: false }) supportsClassB?: boolean; @@ -135,7 +94,9 @@ export class DeviceProfileDto { supportsJoin?: boolean; @ApiHideProperty() - tags?: { [id: string]: string | number }; + tags?: { [id: string]: string }; + @ApiHideProperty() + tagsMap?: Array<[string, string]>; @ApiHideProperty() internalOrganizationId?: number; @@ -145,4 +106,6 @@ export class DeviceProfileDto { @ApiHideProperty() createdBy?: number; + @ApiProperty({ required: false }) + devStatusReqFreq?: number; } diff --git a/src/entities/dto/chirpstack/device/lorawan-stats.response.dto.ts b/src/entities/dto/chirpstack/device/lorawan-stats.response.dto.ts index e4038de6..874daa01 100644 --- a/src/entities/dto/chirpstack/device/lorawan-stats.response.dto.ts +++ b/src/entities/dto/chirpstack/device/lorawan-stats.response.dto.ts @@ -3,11 +3,8 @@ export class LoRaWANStatsResponseDto { } export class LoRaWANStatsElementDto { - errors: Record; gwRssi: number; gwSnr: number; - rxPackets: number; rxPacketsPerDr: Record; - rxPacketsPerFrequency: Record; timestamp: string; } diff --git a/src/entities/dto/chirpstack/gateway-contents.dto.ts b/src/entities/dto/chirpstack/gateway-contents.dto.ts index f5fe225f..b6e3efa9 100644 --- a/src/entities/dto/chirpstack/gateway-contents.dto.ts +++ b/src/entities/dto/chirpstack/gateway-contents.dto.ts @@ -60,15 +60,12 @@ export class GatewayContentsDto { name: string; @ApiHideProperty() - networkServerID: string; - - @ApiHideProperty() - organizationID: string; + tenantId: string; @ApiProperty({ required: false }) @IsJSON() tagsString?: string; @ApiHideProperty() - tags?: { [id: string]: string | number }; + tags?: { [id: string]: string }; } diff --git a/src/entities/dto/chirpstack/list-all-device-profiles-response.dto.ts b/src/entities/dto/chirpstack/list-all-device-profiles-response.dto.ts index a998569f..9e906979 100644 --- a/src/entities/dto/chirpstack/list-all-device-profiles-response.dto.ts +++ b/src/entities/dto/chirpstack/list-all-device-profiles-response.dto.ts @@ -1,6 +1,16 @@ import { DeviceProfileDto } from "./device-profile.dto"; export class ListAllDeviceProfilesResponseDto { - result: DeviceProfileDto[]; + result: DeviceProfileListDto[]; totalCount: string; } + +export class DeviceProfileListDto { + id: string; + name: string; + createdAt: Date; + createdBy?: number; + internalOrganizationId?: number; + updatedAt: Date; + updatedBy?: number; +} diff --git a/src/entities/dto/chirpstack/list-all-network-server-response.dto.ts b/src/entities/dto/chirpstack/list-all-network-server-response.dto.ts deleted file mode 100644 index 053f9e98..00000000 --- a/src/entities/dto/chirpstack/list-all-network-server-response.dto.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { NetworkServerDto } from "./network-server.dto"; - -export class ListAllNetworkServerResponseDto { - result: NetworkServerDto[]; - totalCount: number; -} diff --git a/src/entities/dto/chirpstack/list-all-service-profiles-response.dto.ts b/src/entities/dto/chirpstack/list-all-service-profiles-response.dto.ts deleted file mode 100644 index ea28f7ac..00000000 --- a/src/entities/dto/chirpstack/list-all-service-profiles-response.dto.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ServiceProfileDto } from "./service-profile.dto"; - -export class ListAllServiceProfilesResponseDto { - result: ServiceProfileDto[]; - totalCount: string; -} diff --git a/src/entities/dto/chirpstack/network-server.dto.ts b/src/entities/dto/chirpstack/network-server.dto.ts deleted file mode 100644 index 2d2211a8..00000000 --- a/src/entities/dto/chirpstack/network-server.dto.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { IsOptional, IsString, MaxLength, MinLength } from "class-validator"; - -export class NetworkServerDto { - @ApiProperty({ required: true }) - @IsString() - @MaxLength(1024) - name: string; - - @ApiProperty({ required: true }) - @IsString() - @MaxLength(1024) - server: string; - - @ApiProperty({ required: false }) - @IsOptional() - id?: number; - - @ApiProperty({ required: false }) - @IsString() - @MinLength(1) - @MaxLength(50) - caCert?: string; - - @ApiProperty({ required: false }) - @IsOptional() - gatewayDiscoveryDR?: number; - - @ApiProperty({ required: false }) - @IsOptional() - gatewayDiscoveryEnabled?: boolean; - - @ApiProperty({ required: false }) - @IsOptional() - gatewayDiscoveryInterval?: number; - - @ApiProperty({ required: false }) - @IsOptional() - gatewayDiscoveryTXFrequency?: number; - - @ApiProperty({ required: false }) - @IsOptional() - @IsString() - @MaxLength(1024) - routingProfileCACert?: string; - - @ApiProperty({ required: false }) - @IsOptional() - @IsString() - @MaxLength(1024) - routingProfileTLSCert?: string; - - @ApiProperty({ required: false }) - @IsOptional() - @IsString() - @MaxLength(1024) - routingProfileTLSKey?: string; - - @ApiProperty({ required: false }) - @IsOptional() - @IsString() - @MaxLength(1024) - tlsCert?: string; - - @ApiProperty({ required: false }) - @IsOptional() - @IsString() - @MaxLength(1024) - tlsKey?: string; -} diff --git a/src/entities/dto/chirpstack/service-profile.dto.ts b/src/entities/dto/chirpstack/service-profile.dto.ts deleted file mode 100644 index d0e3caf5..00000000 --- a/src/entities/dto/chirpstack/service-profile.dto.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { ApiHideProperty, ApiProperty } from "@nestjs/swagger"; -import { IsIn, IsInt, IsString, Length, Max, MaxLength, Min } from "class-validator"; - -export class ServiceProfileDto { - @ApiProperty({ required: false }) - id?: string; - - @ApiProperty({ required: true }) - @Length(1, 1024) - name: string; - - @ApiHideProperty() - networkServerID?: string; - - @ApiHideProperty() - addGWMetaData = true; - - @ApiProperty({ required: false }) - channelMask?: string; - - @ApiProperty({ required: false }) - devStatusReqFreq?: number; - - @ApiProperty({ required: false }) - dlBucketSize?: number; - - @ApiProperty({ required: false }) - dlRate?: number; - - @ApiProperty({ required: false }) - dlRatePolicy?: string; - - @ApiProperty({ required: false }) - @IsInt() - @Min(0, { message: "Max data rate må ikke være negativ" }) - @Max(7, { message: "Max data rate må ikke være større end 7" }) - drMax?: number; - - @ApiProperty({ required: true }) - @IsInt() - @Min(0, { message: "Min data rate må ikke være negativ" }) - @Max(7, { message: "Min data rate må ikke være større end 7" }) - drMin?: number; - - @ApiProperty({ required: false }) - hrAllowed?: boolean; - - @ApiProperty({ required: false }) - minGWDiversity?: number; - - @ApiHideProperty() - nwkGeoLoc = true; - - @ApiHideProperty() - organizationID?: string; - - @ApiProperty({ required: false }) - prAllowed?: boolean; - - @ApiProperty({ required: false }) - raAllowed?: boolean; - - @ApiProperty({ required: false }) - reportDevStatusBattery?: boolean; - - @ApiProperty({ required: false }) - reportDevStatusMargin?: boolean; - - @ApiProperty({ required: true }) - targetPER?: number; - - @ApiProperty({ required: false }) - ulBucketSize?: number; - - @ApiProperty({ required: false }) - ulRate?: number; - - @ApiProperty({ required: false }) - ulRatePolicy?: string; -} diff --git a/src/entities/dto/chirpstack/update-gateway.dto.ts b/src/entities/dto/chirpstack/update-gateway.dto.ts index d8e4f1f0..3b628b26 100644 --- a/src/entities/dto/chirpstack/update-gateway.dto.ts +++ b/src/entities/dto/chirpstack/update-gateway.dto.ts @@ -6,6 +6,10 @@ import { Type } from "class-transformer"; export class UpdateGatewayContentsDto extends OmitType(GatewayContentsDto, ["gatewayId"]) { @ApiHideProperty() gatewayId: string; + @ApiHideProperty() + createdBy?: number; + @ApiHideProperty() + updatedBy?: number; } export class UpdateGatewayDto { diff --git a/src/entities/dto/chirpstack/update-network-server.dto.ts b/src/entities/dto/chirpstack/update-network-server.dto.ts deleted file mode 100644 index 66d75153..00000000 --- a/src/entities/dto/chirpstack/update-network-server.dto.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { CreateNetworkServerDto } from "./create-network-server.dto"; - -export class UpdateNetworkServerDto extends CreateNetworkServerDto {} diff --git a/src/entities/dto/chirpstack/update-service-profile.dto.ts b/src/entities/dto/chirpstack/update-service-profile.dto.ts deleted file mode 100644 index 4020bb8c..00000000 --- a/src/entities/dto/chirpstack/update-service-profile.dto.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { CreateServiceProfileDto } from "./create-service-profile.dto"; - -export class UpdateServiceProfileDto extends CreateServiceProfileDto {} diff --git a/src/entities/dto/create-application.dto.ts b/src/entities/dto/create-application.dto.ts index ed85f630..30dab95c 100644 --- a/src/entities/dto/create-application.dto.ts +++ b/src/entities/dto/create-application.dto.ts @@ -99,4 +99,9 @@ export class CreateApplicationDto { }, }) permissionIds?: number[]; + @ApiProperty({ required: false }) + @IsOptional() + @IsString() + @MaxLength(1024) + chirpstackId?: string; } diff --git a/src/entities/dto/create-lorawan-settings.dto.ts b/src/entities/dto/create-lorawan-settings.dto.ts index 383c10b1..86de0f66 100644 --- a/src/entities/dto/create-lorawan-settings.dto.ts +++ b/src/entities/dto/create-lorawan-settings.dto.ts @@ -16,7 +16,6 @@ import { ChirpstackDeviceContentsDto } from "./chirpstack/chirpstack-device-cont export class CreateLoRaWANSettingsDto extends PickType(ChirpstackDeviceContentsDto, [ "devEUI", "deviceProfileID", - "serviceProfileID", "skipFCntCheck", "isDisabled", "deviceStatusBattery", diff --git a/src/entities/dto/update-multicast.dto.ts b/src/entities/dto/update-multicast.dto.ts index 6728ac8d..2359b823 100644 --- a/src/entities/dto/update-multicast.dto.ts +++ b/src/entities/dto/update-multicast.dto.ts @@ -1,4 +1,8 @@ import { PartialType } from "@nestjs/mapped-types"; import { CreateMulticastDto } from "./create-multicast.dto"; +import { ApiProperty } from "@nestjs/swagger"; -export class UpdateMulticastDto extends PartialType(CreateMulticastDto) {} +export class UpdateMulticastDto extends PartialType(CreateMulticastDto) { + @ApiProperty({ required: false }) + id: string; +} diff --git a/src/entities/enum/device-profile-enums.enum.ts b/src/entities/enum/device-profile-enums.enum.ts new file mode 100644 index 00000000..ba21b70f --- /dev/null +++ b/src/entities/enum/device-profile-enums.enum.ts @@ -0,0 +1,17 @@ +export enum MacVersions { + "1.0.0", + "1.0.1", + "1.0.2", + "1.0.3", + "1.0.4", + "1.1.0", +} + +export enum RegParamsRevisions { + "A", + "B", + "RP002-1.0.0", + "RP002-1.0.1", + "RP002-1.0.2", + "RP002-1.0.3", +} diff --git a/src/entities/enum/error-codes.enum.ts b/src/entities/enum/error-codes.enum.ts index a64001ce..225cd1a8 100644 --- a/src/entities/enum/error-codes.enum.ts +++ b/src/entities/enum/error-codes.enum.ts @@ -38,8 +38,6 @@ export enum ErrorCodes { DeleteNotAllowedHasLoRaWANDevices = "MESSAGE.DELETE-NOT-ALLOWED-HAS-LORAWAN-DEVICE", KOMBITLoginFailed = "MESSAGE.KOMBIT-LOGIN-FAILED", ApiKeyAuthFailed = "MESSAGE.API-KEY-AUTH-FAILED", - DifferentServiceprofile = "MESSAGE.DIFFERENT-SERVICE-PROFILE", - NewDevicesWrongServiceProfile = "MESSAGE.WRONG-SERVICE-PROFILE", TooMuchData = "MESSAGE.TOO-MUCH-DATA", ApplicationDoesNotExist = "MESSAGE.APPLICATION-DOES-NOT-EXIST", FailedToCreateOrUpdateIotDevice = "MESSAGE.FAILED-TO-CREATE-OR-UPDATE-IOT-DEVICE", @@ -50,4 +48,5 @@ export enum ErrorCodes { SendMailError = "MESSAGE.SEND-MAIL-ERROR", UserDoesNotExistInArray = "MESSAGE.USER-DOES-NOT-EXIST", UserAlreadyInPermission = "MESSAGE.USER-ALREADY-IN-PERMISSION", + CouldntGetApplications= "MESSAGE.COULDN'T-GET-CS-APPLICATIONS" } diff --git a/src/entities/interfaces/chirpstack-network-server-send-status.interface.ts b/src/entities/interfaces/chirpstack-network-server-send-status.interface.ts deleted file mode 100644 index 6b8170ce..00000000 --- a/src/entities/interfaces/chirpstack-network-server-send-status.interface.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface ChirpstackNetworkServerSendStatus { - totalCount?: number; - result?: []; -} diff --git a/src/entities/interfaces/chirpstack-post-return.interface.ts b/src/entities/interfaces/chirpstack-post-return.interface.ts new file mode 100644 index 00000000..bf92e0a5 --- /dev/null +++ b/src/entities/interfaces/chirpstack-post-return.interface.ts @@ -0,0 +1,3 @@ +export interface PostReturnInterface { + id: string; +} diff --git a/src/entities/lorawan-device.entity.ts b/src/entities/lorawan-device.entity.ts index 00249a9a..70175c8c 100644 --- a/src/entities/lorawan-device.entity.ts +++ b/src/entities/lorawan-device.entity.ts @@ -15,7 +15,7 @@ export class LoRaWANDevice extends IoTDevice { deviceEUI: string; @Column({ nullable: true }) - chirpstackApplicationId: number; + chirpstackApplicationId: string; @BeforeInsert() private beforeInsert() { diff --git a/src/helpers/message-payload.helper.ts b/src/helpers/message-payload.helper.ts index d443dede..4c6465a0 100644 --- a/src/helpers/message-payload.helper.ts +++ b/src/helpers/message-payload.helper.ts @@ -8,7 +8,7 @@ export interface LoRaWANSignalData { name: string; rssi: number; time: string; - loRaSNR: number; + snr: number; location: { altitude: number; latitude: number; @@ -47,8 +47,8 @@ export const isValidLoRaWANSignalData = (rxInfo: unknown): rxInfo is LoRaWANSign typeof unknownInfo[0] === "object" && hasProps(unknownInfo[0], nameof("rssi")) && typeof unknownInfo[0].rssi === "number" && - hasProps(unknownInfo[0], nameof("loRaSNR")) && - typeof unknownInfo[0].loRaSNR === "number" + hasProps(unknownInfo[0], nameof("snr")) && + typeof unknownInfo[0].snr === "number" ); } diff --git a/src/migration/1701075072037-changed-chirpstackapplicationid-to-string.ts b/src/migration/1701075072037-changed-chirpstackapplicationid-to-string.ts new file mode 100644 index 00000000..6d31c5f7 --- /dev/null +++ b/src/migration/1701075072037-changed-chirpstackapplicationid-to-string.ts @@ -0,0 +1,52 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class changedChirpstackapplicationidToString1701075072037 implements MigrationInterface { + name = 'changedChirpstackapplicationidToString1701075072037' + + GuidZeros = "00000000-0000-0000-0000-" + public async up(queryRunner: QueryRunner): Promise { + //SELECT LORAWAN IDS + const iotDevices = await queryRunner.query(`SELECT * FROM "iot_device" WHERE TYPE = 'LORAWAN'`) + + //CONVERT TO GUID + iotDevices.forEach((device: any) => { + device.chirpstackApplicationId = this.GuidZeros + this.appendZeros(+device.chirpstackApplicationId) + }); + + await queryRunner.query(`ALTER TABLE "iot_device" DROP COLUMN "chirpstackApplicationId"`); + await queryRunner.query(`ALTER TABLE "iot_device" ADD "chirpstackApplicationId" character varying`); + + //UPDATE IN NEW TABLE + iotDevices.forEach(async (device: any) => { + await queryRunner.query(`UPDATE "iot_device" SET "chirpstackApplicationId" = $1 WHERE "id" = $2`, [device.chirpstackApplicationId, device.id]); + }); + + } + + public async down(queryRunner: QueryRunner): Promise { + //SELECT LORAWAN IDS + const iotDevices = await queryRunner.query(`SELECT * FROM "iot_device" WHERE TYPE = 'LORAWAN'`) + + await queryRunner.query(`ALTER TABLE "iot_device" DROP COLUMN "chirpstackApplicationId"`); + await queryRunner.query(`ALTER TABLE "iot_device" ADD "chirpstackApplicationId" integer`); + + + //CONVERT TO INT + iotDevices.forEach((device: any) => { + device.chirpstackApplicationId = parseInt(device.chirpstackApplicationId.slice(-12)) + }); + + //UPDATE IN NEW TABLE + iotDevices.forEach(async (device: any) => { + await queryRunner.query(`UPDATE "iot_device" SET "chirpstackApplicationId" = $1 WHERE "id" = $2`, [device.chirpstackApplicationId, device.id]); + }); + } + private appendZeros(id: number) { + let numString = id.toString(); + while (numString.length < 12) { + numString = '0' + numString; + } + return numString; + } + +} diff --git a/src/migration/1701260283869-added-chirpstackId-to-application.ts b/src/migration/1701260283869-added-chirpstackId-to-application.ts new file mode 100644 index 00000000..76a91b2a --- /dev/null +++ b/src/migration/1701260283869-added-chirpstackId-to-application.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class addedChirpstackIdToApplication1701260283869 implements MigrationInterface { + name = 'addedChirpstackIdToApplication1701260283869' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "application" ADD "chirpstackId" character varying`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "application" DROP COLUMN "chirpstackId"`); + } + +} diff --git a/src/modules/device-integrations/chirpstack-administration.module.ts b/src/modules/device-integrations/chirpstack-administration.module.ts index 1c56486f..b5758e9a 100644 --- a/src/modules/device-integrations/chirpstack-administration.module.ts +++ b/src/modules/device-integrations/chirpstack-administration.module.ts @@ -1,34 +1,29 @@ import { ChirpstackGatewayController } from "@admin-controller/chirpstack/chirpstack-gateway.controller"; import { DeviceProfileController } from "@admin-controller/chirpstack/device-profile.controller"; -import { ServiceProfileController } from "@admin-controller/chirpstack/service-profile.controller"; import configuration from "@config/configuration"; +import { SharedModule } from "@modules/shared.module"; import { HttpModule } from "@nestjs/axios"; import { Module } from "@nestjs/common"; import { ConfigModule } from "@nestjs/config"; +import { ApplicationChirpstackService } from "@services/chirpstack/chirpstack-application.service"; import { ChirpstackDeviceService } from "@services/chirpstack/chirpstack-device.service"; import { ChirpstackGatewayService } from "@services/chirpstack/chirpstack-gateway.service"; import { DeviceProfileService } from "@services/chirpstack/device-profile.service"; import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; -import { ChirpstackSetupNetworkServerService } from "@services/chirpstack/network-server.service"; -import { ServiceProfileService } from "@services/chirpstack/service-profile.service"; -import { NetworkServerController } from "@admin-controller/chirpstack/network-server.controller"; @Module({ controllers: [ ChirpstackGatewayController, - ServiceProfileController, DeviceProfileController, - NetworkServerController ], - imports: [HttpModule, ConfigModule.forRoot({ load: [configuration] })], + imports: [HttpModule, ConfigModule.forRoot({ load: [configuration] }), SharedModule], providers: [ GenericChirpstackConfigurationService, - ChirpstackSetupNetworkServerService, ChirpstackGatewayService, - ServiceProfileService, DeviceProfileService, ChirpstackDeviceService, + ApplicationChirpstackService ], - exports: [ChirpstackDeviceService, ChirpstackGatewayService], + exports: [ChirpstackDeviceService, ChirpstackGatewayService, ApplicationChirpstackService], }) export class ChirpstackAdministrationModule {} diff --git a/src/modules/device-integrations/lorawan-gateway.module.ts b/src/modules/device-integrations/lorawan-gateway.module.ts index e5ce4972..08f542a8 100644 --- a/src/modules/device-integrations/lorawan-gateway.module.ts +++ b/src/modules/device-integrations/lorawan-gateway.module.ts @@ -3,7 +3,6 @@ import { SharedModule } from "@modules/shared.module"; import { Module } from "@nestjs/common"; import { ChirpstackGatewayService } from "@services/chirpstack/chirpstack-gateway.service"; import { GatewayStatusHistoryService } from "@services/chirpstack/gateway-status-history.service"; -import { ChirpstackSetupNetworkServerService } from "@services/chirpstack/network-server.service"; import { GatewayBootstrapperService } from "@services/chirpstack/gateway-boostrapper.service"; import { HttpModule } from "@nestjs/axios"; @@ -12,7 +11,6 @@ import { HttpModule } from "@nestjs/axios"; imports: [SharedModule, HttpModule], providers: [ ChirpstackGatewayService, - ChirpstackSetupNetworkServerService, GatewayStatusHistoryService, GatewayBootstrapperService, ], diff --git a/src/modules/device-management/multicast.module.ts b/src/modules/device-management/multicast.module.ts index ccbe3bb7..db497135 100644 --- a/src/modules/device-management/multicast.module.ts +++ b/src/modules/device-management/multicast.module.ts @@ -3,7 +3,7 @@ import { SharedModule } from "@modules/shared.module"; import { HttpModule } from "@nestjs/axios"; import { forwardRef, Module } from "@nestjs/common"; import { MulticastController } from "../../controllers/admin-controller/multicast.controller"; -import { MulticastService } from "../../services/device-management/multicast.service"; +import { MulticastService } from "../../services/chirpstack/multicast.service"; import { ApplicationModule } from "./application.module"; import { IoTDeviceModule } from "./iot-device.module"; diff --git a/src/services/chirpstack/chirpstack-application.service.ts b/src/services/chirpstack/chirpstack-application.service.ts new file mode 100644 index 00000000..dc0c6415 --- /dev/null +++ b/src/services/chirpstack/chirpstack-application.service.ts @@ -0,0 +1,58 @@ +import { BadRequestException, Injectable } from "@nestjs/common"; +import { GenericChirpstackConfigurationService } from "./generic-chirpstack-configuration.service"; + +import { + Application, + CreateApplicationRequest, + DeleteApplicationRequest, + UpdateApplicationRequest, +} from "@chirpstack/chirpstack-api/api/application_pb"; +import { CreateApplicationDto } from "@dto/create-application.dto"; +import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { Application as DbApplication } from "@entities/application.entity"; + +@Injectable() +export class ApplicationChirpstackService extends GenericChirpstackConfigurationService { + constructor() { + super(); + } + defaultApplicationName = "os2iot"; + DEFAULT_DESCRIPTION = "Created by OS2IoT"; + public async createApplication(dto: CreateApplicationDto): Promise { + const req = new CreateApplicationRequest(); + const application = new Application(); + application.setDescription(this.DEFAULT_DESCRIPTION); + application.setName(this.defaultApplicationName + "-" + dto.name); + application.setTenantId(await this.getDefaultOrganizationId()); + + req.setApplication(application); + try { + return await this.post("applications", this.applicationServiceClient, req); + } catch (e) { + throw e; + } + } + public async deleteApplication(id: string): Promise { + const req = new DeleteApplicationRequest(); + req.setId(id); + try { + return await this.delete("applications", this.applicationServiceClient, req); + } catch (e) { + throw e; + } + } + public async updateApplication(dto: DbApplication): Promise { + const req = new UpdateApplicationRequest(); + const application = new Application(); + application.setId(dto.chirpstackId); + application.setDescription(this.DEFAULT_DESCRIPTION); + application.setName(this.defaultApplicationName + "-" + dto.name); + application.setTenantId(await this.getDefaultOrganizationId()); + req.setApplication(application); + try { + return await this.put("applications", this.applicationServiceClient, req); + } catch (e) { + throw e; + } + } +} diff --git a/src/services/chirpstack/chirpstack-device.service.ts b/src/services/chirpstack/chirpstack-device.service.ts index cb1e50c7..15f3da2c 100644 --- a/src/services/chirpstack/chirpstack-device.service.ts +++ b/src/services/chirpstack/chirpstack-device.service.ts @@ -1,26 +1,21 @@ -import { BadRequestException, Injectable, Logger } from "@nestjs/common"; +import { BadRequestException, Injectable, Logger, NotFoundException } from "@nestjs/common"; import { AxiosResponse } from "axios"; import { ChirpstackDeviceActivationContentsDto } from "@dto/chirpstack/chirpstack-device-activation-response.dto"; -import { ChirpstackDeviceActivationDto } from "@dto/chirpstack/chirpstack-device-activation-response.dto"; import { ChirpstackDeviceContentsDto } from "@dto/chirpstack/chirpstack-device-contents.dto"; -import { - ChirpstackDeviceKeysContentDto, - ChirpstackDeviceKeysResponseDto, -} from "@dto/chirpstack/chirpstack-device-keys-response.dto"; +import { ChirpstackDeviceKeysContentDto } from "@dto/chirpstack/chirpstack-device-keys-response.dto"; import { ChirpstackSingleApplicationResponseDto } from "@dto/chirpstack/chirpstack-single-application-response.dto"; -import { ChirpstackSingleDeviceResponseDto } from "@dto/chirpstack/chirpstack-single-device-response.dto"; import { CreateChirpstackApplicationDto } from "@dto/chirpstack/create-chirpstack-application.dto"; import { CreateChirpstackDeviceDto } from "@dto/chirpstack/create-chirpstack-device.dto"; import { ListAllChirpstackApplicationsResponseDto } from "@dto/chirpstack/list-all-applications-response.dto"; import { ListAllDevicesResponseDto } from "@dto/chirpstack/list-all-devices-response.dto"; import { CreateLoRaWANSettingsDto } from "@dto/create-lorawan-settings.dto"; import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; +import { CreateChirpstackDeviceQueueItemDto } from "@dto/chirpstack/create-chirpstack-device-queue-item.dto"; import { - CreateChirpstackDeviceQueueItemDto, - CreateChirpstackDeviceQueueItemResponse, -} from "@dto/chirpstack/create-chirpstack-device-queue-item.dto"; -import { DeviceDownlinkQueueResponseDto } from "@dto/chirpstack/chirpstack-device-downlink-queue-response.dto"; + DeviceDownlinkQueueResponseDto, + DeviceQueueItem, +} from "@dto/chirpstack/chirpstack-device-downlink-queue-response.dto"; import { ErrorCodes } from "@enum/error-codes.enum"; import { ChirpstackManyDeviceResponseDto } from "@dto/chirpstack/chirpstack-many-device-response"; import { IoTDevice } from "@entities/iot-device.entity"; @@ -29,19 +24,71 @@ import { ActivationType } from "@enum/lorawan-activation-type.enum"; import { ChirpstackDeviceId } from "@dto/chirpstack/chirpstack-device-id.dto"; import { ChirpstackApplicationResponseDto } from "@dto/chirpstack/chirpstack-application-response.dto"; import { groupBy } from "lodash"; -import { LoRaWANStatsResponseDto } from "@dto/chirpstack/device/lorawan-stats.response.dto"; +import { + LoRaWANStatsElementDto, + LoRaWANStatsResponseDto, +} from "@dto/chirpstack/device/lorawan-stats.response.dto"; import { ConfigService } from "@nestjs/config"; -import { HttpService } from "@nestjs/axios"; +import { DeviceServiceClient } from "@chirpstack/chirpstack-api/api/device_grpc_pb"; +import { ServiceError, credentials } from "@grpc/grpc-js"; +import { + Application, + CreateApplicationRequest, + GetApplicationRequest, + GetApplicationResponse, + ListApplicationsRequest, +} from "@chirpstack/chirpstack-api/api/application_pb"; +import { + ActivateDeviceRequest, + CreateDeviceKeysRequest, + CreateDeviceRequest, + DeleteDeviceRequest, + Device, + DeviceActivation, + DeviceKeys, + DeviceQueueItem as DeviceQueueItemChirpstack, + EnqueueDeviceQueueItemRequest, + FlushDeviceQueueRequest, + GetDeviceActivationRequest, + GetDeviceActivationResponse, + GetDeviceKeysRequest, + GetDeviceKeysResponse, + GetDeviceLinkMetricsRequest, + GetDeviceLinkMetricsResponse, + GetDeviceQueueItemsRequest, + GetDeviceQueueItemsResponse, + GetDeviceRequest, + GetDeviceResponse, + ListDevicesRequest, + UpdateDeviceKeysRequest, + UpdateDeviceRequest, +} from "@chirpstack/chirpstack-api/api/device_pb"; +import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { dateToTimestamp } from "@helpers/date.helper"; +import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; +import { Aggregation } from "@chirpstack/chirpstack-api/common/common_pb"; +import { DeviceMetricsDto, MetricProperties } from "@dto/chirpstack/chirpstack-device-metrics.dto"; +import { LoRaWANDevice } from "@entities/lorawan-device.entity"; +import { InjectRepository } from "@nestjs/typeorm"; +import { Repository } from "typeorm"; +import { Application as DbApplication } from "@entities/application.entity"; @Injectable() export class ChirpstackDeviceService extends GenericChirpstackConfigurationService { - constructor(internalHttpService: HttpService, private configService: ConfigService) { - super(internalHttpService); + @InjectRepository(DbApplication) + private applicationRepository: Repository; + + constructor(private configService: ConfigService) { + super(); this.deviceStatsIntervalInDays = configService.get( "backend.deviceStatsIntervalInDays" ); } + private deviceServiceClient = new DeviceServiceClient( + this.baseUrlGRPC, + credentials.createInsecure() + ); private readonly logger = new Logger(ChirpstackDeviceService.name); @@ -52,50 +99,60 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi private readonly deviceStatsIntervalInDays: number; async findOrCreateDefaultApplication( - dto: CreateChirpstackDeviceDto, - applications: ListAllChirpstackApplicationsResponseDto = null - ): Promise { + applications: ListAllChirpstackApplicationsResponseDto = null, + iotDevice: LoRaWANDevice + ): Promise { const organizationID = await this.getDefaultOrganizationId(); + const req = new ListApplicationsRequest(); + req.setTenantId(organizationID); // Fetch applications applications = applications ?? (await this.getAllWithPagination( - `applications?limit=100&organizationID=${organizationID}` + `applications?limit=100&organizationID=${organizationID}`, + 100, + undefined, + this.applicationServiceClient )); - // if default exist use it + + // if application exist use it let applicationId = applications.result.find( element => - element.serviceProfileID.toLowerCase() === - dto.device.serviceProfileID.toLowerCase() && - element.name.startsWith(this.defaultApplicationName) + element.id === iotDevice.chirpstackApplicationId || + element.id === iotDevice.application.chirpstackId )?.id; - // otherwise create default + + // otherwise create new application if (!applicationId) { - applicationId = await this.createDefaultApplication( + applicationId = await this.createNewApplication( applicationId, - dto, - organizationID + organizationID, + iotDevice.application.name, + iotDevice.application.id ); } - return +applicationId; + return applicationId; } - private async createDefaultApplication( + private async createNewApplication( applicationId: string, - dto: CreateChirpstackDeviceDto, - organizationID: string + organizationID: string, + name: string, + id: number ) { applicationId = await this.createApplication({ application: { - name: `${ - this.defaultApplicationName - }-${dto.device.serviceProfileID.toLowerCase()}`.substring(0, 50), + name: `${this.defaultApplicationName}-${name}`, description: this.DEFAULT_DESCRIPTION, - organizationID: organizationID, - serviceProfileID: dto.device.serviceProfileID, + tenantId: organizationID, }, }); + const existingApplication = await this.applicationRepository.findOneOrFail({ + where: { id: id }, + }); + existingApplication.chirpstackId = applicationId; + await this.applicationRepository.save(existingApplication) return applicationId; } @@ -108,7 +165,6 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi csDto.description = this.DEFAULT_DESCRIPTION; csDto.devEUI = dto.devEUI; csDto.deviceProfileID = dto.deviceProfileID; - csDto.serviceProfileID = dto.serviceProfileID; csDto.isDisabled = dto.isDisabled; csDto.skipFCntCheck = dto.skipFCntCheck; @@ -116,46 +172,67 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi return { device: csDto }; } - async overwriteDownlink( - dto: CreateChirpstackDeviceQueueItemDto - ): Promise { + async overwriteDownlink(dto: CreateChirpstackDeviceQueueItemDto): Promise { await this.deleteDownlinkQueue(dto.deviceQueueItem.devEUI); try { - const res = await this.post( - `devices/${dto.deviceQueueItem.devEUI}/queue`, - dto - ); - return res.data; + const req = new EnqueueDeviceQueueItemRequest(); + const queueItem = new DeviceQueueItemChirpstack(); + queueItem.setConfirmed(dto.deviceQueueItem.confirmed); + queueItem.setData(dto.deviceQueueItem.data); + queueItem.setDevEui(dto.deviceQueueItem.devEUI); + queueItem.setFPort(dto.deviceQueueItem.fPort); + req.setQueueItem(queueItem); + + const res = await this.postDownlink(this.deviceServiceClient, req); + return res; } catch (err) { const fcntError = "enqueue downlink payload error: get next downlink fcnt for deveui error"; if (err?.response?.data?.error?.startsWith(fcntError)) { - throw new BadRequestException( - ErrorCodes.DeviceIsNotActivatedInChirpstack - ); + throw new BadRequestException(ErrorCodes.DeviceIsNotActivatedInChirpstack); } throw err; } } - async deleteDevice(deviceEUI: string): Promise { + async deleteDevice(deviceEUI: string): Promise { try { - return await this.delete(`devices/`, deviceEUI); + const req = new DeleteDeviceRequest(); + req.setDevEui(deviceEUI); + await this.delete(`devices`, this.deviceServiceClient, req); } catch (err) { throw err; } } async getDownlinkQueue(deviceEUI: string): Promise { - const res = await this.get( - `devices/${deviceEUI}/queue` - ); - return res; + const req = new GetDeviceQueueItemsRequest(); + req.setDevEui(deviceEUI); + const res = await this.getQueue(this.deviceServiceClient, req); + + const queueDto: DeviceQueueItem[] = []; + res.getResultList().forEach(queueItem => { + queueDto.push({ + confirmed: queueItem.getConfirmed(), + devEUI: queueItem.getDevEui(), + fCnt: queueItem.getFCntDown(), + fPort: queueItem.getFPort(), + data: queueItem.getData_asB64(), + }); + }); + + const responseDto: DeviceDownlinkQueueResponseDto = { + totalCount: res.getTotalCount(), + deviceQueueItems: queueDto, + }; + return responseDto; } async deleteDownlinkQueue(deviceEUI: string): Promise { - await this.delete(`devices/${deviceEUI}/queue`); + const req = new FlushDeviceQueueRequest(); + req.setDevEui(deviceEUI); + await this.deleteQueue(this.deviceServiceClient, req); } async activateDeviceWithABP( @@ -164,33 +241,34 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi fCntUp: number, nFCntDown: number, networkSessionKey: string, - applicationSessionKey: string, - isUpdate: boolean + applicationSessionKey: string ): Promise { - const { res, dto } = await this.createOrUpdateABPActivation( + const res = await this.createOrUpdateABPActivation( devAddr, networkSessionKey, applicationSessionKey, fCntUp, nFCntDown, - devEUI, - isUpdate + devEUI ); - if (res.status != 200) { - this.logger.warn( - `Could not ABP activate Chirpstack Device using body: ${JSON.stringify( - dto - )}` - ); + if (!res) { + this.logger.warn(`Could not ABP activate Chirpstack Device using DEVEUI: ${devEUI}}`); return false; } - return res.status == 200; + return true; } async getAllDevicesStatus(): Promise { - return await this.get( - `devices?limit=10000&offset=0` + const req = new ListDevicesRequest(); + req.setLimit(10000); + req.setOffset(0); + const test = await this.get( + `devices`, + this.deviceServiceClient, + req ); + + return test; } private async createOrUpdateABPActivation( @@ -199,28 +277,44 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi applicationSessionKey: string, fCntUp: number, nFCntDown: number, - devEUI: string, - isUpdate: boolean + devEUI: string ) { - const dto = { - deviceActivation: { - devAddr: devAddr, - nwkSEncKey: networkSessionKey, - appSKey: applicationSessionKey, - fCntUp: fCntUp, - nFCntDown: nFCntDown, - devEUI: devEUI, - fNwkSIntKey: networkSessionKey, - sNwkSIntKey: networkSessionKey, - }, - }; - let res; - if (isUpdate) { - res = await this.put(`devices`, dto, `${devEUI}/activate`); - } else { - res = await this.post(`devices/${devEUI}/activate`, dto); + const req = new ActivateDeviceRequest(); + const deviceActivation = this.mapActivationToChirpstack( + devAddr, + networkSessionKey, + applicationSessionKey, + fCntUp, + nFCntDown, + devEUI + ); + req.setDeviceActivation(deviceActivation); + try { + await this.postActivation(this.deviceServiceClient, req); + } catch (e) { + return false; } - return { res, dto }; + + return true; + } + mapActivationToChirpstack( + devAddr: string, + networkSessionKey: string, + applicationSessionKey: string, + fCntUp: number, + nFCntDown: number, + devEUI: string + ) { + const deviceActivation = new DeviceActivation(); + deviceActivation.setDevAddr(devAddr); + deviceActivation.setNwkSEncKey(networkSessionKey); + deviceActivation.setAppSKey(applicationSessionKey); + deviceActivation.setFCntUp(fCntUp); + deviceActivation.setNFCntDown(nFCntDown); + deviceActivation.setDevEui(devEUI); + deviceActivation.setFNwkSIntKey(networkSessionKey); + deviceActivation.setSNwkSIntKey(networkSessionKey); + return deviceActivation; } async activateDeviceWithOTAA( @@ -228,87 +322,163 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi nwkKey: string, isUpdate: boolean ): Promise { - // http://localhost:8080/api/devices/0011223344557188/keys - // {"deviceKeys":{"nwkKey":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","devEUI":"0011223344557188"}} + try { + if (isUpdate) { + const req = new UpdateDeviceKeysRequest(); + const deviceKeys = this.mapDeviceKeysToChirpstack(deviceEUI, nwkKey); + req.setDeviceKeys(deviceKeys); + await this.putKeys(this.deviceServiceClient, req); + } else { + const req = new CreateDeviceKeysRequest(); + const deviceKeys = this.mapDeviceKeysToChirpstack(deviceEUI, nwkKey); + req.setDeviceKeys(deviceKeys); - const dto = { - deviceKeys: { - nwkKey: nwkKey, - devEUI: deviceEUI, - }, - }; - let res; - if (isUpdate) { - res = await this.put(`devices`, dto, `${deviceEUI}/keys`); - } else { - res = await this.post(`devices/${deviceEUI}/keys`, dto); - } - if (res.status != 200) { - this.logger.warn( - `Could not activate Chirpstack Device using body: ${JSON.stringify(dto)}` - ); + await this.postKeys(this.deviceServiceClient, req); + } + } catch (e) { return false; } - return res.status == 200; + + return true; + } + + mapDeviceKeysToChirpstack(deviceEUI: string, nwkKey: string) { + const deviceKeys = new DeviceKeys(); + deviceKeys.setDevEui(deviceEUI); + deviceKeys.setNwkKey(nwkKey); + return deviceKeys; } async createOrUpdateDevice( dto: CreateChirpstackDeviceDto, lorawanDevices: ChirpstackDeviceId[] = null ): Promise { - let res: AxiosResponse; - if (await this.isDeviceAlreadyCreated(dto.device.devEUI, lorawanDevices)) { - res = await this.put(`devices`, dto, dto.device.devEUI); - } else { - res = await this.post(`devices`, dto); + try { + if (await this.isDeviceAlreadyCreated(dto.device.devEUI, lorawanDevices)) { + const req = new UpdateDeviceRequest(); + const device = this.mapDeviceToChirpstack(dto); + req.setDevice(device); + await this.put(`devices`, this.deviceServiceClient, req); + } else { + const req = new CreateDeviceRequest(); + const device = this.mapDeviceToChirpstack(dto); + req.setDevice(device); + await this.post(`devices`, this.deviceServiceClient, req); + } + } catch (e) { + return false; } + return true; + } - if (res.status !== 200) { - this.logger.warn( - `Could not create Chirpstack Device using body: ${JSON.stringify(dto)}` + mapDeviceToChirpstack(dto: CreateChirpstackDeviceDto): Device { + const device = new Device(); + device.setApplicationId(dto.device.applicationID); + device.setDescription(dto.device.description); + device.setDevEui(dto.device.devEUI); + device.setDeviceProfileId(dto.device.deviceProfileID); + device.setIsDisabled(dto.device.isDisabled); + device.setName(dto.device.name); + device.setSkipFcntCheck(dto.device.skipFCntCheck); + return device; + } + async getChirpstackApplication(id: string): Promise { + const req = new GetApplicationRequest(); + req.setId(id); + try { + const csApplication = await this.get( + `applications/${id}`, + this.applicationServiceClient, + req ); - return false; - } + const applicationDto = new ChirpstackApplicationResponseDto(); - return true; - } + applicationDto.name = csApplication.getApplication().getName(); + applicationDto.description = csApplication.getApplication().getDescription(); + applicationDto.id = csApplication.getApplication().getId(); + applicationDto.tenantId = csApplication.getApplication().getTenantId(); - async getChirpstackApplication( - id: string - ): Promise { - return await this.get( - `applications/${id}` - ); + const returnDto = new ChirpstackSingleApplicationResponseDto(); + returnDto.application = applicationDto; + + return returnDto; + } catch (err) { + throw new BadRequestException(ErrorCodes.CouldntGetApplications); + } } async getChirpstackDevice(id: string): Promise { - const res = await this.get(`devices/${id}`); - res.device.deviceStatusBattery = res.deviceStatusBattery; - res.device.deviceStatusMargin = res.deviceStatusMargin; - return res.device; + try { + const req = new GetDeviceRequest(); + req.setDevEui(id); + + const res = await this.get( + `devices/${id}`, + this.deviceServiceClient, + req + ); + + const deviceDto: ChirpstackDeviceContentsDto = { + deviceStatusBattery: res.getDeviceStatus()?.getBatteryLevel(), + deviceStatusMargin: res.getDeviceStatus()?.getMargin(), + devEUI: res.getDevice().getDevEui(), + deviceProfileID: res.getDevice().getDeviceProfileId(), + applicationID: res.getDevice().getApplicationId(), + description: res.getDevice().getDescription(), + isDisabled: res.getDevice().getIsDisabled(), + name: res.getDevice().getName(), + skipFCntCheck: res.getDevice().getSkipFcntCheck(), + tags: res.getDevice().getTagsMap().toObject(), + variables: res.getDevice().getVariablesMap().toObject(), + }; + + return deviceDto; + } catch (err) { + throw new BadRequestException(ErrorCodes.CouldntGetApplications); + } } - async getKeys(deviceId: string): Promise { + async getDeviceKeys(deviceId: string): Promise { try { - const res = await this.get( - `devices/${deviceId}/keys` - ); - return res.deviceKeys; + const req = new GetDeviceKeysRequest(); + req.setDevEui(deviceId); + + const res = await this.getKeys(this.deviceServiceClient, req); + + const keysDto: ChirpstackDeviceKeysContentDto = { + appKey: res.getDeviceKeys().getAppKey(), + devEUI: res.getDeviceKeys().getDevEui(), + nwkKey: res.getDeviceKeys().getNwkKey(), + }; + + return keysDto; } catch (err) { // Chirpstack returns 404 if keys are not saved .. + // It seems like that the current logic is using this catch to see if the device is an ABP or OTAA device. return new ChirpstackDeviceKeysContentDto(); } } - async getActivation( - deviceId: string - ): Promise { + async getDeviceActivation(deviceId: string): Promise { try { - const res = await this.get( - `devices/${deviceId}/activation` - ); - return res.deviceActivation; + const req = new GetDeviceActivationRequest(); + req.setDevEui(deviceId); + + const res = await this.getActivation(this.deviceServiceClient, req); + + const activationDto: ChirpstackDeviceActivationContentsDto = { + aFCntDown: res.getDeviceActivation().getAFCntDown(), + devEUI: res.getDeviceActivation().getDevEui(), + appSKey: res.getDeviceActivation().getAppSKey(), + devAddr: res.getDeviceActivation().getDevAddr(), + fCntUp: res.getDeviceActivation().getFCntUp(), + fNwkSIntKey: res.getDeviceActivation().getFNwkSIntKey(), + nFCntDown: res.getDeviceActivation().getAFCntDown(), + nwkSEncKey: res.getDeviceActivation().getNwkSEncKey(), + sNwkSIntKey: res.getDeviceActivation().getSNwkSIntKey(), + }; + return activationDto; } catch (err) { return new ChirpstackDeviceActivationContentsDto(); } @@ -320,46 +490,29 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi * @param applications * @returns The mutated device */ - async enrichLoRaWANDevice( - iotDevice: IoTDevice, - applications: ChirpstackApplicationResponseDto[] = [] - ): Promise { + async enrichLoRaWANDevice(iotDevice: IoTDevice): Promise { const loraDevice = iotDevice as LoRaWANDeviceWithChirpstackDataDto; loraDevice.lorawanSettings = new CreateLoRaWANSettingsDto(); await this.mapActivationAndKeys(loraDevice); const csData = await this.getChirpstackDevice(loraDevice.deviceEUI); loraDevice.lorawanSettings.devEUI = csData.devEUI; loraDevice.lorawanSettings.deviceProfileID = csData.deviceProfileID; - loraDevice.lorawanSettings.serviceProfileID = csData.serviceProfileID; loraDevice.lorawanSettings.skipFCntCheck = csData.skipFCntCheck; loraDevice.lorawanSettings.isDisabled = csData.isDisabled; loraDevice.lorawanSettings.deviceStatusBattery = csData.deviceStatusBattery; loraDevice.lorawanSettings.deviceStatusMargin = csData.deviceStatusMargin; - const appMatch = applications.find(app => app.id === csData.applicationID); - loraDevice.lorawanSettings.serviceProfileID = appMatch - ? appMatch.serviceProfileID - : loraDevice.lorawanSettings.serviceProfileID; - - if (!loraDevice.lorawanSettings.serviceProfileID) { - const csAppliation = await this.getChirpstackApplication( - csData.applicationID - ); - loraDevice.lorawanSettings.serviceProfileID = - csAppliation.application.serviceProfileID; - } - return loraDevice; } private async mapActivationAndKeys(loraDevice: LoRaWANDeviceWithChirpstackDataDto) { - const keys = await this.getKeys(loraDevice.deviceEUI); + const keys = await this.getDeviceKeys(loraDevice.deviceEUI); if (keys.nwkKey) { // OTAA loraDevice.lorawanSettings.activationType = ActivationType.OTAA; loraDevice.lorawanSettings.OTAAapplicationKey = keys.nwkKey; } else { - const activation = await this.getActivation(loraDevice.deviceEUI); + const activation = await this.getDeviceActivation(loraDevice.deviceEUI); if (activation.devAddr != null) { // ABP loraDevice.lorawanSettings.activationType = ActivationType.ABP; @@ -378,26 +531,109 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi deviceEUI: string, chirpstackIds: ChirpstackDeviceId[] = null ): Promise { - const devices = !chirpstackIds - ? await this.getAllChirpstackDevices() - : chirpstackIds; - const alreadyExists = devices.some( - x => x.devEUI.toLowerCase() === deviceEUI.toLowerCase() - ); + const devices = !chirpstackIds ? await this.getAllChirpstackDevices() : chirpstackIds; + const alreadyExists = devices.some(x => x.devEUI.toLowerCase() === deviceEUI.toLowerCase()); return alreadyExists; } - getStats(deviceEUI: string): Promise { + async getStats(deviceEUI: string): Promise { const now = new Date(); - const to_time = now.toISOString(); + const to_time = dateToTimestamp(now); const from_time = new Date( new Date().setDate(now.getDate() - this.deviceStatsIntervalInDays) - ).toISOString(); - - return this.get( - `devices/${deviceEUI}/stats?interval=DAY&startTimestamp=${from_time}&endTimestamp=${to_time}` ); + const from_time_timestamp: Timestamp = dateToTimestamp(from_time); + + const req = new GetDeviceLinkMetricsRequest(); + req.setDevEui(deviceEUI); + req.setStart(from_time_timestamp); + req.setEnd(to_time); + req.setAggregation(Aggregation.DAY); + const metaData = await this.makeMetadataHeader(); + + const getDeviceMetricsPromise = new Promise( + (resolve, reject) => { + this.deviceServiceClient.getLinkMetrics(req, metaData, (err, resp) => { + if (err) { + reject(err); + } else { + resolve(resp); + } + }); + } + ); + try { + const metrics = await getDeviceMetricsPromise; + return this.mapMetrics(metrics); + } catch (err) { + throw new BadRequestException(err); + } + } + private mapMetrics(metrics: GetDeviceLinkMetricsResponse): LoRaWANStatsResponseDto { + const statsElementDto: LoRaWANStatsElementDto[] = []; + const packetCounts: DeviceMetricsDto = {}; + + const rssiTimestamp = metrics.getGwRssi().getTimestampsList(); + const rssis = metrics + .getGwRssi() + .getDatasetsList() + .find(e => e.getLabel() === "rssi") + .getDataList(); + + this.processPackets(rssiTimestamp, rssis, MetricProperties.rssi, packetCounts); + + const snrTimestamp = metrics.getGwSnr().getTimestampsList(); + const snr = metrics + .getGwSnr() + .getDatasetsList() + .find(e => e.getLabel() === "snr") + .getDataList(); + + this.processPackets(snrTimestamp, snr, MetricProperties.snr, packetCounts); + + const drTimestamp = metrics.getRxPacketsPerDr().getTimestampsList(); + const drDatasets = metrics.getRxPacketsPerDr().getDatasetsList(); + + drDatasets.forEach(drDataset => { + const drLabel = drDataset.getLabel(); + const drData = drDataset.getDataList(); + this.processPackets(drTimestamp, drData, MetricProperties.dr, packetCounts, drLabel); + }); + + Object.keys(packetCounts).forEach(timestamp => { + const packetCount = packetCounts[timestamp]; + const dto: LoRaWANStatsElementDto = { + timestamp, + gwRssi: packetCount.rssi, + gwSnr: packetCount.snr, + rxPacketsPerDr: packetCount.rxPacketsPerDr, + }; + statsElementDto.push(dto); + }); + return { result: statsElementDto }; } + private processPackets = ( + timestamps: Array, + packets: number[], + key: string, + packetCounts: DeviceMetricsDto, + drLabel?: string + ) => { + timestamps.forEach((timestamp, index) => { + const isoTimestamp = timestamp.toDate().toISOString(); + packetCounts[isoTimestamp] = packetCounts[isoTimestamp] || { + rssi: 0, + snr: 0, + rxPacketsPerDr: {}, + }; + + if (drLabel) { + packetCounts[isoTimestamp].rxPacketsPerDr[drLabel as any] = packets[index]; + } else { + (packetCounts[isoTimestamp] as any)[key] = packets[index]; + } + }); + }; /** * Fetch LoRaWAN applications by the device application id. This **assumes** that @@ -408,10 +644,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi public async getLoRaWANApplications( devices: LoRaWANDeviceWithChirpstackDataDto[] ): Promise { - const loraDevicesByAppId = groupBy( - devices, - device => device.chirpstackApplicationId - ); + const loraDevicesByAppId = groupBy(devices, device => device.chirpstackApplicationId); const res: ChirpstackSingleApplicationResponseDto[] = []; @@ -423,16 +656,195 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi return res; } - private async getAllChirpstackDevices( - limit = 1000 - ): Promise { - return (await this.get(`devices?limit=${limit}`)) - .result; + private async getAllChirpstackDevices(limit = 1000): Promise { + return (await this.get(`devices?limit=${limit}`)).result; } - private async createApplication( - dto: CreateChirpstackApplicationDto - ): Promise { - return (await this.post("applications", dto)).data.id; + private async createApplication(dto: CreateChirpstackApplicationDto): Promise { + const req = new CreateApplicationRequest(); + const application = new Application(); + application.setDescription(dto.application.description); + application.setName(dto.application.name); + application.setTenantId(dto.application.tenantId); + + req.setApplication(application); + const applicationIdObject: PostReturnInterface = await this.post( + "applications", + this.applicationServiceClient, + req + ); + return applicationIdObject.id; + } + + async getKeys( + client: DeviceServiceClient, + request: GetDeviceKeysRequest + ): Promise { + const metaData = await this.makeMetadataHeader(); + const getPromise = new Promise((resolve, reject) => { + client.getKeys(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`get from Keys success`); + resolve(resp); + } + }); + }); + try { + return await getPromise; + } catch (err) { + throw new NotFoundException(); + } + } + async postKeys(client: DeviceServiceClient, request: CreateDeviceKeysRequest): Promise { + const metaData = await this.makeMetadataHeader(); + const createPromise = new Promise((resolve, reject) => { + client.createKeys(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`post KEYS success`); + resolve(resp); + } + }); + }); + try { + return await createPromise; + } catch (err) { + this.logger.error(`POST KEYS got error: ${err}`); + throw new BadRequestException(); + } + } + async putKeys(client: DeviceServiceClient, request: UpdateDeviceKeysRequest): Promise { + const metaData = await this.makeMetadataHeader(); + const updatePromise = new Promise((resolve, reject) => { + client.updateKeys(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`update KEYS success`); + resolve(resp); + } + }); + }); + try { + return await updatePromise; + } catch (err) { + this.logger.error(`UPDATE KEYS got error: ${err}`); + throw new BadRequestException(); + } + } + + async getQueue( + client: DeviceServiceClient, + request: GetDeviceQueueItemsRequest + ): Promise { + const metaData = await this.makeMetadataHeader(); + const getPromise = new Promise((resolve, reject) => { + client.getQueue(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`get from Queue success`); + resolve(resp); + } + }); + }); + try { + return await getPromise; + } catch (err) { + throw new NotFoundException(); + } + } + async deleteQueue( + client: DeviceServiceClient, + request: FlushDeviceQueueRequest + ): Promise { + const metaData = await this.makeMetadataHeader(); + const getPromise = new Promise((resolve, reject) => { + client.flushQueue(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`Delete queue success`); + resolve(resp); + } + }); + }); + try { + return await getPromise; + } catch (err) { + this.logger.error(`DELETE queue got error: ${err}`); + throw new BadRequestException(); + } + } + + async postDownlink( + client: DeviceServiceClient, + request: EnqueueDeviceQueueItemRequest + ): Promise { + const metaData = await this.makeMetadataHeader(); + const createPromise = new Promise((resolve, reject) => { + client.enqueue(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`post downlink success`); + resolve(resp.toObject()); + } + }); + }); + try { + return await createPromise; + } catch (err) { + this.logger.error(`POST downlink got error: ${err}`); + throw new BadRequestException(); + } + } + + async getActivation( + client: DeviceServiceClient, + request: GetDeviceActivationRequest + ): Promise { + const metaData = await this.makeMetadataHeader(); + const getPromise = new Promise((resolve, reject) => { + client.getActivation(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`get from Activation success`); + resolve(resp); + } + }); + }); + try { + return await getPromise; + } catch (err) { + this.logger.error(`GET Activation got error: ${err}`); + throw new NotFoundException(); + } + } + async postActivation( + client?: DeviceServiceClient, + request?: ActivateDeviceRequest + ): Promise { + const metaData = await this.makeMetadataHeader(); + const createPromise = new Promise((resolve, reject) => { + client.activate(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`post ACTIVATION success`); + resolve(resp); + } + }); + }); + try { + return await createPromise; + } catch (err) { + this.logger.error(`POST ACTIVATION got error: ${err}`); + throw new BadRequestException(); + } } } diff --git a/src/services/chirpstack/chirpstack-gateway.service.ts b/src/services/chirpstack/chirpstack-gateway.service.ts index 6d4c46d4..02109bed 100644 --- a/src/services/chirpstack/chirpstack-gateway.service.ts +++ b/src/services/chirpstack/chirpstack-gateway.service.ts @@ -10,37 +10,53 @@ import * as BluebirdPromise from "bluebird"; import { ChirpstackErrorResponseDto } from "@dto/chirpstack/chirpstack-error-response.dto"; import { ChirpstackResponseStatus } from "@dto/chirpstack/chirpstack-response.dto"; import { CreateGatewayDto } from "@dto/chirpstack/create-gateway.dto"; -import { GatewayStatsResponseDto } from "@dto/chirpstack/gateway-stats.response.dto"; -import { ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways.dto"; +import { GatewayStatsElementDto } from "@dto/chirpstack/gateway-stats.response.dto"; +import { ListAllGatewaysResponseGrpcDto } from "@dto/chirpstack/list-all-gateways.dto"; import { SingleGatewayResponseDto } from "@dto/chirpstack/single-gateway-response.dto"; -import { - UpdateGatewayContentsDto, - UpdateGatewayDto, -} from "@dto/chirpstack/update-gateway.dto"; +import { UpdateGatewayContentsDto, UpdateGatewayDto } from "@dto/chirpstack/update-gateway.dto"; import { ErrorCodes } from "@enum/error-codes.enum"; import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; -import { ChirpstackSetupNetworkServerService } from "@services/chirpstack/network-server.service"; import { GatewayContentsDto } from "@dto/chirpstack/gateway-contents.dto"; import * as _ from "lodash"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; -import { checkIfUserHasAccessToOrganization, OrganizationAccessScope } from "@helpers/security-helper"; -import { GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto"; -import { HttpService } from "@nestjs/axios"; - +import { + checkIfUserHasAccessToOrganization, + OrganizationAccessScope, +} from "@helpers/security-helper"; +import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; +import { GatewayServiceClient } from "@chirpstack/chirpstack-api/api/gateway_grpc_pb"; +import { + CreateGatewayRequest, + DeleteGatewayRequest, + Gateway, + GetGatewayMetricsRequest, + GetGatewayMetricsResponse, + GetGatewayRequest, + GetGatewayResponse, + ListGatewaysRequest, + ListGatewaysResponse, + UpdateGatewayRequest, +} from "@chirpstack/chirpstack-api/api/gateway_pb"; +import { credentials } from "@grpc/grpc-js"; +import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; +import { Aggregation, Location } from "@chirpstack/chirpstack-api/common/common_pb"; +import { dateToTimestamp } from "@helpers/date.helper"; @Injectable() export class ChirpstackGatewayService extends GenericChirpstackConfigurationService { - constructor( - internalHttpService: HttpService, - private chirpstackSetupNetworkServerService: ChirpstackSetupNetworkServerService - ) { - super(internalHttpService); + constructor() { + super(); } GATEWAY_STATS_INTERVAL_IN_DAYS = 29; - private readonly logger = new Logger(ChirpstackGatewayService.name, { timestamp: true }); + private readonly logger = new Logger(ChirpstackGatewayService.name, { + timestamp: true, + }); private readonly ORG_ID_KEY = "internalOrganizationId"; private readonly UPDATED_BY_KEY = "os2iot-updated-by"; private readonly CREATED_BY_KEY = "os2iot-created-by"; - + private gatewayClient = new GatewayServiceClient( + this.baseUrlGRPC, + credentials.createInsecure() + ); async createNewGateway( dto: CreateGatewayDto, userId: number @@ -50,50 +66,96 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ dto.gateway.tags = this.addOrganizationToTags(dto); dto.gateway.tags = this.addUserToTags(dto, userId); - const result = await this.post("gateways", dto); - return this.handlePossibleError(result, dto); + const req = new CreateGatewayRequest(); + const location = new Location(); + this.mapToLocationChirpstack(location, dto); + + const gateway = new Gateway(); + await this.mapToGatewayChirpstack(gateway, dto, location); + Object.entries(dto.gateway.tags).forEach(([key, value]) => { + gateway.getTagsMap().set(key, value); + }); + req.setGateway(gateway); + try { + await this.post("gateways", this.gatewayClient, req); + return { success: true }; + } catch (e) { + this.logger.error( + `Error from Chirpstack: '${JSON.stringify(dto)}', got response: ${JSON.stringify( + e + )}` + ); + throw new BadRequestException({ + success: false, + error: e, + }); + } } - addUserToTags( - dto: CreateGatewayDto, - userId: number - ): { [id: string]: string | number } { + async mapToGatewayChirpstack( + gateway: Gateway, + dto: CreateGatewayDto | UpdateGatewayDto, + location: Location, + gatewayId?: string + ) { + gateway.setGatewayId(gatewayId ? gatewayId : dto.gateway.gatewayId); + gateway.setDescription(dto.gateway.description); + gateway.setName(dto.gateway.name); + gateway.setLocation(location); + gateway.setStatsInterval(30); + gateway.setTenantId( + dto.gateway.tenantId ? dto.gateway.tenantId : await this.getDefaultOrganizationId() + ); + } + mapToLocationChirpstack(location: Location, dto: CreateGatewayDto | UpdateGatewayDto) { + location.setAccuracy(dto.gateway.location.accuracy); + location.setAltitude(dto.gateway.location.altitude); + location.setLatitude(dto.gateway.location.latitude); + location.setLongitude(dto.gateway.location.longitude); + location.setSource(dto.gateway.location.source); + } + + addUserToTags(dto: CreateGatewayDto, userId: number): { [id: string]: string } { const tags = dto.gateway.tags; tags[this.CREATED_BY_KEY] = `${userId}`; tags[this.UPDATED_BY_KEY] = `${userId}`; return tags; } - updateUpdatedByTag( - dto: UpdateGatewayDto, - userId: number - ): { [id: string]: string | number } { + updateTags(dto: UpdateGatewayDto, userId: number): { [id: string]: string } { const tags = dto.gateway.tags; tags[this.UPDATED_BY_KEY] = `${userId}`; + tags[this.CREATED_BY_KEY] = `${dto.gateway.createdBy}`; return tags; } - addOrganizationToTags(dto: CreateGatewayDto): { [id: string]: string | number } { + addOrganizationToTags(dto: CreateGatewayDto): { [id: string]: string } { const tags = dto.gateway.tags; tags[this.ORG_ID_KEY] = `${dto.organizationId}`; return tags; } - async getAll(organizationId?: number): Promise { + async getAll(organizationId?: number): Promise { const limit = 1000; - let allResults: GatewayResponseDto[] = []; + let allResults: GatewayResponseGrpcDto[] = []; let totalCount = 0; - let lastResults: ListAllGatewaysResponseDto; + let lastResults: ListGatewaysResponse.AsObject; + const req = new ListGatewaysRequest(); do { - // Default parameters if not set - lastResults = await this.getAllWithPagination( - "gateways", - limit, - allResults.length - ); - allResults = _.union(allResults, lastResults.result); + try { + lastResults = await this.getAllWithPagination( + "gateways", + limit, + allResults.length, + this.gatewayClient, + req + ); + } catch (err) { + throw err; + } + allResults = _.union(allResults, lastResults.resultList); totalCount = lastResults.totalCount; - } while (totalCount > allResults.length && lastResults.result.length > 0); + } while (totalCount > allResults.length && lastResults.resultList.length > 0); await this.enrichWithOrganizationId(allResults); if (organizationId !== undefined) { @@ -101,33 +163,32 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ return x.internalOrganizationId === +organizationId; }); return { - result: filteredResults, + resultList: filteredResults, totalCount: filteredResults.length, }; } return { - result: allResults, + resultList: allResults, totalCount: totalCount, }; } - /** * Fetch gateways individually. This gives us the tags which contain the OS2 organization id. * This is a very expensive operation, but it's the only way to retrieve gateway tags. * @param results */ - private async enrichWithOrganizationId(results: GatewayResponseDto[]) { + private async enrichWithOrganizationId(results: GatewayResponseGrpcDto[]) { await BluebirdPromise.all( BluebirdPromise.map( results, async x => { try { - const gw = await this.getOne(x.id); + const gw = await this.getOne(x.gatewayId); x.internalOrganizationId = gw.gateway.internalOrganizationId; } catch (err) { this.logger.error( - `Failed to fetch gateway details for id ${x.id}`, + `Failed to fetch gateway details for id ${x.gatewayId}`, err ); x.internalOrganizationId = null; @@ -139,29 +200,57 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ ) ); } + async mapSingleGatewayResponse(result: GetGatewayResponse, gatewayId: string) { + const gatewayReponseObject: SingleGatewayResponseDto = { + createdAt: result.getCreatedAt()?.toDate(), + lastSeenAt: result.getLastSeenAt()?.toObject(), + updatedAt: result.getUpdatedAt()?.toDate(), + stats: await this.getGatewayStats(gatewayId), + gateway: result.getGateway()?.toObject(), + }; + gatewayReponseObject.gateway.internalOrganizationId = +result + .getGateway() + .getTagsMap() + .get(this.ORG_ID_KEY); + gatewayReponseObject.gateway.createdBy = +result + .getGateway() + .getTagsMap() + .get(this.CREATED_BY_KEY); + gatewayReponseObject.gateway.updatedBy = +result + .getGateway() + .getTagsMap() + .get(this.UPDATED_BY_KEY); + //Filter out specific tags. + gatewayReponseObject.gateway.tagsMap = gatewayReponseObject.gateway.tagsMap.filter( + ([key]) => { + return ( + key !== this.ORG_ID_KEY && + key !== this.CREATED_BY_KEY && + key !== this.UPDATED_BY_KEY + ); + } + ); + return gatewayReponseObject; + } async getOne(gatewayId: string): Promise { if (gatewayId?.length != 16) { throw new BadRequestException("Invalid gateway id"); } + const req = new GetGatewayRequest(); + req.setGatewayId(gatewayId); try { - const result: SingleGatewayResponseDto = await this.get( - `gateways/${gatewayId}` + const result = await this.get( + `gateways/${gatewayId}`, + this.gatewayClient, + req ); - result.gateway.internalOrganizationId = +result.gateway.tags[this.ORG_ID_KEY]; - result.gateway.createdBy = +result.gateway.tags[this.CREATED_BY_KEY]; - result.gateway.updatedBy = +result.gateway.tags[this.UPDATED_BY_KEY]; - result.gateway.tags[this.ORG_ID_KEY] = undefined; - result.gateway.tags[this.CREATED_BY_KEY] = undefined; - result.gateway.tags[this.UPDATED_BY_KEY] = undefined; - - result.stats = (await this.getGatewayStats(gatewayId)).result; - - return result; + const gatewayReponseObject = this.mapSingleGatewayResponse(result, gatewayId); + return gatewayReponseObject; } catch (err) { this.logger.error( `Tried to find gateway with id: '${gatewayId}', got an error: ${JSON.stringify( - err + err.message )}` ); if (err?.message == "object does not exist") { @@ -171,16 +260,86 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ } } - private async getGatewayStats(gatewayId: string): Promise { + private async getGatewayStats(gatewayId: string): Promise { const now = new Date(); - const to_time = now.toISOString(); + const to_time = dateToTimestamp(now); const from_time = new Date( new Date().setDate(now.getDate() - this.GATEWAY_STATS_INTERVAL_IN_DAYS) - ).toISOString(); + ); + const from_time_timestamp: Timestamp = dateToTimestamp(from_time); + + const request = new GetGatewayMetricsRequest(); + request.setGatewayId(gatewayId); + request.setStart(from_time_timestamp); + request.setEnd(to_time); + request.setAggregation(Aggregation.DAY); + + const metaData = await this.makeMetadataHeader(); - return await this.get( - `gateways/${gatewayId}/stats?interval=DAY&startTimestamp=${from_time}&endTimestamp=${to_time}` + const getGatewayMetricsPromise = new Promise( + (resolve, reject) => { + this.gatewayClient.getMetrics(request, metaData, (err, resp) => { + if (err) { + reject(err); + } else { + resolve(resp); + } + }); + } ); + try { + const metrics = await getGatewayMetricsPromise; + return this.mapPackets(metrics); + } catch (err) { + throw new BadRequestException(err); + } + } + + private mapPackets(metrics: GetGatewayMetricsResponse) { + const gatewayResponseDto: GatewayStatsElementDto[] = []; + const packetCounts: { [timestamp: string]: { rx: number; tx: number } } = {}; + + const rxTimestamps = metrics.getRxPackets().getTimestampsList(); + const rxPackets = metrics + .getRxPackets() + .getDatasetsList() + .find(e => e.getLabel() === "rx_count") + .getDataList(); + + this.processPackets(rxTimestamps, rxPackets, "rx", packetCounts); + + const txTimestamps = metrics.getTxPackets().getTimestampsList(); + const txPackets = metrics + .getTxPackets() + .getDatasetsList() + .find(e => e.getLabel() === "tx_count") + .getDataList(); + + this.processPackets(txTimestamps, txPackets, "tx", packetCounts); + + Object.keys(packetCounts).forEach(timestamp => { + const packetCount = packetCounts[timestamp]; + const dto: GatewayStatsElementDto = { + timestamp, + rxPacketsReceived: packetCount.rx, + txPacketsEmitted: packetCount.tx, + }; + gatewayResponseDto.push(dto); + }); + return gatewayResponseDto; + } + + private processPackets( + timestamps: Array, + packets: number[], + key: string, + packetCounts: { [timestamp: string]: { rx: number; tx: number } } + ) { + timestamps.forEach((timestamp, index) => { + const isoTimestamp = timestamp.toDate().toISOString(); + packetCounts[isoTimestamp] = packetCounts[isoTimestamp] || { rx: 0, tx: 0 }; + (packetCounts[isoTimestamp] as any)[key] = packets[index]; + }); } async modifyGateway( @@ -190,36 +349,65 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ ): Promise { dto.gateway = await this.updateDtoContents(dto.gateway); dto.gateway.tags = await this.ensureOrganizationIdIsSet(gatewayId, dto, req); - dto.gateway.tags = this.updateUpdatedByTag(dto, +req.user.userId); - const result = await this.put("gateways", dto, gatewayId); - return this.handlePossibleError(result, dto); + dto.gateway.tags = this.updateTags(dto, +req.user.userId); + + const request = new UpdateGatewayRequest(); + const location = new Location(); + this.mapToLocationChirpstack(location, dto); + + const gateway = new Gateway(); + await this.mapToGatewayChirpstack(gateway, dto, location, gatewayId); + + Object.entries(dto.gateway.tags).forEach(([key, value]) => { + gateway.getTagsMap().set(key, value); + }); + + request.setGateway(gateway); + try { + await this.put("gateways", this.gatewayClient, request); + return { success: true }; + } catch (e) { + this.logger.error( + `Error from Chirpstack: '${JSON.stringify(dto)}', got response: ${JSON.stringify( + e + )}` + ); + throw new BadRequestException({ + success: false, + error: e, + }); + } } async ensureOrganizationIdIsSet( gatewayId: string, dto: UpdateGatewayDto, req: AuthenticatedRequest - ): Promise<{ [id: string]: string | number }> { + ): Promise<{ [id: string]: string }> { const existing = await this.getOne(gatewayId); const tags = dto.gateway.tags; tags[this.ORG_ID_KEY] = `${existing.gateway.internalOrganizationId}`; // TODO: Interpolated string will never be null? if (tags[this.ORG_ID_KEY] != null) { - checkIfUserHasAccessToOrganization(req, +tags[this.ORG_ID_KEY], OrganizationAccessScope.GatewayWrite); + checkIfUserHasAccessToOrganization( + req, + +tags[this.ORG_ID_KEY], + OrganizationAccessScope.GatewayWrite + ); } return tags; } async deleteGateway(gatewayId: string): Promise { + const req = new DeleteGatewayRequest(); + req.setGatewayId(gatewayId); try { - await this.delete("gateways", gatewayId); + await this.delete("gateways", this.gatewayClient, req); return { success: true, }; } catch (err) { - this.logger.error( - `Got error from Chirpstack: ${JSON.stringify(err?.response?.data)}` - ); + this.logger.error(`Got error from Chirpstack: ${JSON.stringify(err?.response?.data)}`); return { success: false, chirpstackError: err?.response?.data as ChirpstackErrorResponseDto, @@ -227,25 +415,6 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ } } - private handlePossibleError( - result: AxiosResponse, - dto: CreateGatewayDto | UpdateGatewayDto - ): ChirpstackResponseStatus { - if (result.status != 200) { - this.logger.error( - `Error from Chirpstack: '${JSON.stringify( - dto - )}', got response: ${JSON.stringify(result.data)}` - ); - throw new BadRequestException({ - success: false, - error: result.data, - }); - } - - return { success: true }; - } - private async updateDtoContents( contentsDto: GatewayContentsDto | UpdateGatewayContentsDto ): Promise { @@ -254,19 +423,9 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ contentsDto.gatewayProfileID = null; } - // Add network server - if (!contentsDto?.networkServerID) { - contentsDto.networkServerID = await this.chirpstackSetupNetworkServerService.getDefaultNetworkServerId(); - } - - if (!contentsDto?.organizationID) { - contentsDto.organizationID = await this.chirpstackSetupNetworkServerService.getDefaultOrganizationId(); - } - if (contentsDto?.tagsString) { contentsDto.tags = JSON.parse(contentsDto.tagsString); } - return contentsDto; } } diff --git a/src/services/chirpstack/device-profile.service.ts b/src/services/chirpstack/device-profile.service.ts index fd2565a5..055c5ddd 100644 --- a/src/services/chirpstack/device-profile.service.ts +++ b/src/services/chirpstack/device-profile.service.ts @@ -1,15 +1,41 @@ -import { BadRequestException, Injectable } from "@nestjs/common"; -import { AxiosResponse } from "axios"; - +import { + BadRequestException, + Injectable, + InternalServerErrorException, + NotFoundException, +} from "@nestjs/common"; import { CreateDeviceProfileDto } from "@dto/chirpstack/create-device-profile.dto"; -import { ListAllDeviceProfilesResponseDto } from "@dto/chirpstack/list-all-device-profiles-response.dto"; - +import { + DeviceProfileListDto, + ListAllDeviceProfilesResponseDto, +} from "@dto/chirpstack/list-all-device-profiles-response.dto"; import { GenericChirpstackConfigurationService } from "./generic-chirpstack-configuration.service"; import { UpdateDeviceProfileDto } from "@dto/chirpstack/update-device-profile.dto"; import { DeviceProfileDto } from "@dto/chirpstack/device-profile.dto"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; import { ErrorCodes } from "@enum/error-codes.enum"; -import { checkIfUserHasAccessToOrganization, OrganizationAccessScope } from "@helpers/security-helper"; +import { + checkIfUserHasAccessToOrganization, + OrganizationAccessScope, +} from "@helpers/security-helper"; +import { DeviceProfileServiceClient } from "@chirpstack/chirpstack-api/api/device_profile_grpc_pb"; +import { credentials, ServiceError } from "@grpc/grpc-js"; +import { + CreateDeviceProfileRequest, + DeleteDeviceProfileRequest, + DeviceProfile, + GetDeviceProfileRequest, + GetDeviceProfileResponse, + ListDeviceProfileAdrAlgorithmsResponse, + ListDeviceProfilesRequest, + ListDeviceProfilesResponse, + UpdateDeviceProfileRequest, +} from "@chirpstack/chirpstack-api/api/device_profile_pb"; +import { timestampToDate } from "@helpers/date.helper"; +import { ListAllAdrAlgorithmsResponseDto } from "@dto/chirpstack/list-all-adr-algorithms-response.dto"; +import { Empty } from "google-protobuf/google/protobuf/empty_pb"; +import { AdrAlgorithmDto } from "@dto/chirpstack/adr-algorithm.dto"; +import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; @Injectable() export class DeviceProfileService extends GenericChirpstackConfigurationService { @@ -17,32 +43,42 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService private readonly UPDATED_BY_KEY = "os2iot-updated-by"; private readonly CREATED_BY_KEY = "os2iot-created-by"; + private deviceProfileClient = new DeviceProfileServiceClient( + this.baseUrlGRPC, + credentials.createInsecure() + ); public async createDeviceProfile( dto: CreateDeviceProfileDto, userId: number - ): Promise { + ): Promise { if (await this.isNameInUse(dto.deviceProfile.name)) { throw new BadRequestException(ErrorCodes.NameInvalidOrAlreadyInUse); } dto.deviceProfile = await this.updateDto(dto.deviceProfile); dto.deviceProfile.tags = this.addOrganizationToTags(dto); dto.deviceProfile.tags = this.addUserIdToTags(dto, userId); - const result = await this.post("device-profiles", dto); + + const deviceProfile = new DeviceProfile(); + const req = new CreateDeviceProfileRequest(); + + Object.entries(dto.deviceProfile.tags).forEach(([key, value]) => { + deviceProfile.getTagsMap().set(key, value); + }); + + this.mapToChirpstackDto(deviceProfile, dto, true); + + req.setDeviceProfile(deviceProfile); + const result: PostReturnInterface = await this.post("device-profiles", this.deviceProfileClient, req); return result; } - private addOrganizationToTags( - dto: CreateDeviceProfileDto - ): { [id: string]: string | number } { + private addOrganizationToTags(dto: CreateDeviceProfileDto): { [id: string]: string } { const tags = dto.deviceProfile?.tags != null ? dto.deviceProfile.tags : {}; tags[this.ORG_ID_KEY] = `${dto.internalOrganizationId}`; return tags; } - private addUserIdToTags( - dto: CreateDeviceProfileDto, - userId: number - ): { [id: string]: string | number } { + private addUserIdToTags(dto: CreateDeviceProfileDto, userId: number): { [id: string]: string } { const tags = dto.deviceProfile?.tags != null ? dto.deviceProfile.tags : {}; tags[this.CREATED_BY_KEY] = `${userId}`; tags[this.UPDATED_BY_KEY] = `${userId}`; @@ -53,13 +89,21 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService data: UpdateDeviceProfileDto, id: string, req: AuthenticatedRequest - ): Promise { + ): Promise { if (await this.isNameInUse(data.deviceProfile.name, id)) { throw new BadRequestException(ErrorCodes.NameInvalidOrAlreadyInUse); } + const deviceProfile = new DeviceProfile(); + const request = new UpdateDeviceProfileRequest(); + this.mapToChirpstackDto(deviceProfile, data); + data.deviceProfile.tags = await this.updateTags(id, req); data.deviceProfile = await this.updateDto(data.deviceProfile); - return await this.put("device-profiles", data, id); + Object.entries(data.deviceProfile.tags).forEach(([key, value]) => { + deviceProfile.getTagsMap().set(key, value); + }); + request.setDeviceProfile(deviceProfile); + return await this.put("device-profiles", this.deviceProfileClient, request); } private async isNameInUse(name: string, id?: string): Promise { @@ -72,83 +116,247 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService private async updateTags( deviceProfileId: string, req: AuthenticatedRequest - ): Promise<{ [id: string]: string | number }> { - const result: CreateDeviceProfileDto = await this.getOneById( + ): Promise<{ [id: string]: string }> { + const request = new GetDeviceProfileRequest(); + const result = await this.getOneById( "device-profiles", - deviceProfileId + deviceProfileId, + this.deviceProfileClient, + request ); - const tags = result.deviceProfile.tags; - tags[this.UPDATED_BY_KEY] = `${req.user.userId}`; - if (tags[this.ORG_ID_KEY] != null) { - checkIfUserHasAccessToOrganization(req, +tags[this.ORG_ID_KEY], OrganizationAccessScope.ApplicationWrite); + const tags = result.getDeviceProfile().getTagsMap(); + tags.set(this.UPDATED_BY_KEY, req.user.userId.toString()); + if (result.getDeviceProfile().getTagsMap().get(this.ORG_ID_KEY) != null) { + checkIfUserHasAccessToOrganization( + req, + +result.getDeviceProfile().getTagsMap().get(this.ORG_ID_KEY), + OrganizationAccessScope.ApplicationWrite + ); } - return tags; + const tagsObject: { [id: string]: string } = {}; + tags.forEach((value, key) => { + tagsObject[key] = value; + }); + + return tagsObject; } - public async deleteDeviceProfile( - id: string, - req: AuthenticatedRequest - ): Promise { - const result: CreateDeviceProfileDto = await this.getOneById( + public async deleteDeviceProfile(id: string, req: AuthenticatedRequest): Promise { + const getReq = new GetDeviceProfileRequest(); + const result = await this.getOneById( "device-profiles", - id + id, + this.deviceProfileClient, + getReq ); - if (result.deviceProfile.tags[this.ORG_ID_KEY] != null) { + if (result.getDeviceProfile().getTagsMap().get(this.ORG_ID_KEY) != null) { checkIfUserHasAccessToOrganization( req, - +result.deviceProfile.tags[this.ORG_ID_KEY], + +result.getDeviceProfile().getTagsMap().get(this.ORG_ID_KEY), OrganizationAccessScope.ApplicationWrite ); } - return await this.delete("device-profiles", id); + + const deleteReq = new DeleteDeviceProfileRequest(); + deleteReq.setId(result.getDeviceProfile().getId()); + return await this.delete("device-profiles", this.deviceProfileClient, deleteReq); } public async findAllDeviceProfiles( limit?: number, offset?: number ): Promise { - const result = await this.getAllWithPagination( + const req = new ListDeviceProfilesRequest(); + req.setTenantId(await this.getDefaultOrganizationId()); + + const result = await this.getAllWithPagination( "device-profiles", limit, - offset + offset, + this.deviceProfileClient, + req ); + const deviceResultListDto: DeviceProfileListDto[] = []; + result.resultList.map(e => { + const resultItem: DeviceProfileListDto = { + name: e.name, + createdAt: timestampToDate(e.createdAt), + updatedAt: timestampToDate(e.updatedAt), + id: e.id, + }; + deviceResultListDto.push(resultItem); + }); + const deviceProfileList: ListAllDeviceProfilesResponseDto = { + totalCount: result.totalCount.toString(), + result: deviceResultListDto, + }; await Promise.all( - result.result.map(async x => { + deviceProfileList.result.map(async x => { const dp = await this.findOneDeviceProfileById(x.id); x.internalOrganizationId = +dp.deviceProfile.internalOrganizationId; x.createdBy = +dp.deviceProfile.createdBy; x.updatedBy = +dp.deviceProfile.updatedBy; - x.adrAlgorithmID = x.adrAlgorithmID ? x.adrAlgorithmID : "default"; }) ); - return result; + return deviceProfileList; } public async findOneDeviceProfileById(id: string): Promise { - const result: CreateDeviceProfileDto = await this.getOneById( - "device-profiles", - id - ); - result.deviceProfile.internalOrganizationId = +result.deviceProfile.tags[ - this.ORG_ID_KEY - ]; - result.deviceProfile.createdBy = +result.deviceProfile.tags[this.CREATED_BY_KEY]; - result.deviceProfile.updatedBy = +result.deviceProfile.tags[this.UPDATED_BY_KEY]; - result.deviceProfile.adrAlgorithmID = result.deviceProfile.adrAlgorithmID ? result.deviceProfile.adrAlgorithmID : "default"; - - result.deviceProfile.tags[this.ORG_ID_KEY] = undefined; - result.deviceProfile.tags[this.CREATED_BY_KEY] = undefined; - result.deviceProfile.tags[this.UPDATED_BY_KEY] = undefined; + const req = new GetDeviceProfileRequest(); + req.setId(id); + try { + const result = await this.getOneById( + "device-profiles", + id, + this.deviceProfileClient, + req + ); + const deviceProfileObject = this.mapSingleDeviceProfileResponse(result); - return result; + return deviceProfileObject; + } catch (err) { + throw new InternalServerErrorException("Could not get device profile"); + } } public async updateDto(dto: DeviceProfileDto): Promise { - dto.networkServerID = await this.getDefaultNetworkServerId(); dto.organizationID = await this.getDefaultOrganizationId(); return dto; } + + private mapSingleDeviceProfileResponse( + result: GetDeviceProfileResponse + ): CreateDeviceProfileDto { + const responseObject = result.getDeviceProfile().toObject(); + const deviceProfileMapped = this.mapDeviceInfoContent(responseObject); + const deviceProfileResponseObject: CreateDeviceProfileDto = { + deviceProfile: deviceProfileMapped, + createdAt: result.getCreatedAt().toDate(), + updatedAt: result.getUpdatedAt().toDate(), + internalOrganizationId: +result.getDeviceProfile().getTagsMap().get(this.ORG_ID_KEY), + }; + + deviceProfileResponseObject.deviceProfile.internalOrganizationId = +result + .getDeviceProfile() + .getTagsMap() + .get(this.ORG_ID_KEY); + deviceProfileResponseObject.deviceProfile.createdBy = +result + .getDeviceProfile() + .getTagsMap() + .get(this.CREATED_BY_KEY); + deviceProfileResponseObject.deviceProfile.updatedBy = +result + .getDeviceProfile() + .getTagsMap() + .get(this.UPDATED_BY_KEY); + + deviceProfileResponseObject.deviceProfile.tagsMap = deviceProfileResponseObject.deviceProfile.tagsMap.filter( + ([key]) => { + return ( + key !== this.ORG_ID_KEY && + key !== this.CREATED_BY_KEY && + key !== this.UPDATED_BY_KEY + ); + } + ); + return deviceProfileResponseObject; + } + + private mapDeviceInfoContent(devProfile: DeviceProfile.AsObject) { + const deviceProfileMapped: DeviceProfileDto = { + name: devProfile.name, + id: devProfile.id, + adrAlgorithmID: devProfile.adrAlgorithmId, + macVersion: devProfile.macVersion, + regParamsRevision: devProfile.regParamsRevision, + classBTimeout: devProfile.classBTimeout, + classCTimeout: devProfile.classCTimeout, + pingSlotDR: devProfile.classBPingSlotDr, + pingSlotFreq: devProfile.classBPingSlotFreq, + pingSlotPeriod: devProfile.classBPingSlotNbK, + rfRegion: "EU868", + rxDROffset1: devProfile.abpRx1DrOffset, + rxDataRate2: devProfile.abpRx2Dr, + rxDelay1: devProfile.abpRx1Delay, + rxFreq2: devProfile.abpRx2Freq, + supportsClassB: devProfile.supportsClassB, + supportsClassC: devProfile.supportsClassC, + supportsJoin: devProfile.supportsOtaa, + tagsMap: devProfile.tagsMap, + devStatusReqFreq: devProfile.deviceStatusReqInterval, + }; + return deviceProfileMapped; + } + + mapToChirpstackDto( + deviceProfile: DeviceProfile, + data: CreateDeviceProfileDto | UpdateDeviceProfileDto, + isCreate?: boolean + ) { + deviceProfile.setName(data.deviceProfile.name); + deviceProfile.setMacVersion(data.deviceProfile.macVersion); + deviceProfile.setRegParamsRevision(data.deviceProfile.regParamsRevision); + deviceProfile.setAdrAlgorithmId(data.deviceProfile.adrAlgorithmID); + deviceProfile.setClassBTimeout(data.deviceProfile.classBTimeout); + deviceProfile.setClassCTimeout(data.deviceProfile.classCTimeout); + deviceProfile.setId(data.deviceProfile.id); + deviceProfile.setClassBPingSlotDr(data.deviceProfile.pingSlotDR); + deviceProfile.setClassBPingSlotFreq(data.deviceProfile.pingSlotFreq); + deviceProfile.setClassBPingSlotNbK(data.deviceProfile.pingSlotPeriod); + //region 0 = EU868 + deviceProfile.setRegion(0); + deviceProfile.setAbpRx1DrOffset(data.deviceProfile.rxDROffset1); + deviceProfile.setAbpRx2Dr(data.deviceProfile.rxDataRate2); + deviceProfile.setAbpRx1Delay(data.deviceProfile.rxDelay1); + deviceProfile.setAbpRx2Freq(data.deviceProfile.rxFreq2); + deviceProfile.setSupportsClassB(data.deviceProfile.supportsClassB); + deviceProfile.setSupportsClassC(data.deviceProfile.supportsClassC); + deviceProfile.setSupportsOtaa(data.deviceProfile.supportsJoin); + deviceProfile.setDeviceStatusReqInterval(data.deviceProfile.devStatusReqFreq === undefined ? 1 : data.deviceProfile.devStatusReqFreq); + + isCreate ? deviceProfile.setTenantId(data.deviceProfile.organizationID) : {}; + } + + public async getAdrAlgorithmsForChirpstack(): Promise { + const result = await this.getAdrAlgorithms(); + + const adrAlgoritmList: AdrAlgorithmDto[] = []; + result.getResultList().map(e => { + const resultItem: AdrAlgorithmDto = { + id: e.getId(), + name: e.getName(), + }; + adrAlgoritmList.push(resultItem); + }); + + return { + adrAlgorithms: adrAlgoritmList, + }; + } + + async getAdrAlgorithms(): Promise { + const metaData = await this.makeMetadataHeader(); + const getPromise = new Promise( + (resolve, reject) => { + this.deviceProfileClient.listAdrAlgorithms( + new Empty(), + metaData, + (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + resolve(resp); + } + } + ); + } + ); + try { + return await getPromise; + } catch (err) { + throw new NotFoundException(); + } + } } diff --git a/src/services/chirpstack/generic-chirpstack-configuration.service.ts b/src/services/chirpstack/generic-chirpstack-configuration.service.ts index 487835a0..dc2fd000 100644 --- a/src/services/chirpstack/generic-chirpstack-configuration.service.ts +++ b/src/services/chirpstack/generic-chirpstack-configuration.service.ts @@ -5,30 +5,39 @@ import { Logger, NotFoundException, } from "@nestjs/common"; -import { AxiosRequestConfig, AxiosResponse } from "axios"; - +import { AxiosRequestConfig } from "axios"; import { HeaderDto } from "@dto/chirpstack/header.dto"; -import { ListAllNetworkServerResponseDto } from "@dto/chirpstack/list-all-network-server-response.dto"; -import { ListAllOrganizationsResponseDto } from "@dto/chirpstack/list-all-organizations-response.dto"; import { AuthorizationType } from "@enum/authorization-type.enum"; -import { ErrorCodes } from "@enum/error-codes.enum"; - import { JwtToken } from "./jwt-token"; import { ListAllChirpstackApplicationsResponseDto } from "@dto/chirpstack/list-all-applications-response.dto"; -import { HttpService } from "@nestjs/axios"; +import { Metadata, ServiceError, credentials } from "@grpc/grpc-js"; +import { InternalServiceClient } from "@chirpstack/chirpstack-api/api/internal_grpc_pb"; +import { LoginRequest } from "@chirpstack/chirpstack-api/api/internal_pb"; +import configuration from "@config/configuration"; +import { TenantServiceClient } from "@chirpstack/chirpstack-api/api/tenant_grpc_pb"; +import { ListTenantsRequest, ListTenantsResponse } from "@chirpstack/chirpstack-api/api/tenant_pb"; +import { ApplicationServiceClient } from "@chirpstack/chirpstack-api/api/application_grpc_pb"; +import { + ListApplicationsRequest, + ListApplicationsResponse, +} from "@chirpstack/chirpstack-api/api/application_pb"; +import { ChirpstackApplicationResponseDto } from "@dto/chirpstack/chirpstack-application-response.dto"; +import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; @Injectable() export class GenericChirpstackConfigurationService { - baseUrl = `http://${ - process.env.CHIRPSTACK_APPLICATION_SERVER_HOSTNAME || "localhost" - }:${process.env.CHIRPSTACK_APPLICATION_SERVER_PORT || "8080"}`; - - networkServer = `${ - process.env.CHIRPSTACK_NETWORK_SERVER || "chirpstack-network-server" - }:${process.env.CHIRPSTACK_NETWORK_SERVER_PORT || "8000"}`; - constructor(private httpService: HttpService) {} + baseUrlGRPC = `${process.env.CHIRPSTACK_HOSTNAME || "localhost"}:${ + process.env.CHIRPSTACK_PORT || "8084" + }`; + baseUrl = `http://${process.env.CHIRPSTACK_APPLICATION_SERVER_HOSTNAME || "localhost"}:${ + process.env.CHIRPSTACK_APPLICATION_SERVER_PORT || "8080" + }`; private readonly innerLogger = new Logger(GenericChirpstackConfigurationService.name); + protected applicationServiceClient = new ApplicationServiceClient( + this.baseUrlGRPC, + credentials.createInsecure() + ); setupHeader(endPoint: string, limit?: number, offset?: number): HeaderDto { const timeoutMs = 30 * 1000; @@ -36,9 +45,7 @@ export class GenericChirpstackConfigurationService { // If limits are supplied, add these as query params if (limit != null && offset != null) { - url += `${ - endPoint.indexOf("?") >= 0 ? "&" : "?" - }limit=${limit}&offset=${offset}`; + url += `${endPoint.indexOf("?") >= 0 ? "&" : "?"}limit=${limit}&offset=${offset}`; } const headerDto: HeaderDto = { @@ -51,227 +58,220 @@ export class GenericChirpstackConfigurationService { return headerDto; } - makeAxiosConfiguration(config: { - timeout: number; - authorizationHeader: string; - }): AxiosRequestConfig { - const axiosConfig: AxiosRequestConfig = { - timeout: config.timeout, - headers: { "Content-Type": "application/json" }, - }; - - axiosConfig.headers["Authorization"] = config.authorizationHeader; + //TODO::: Should this be called once or in every function? If once, what if token expires? + async makeMetadataHeader(): Promise { + return new Promise((resolve, reject) => { + // Create the client for the 'internal' service + const internalServiceClient = new InternalServiceClient( + this.baseUrlGRPC, + credentials.createInsecure() + ); - return axiosConfig; + // Create and build the login request message + const loginRequest = new LoginRequest(); + loginRequest.setEmail("admin"); + loginRequest.setPassword(configuration()["chirpstack"]["password"]); + const metadata = new Metadata(); + + // Send the login request + internalServiceClient.login(loginRequest, (error: ServiceError, response: any) => { + if (error) { + reject(error); + } else { + metadata.set("authorization", "Bearer " + response.getJwt()); + resolve(metadata); + } + }); + }); } - async post(endpoint: string, data: T): Promise { - const header = this.setupHeader(endpoint); - const axiosConfig = this.makeAxiosConfiguration(header); - + async post(endpoint: string, client?: any, request?: any): Promise { + const metaData = await this.makeMetadataHeader(); + const createPromise = new Promise((resolve, reject) => { + client.create(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.innerLogger.debug(`post:${endpoint} success`); + resolve(resp.toObject()); + } + }); + }); try { - const result = await this.httpService - .post(header.url, data, axiosConfig) - .toPromise(); - - this.innerLogger.debug( - `post: ${JSON.stringify( - data - )} to ${endpoint} resulting in ${result.status.toString()} and message: ${ - result.statusText - }` - ); - - return result; + return await createPromise; } catch (err) { - this.innerLogger.error( - `post got error: ${JSON.stringify(err?.response?.data)}` - ); - - this.throwBadRequestIf400(err); - - throw err; + this.innerLogger.error(`POST ${endpoint} got error: ${err}`); + throw new BadRequestException(); } } - - private throwBadRequestIf400(err: any) { - if (err?.response?.status == 400) { - throw new BadRequestException({ - success: false, - chirpstackError: err?.response?.data, + async put(endpoint: string, client?: any, request?: any): Promise { + const metaData = await this.makeMetadataHeader(); + const updatePromise = new Promise((resolve, reject) => { + client.update(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.innerLogger.debug(`update :${endpoint} success`); + resolve(resp); + } }); - } - } - - async put(endpoint: string, data: T, id: string): Promise { - const header = this.setupHeader(endpoint); - const axiosConfig = this.makeAxiosConfiguration(header); - const url = header.url + "/" + id; + }); try { - const result = await this.httpService.put(url, data, axiosConfig).toPromise(); - - this.innerLogger.debug( - `put: ${JSON.stringify( - data - )} to ${endpoint} resulting in ${result.status.toString()} and message: ${ - result.statusText - }` - ); - - return result; + await updatePromise; + return; } catch (err) { - this.throwBadRequestIf400(err); - this.innerLogger.error(`Put got error: `); - throw new NotFoundException(ErrorCodes.IdDoesNotExists); + this.innerLogger.error(`UPDATE ${endpoint} got error: ${err}`); + throw new BadRequestException(); } } - async getOneById(endpoint: string, id: string): Promise { - const header = this.setupHeader(endpoint); - const axiosConfig = this.makeAxiosConfiguration(header); + async getOneById(endpoint: string, id: string, client?: any, request?: any): Promise { + const metaData = await this.makeMetadataHeader(); + request.setId(id); + const getPromise = new Promise((resolve, reject) => { + client.get(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.innerLogger.debug(`get from:${endpoint} success`); + resolve(resp); + } + }); + }); try { - const url = header.url + "/" + id; - const result = await this.httpService.get(url, axiosConfig).toPromise(); - - this.innerLogger.debug( - `get by ID from:${endpoint} resulting in ${result.status.toString()} and message: ${ - result.statusText - }` - ); - - return result.data; + return await getPromise; } catch (err) { - this.innerLogger.error( - `GET: ${err?.config?.url} Status: ${ - err?.response?.status - }. Error response: '${JSON.stringify(err?.response?.data)}'` - ); - throw new NotFoundException(ErrorCodes.IdDoesNotExists); + this.innerLogger.error(`GET ${endpoint} got error: ${err}`); + throw new NotFoundException(); } } - async delete(endpoint: string, id?: string): Promise { - const header = this.setupHeader(endpoint); - const axiosConfig = this.makeAxiosConfiguration(header); - const url = header.url + (id != undefined ? "/" + id : ""); - try { - const result = await this.httpService.delete(url, axiosConfig).toPromise(); - - this.innerLogger.debug( - `DELETE ${url} - Status: ${result.status.toString()} and message: ${ - result.statusText - }` - ); - return result; - } catch (err) { - this.innerLogger.error( - `DELETE ${url} - Got error: ${JSON.stringify(err?.response?.data)}` - ); - throw new InternalServerErrorException(err?.response?.data); + async delete(endpoint: string, client?: any, request?: any): Promise { + //MAYBE return boolean of result (succes vs failure) + if (client) { + const metaData = await this.makeMetadataHeader(); + const deletePromise = new Promise((resolve, reject) => { + client.delete(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.innerLogger.debug(`delete :${endpoint} success`); + resolve(resp); + } + }); + }); + try { + await deletePromise; + return; + } catch (err) { + this.innerLogger.error(`DELETE ${endpoint} got error: ${err}`); + throw new BadRequestException(); + } } } - async get(endpoint: string): Promise { - const header = this.setupHeader(endpoint); - const axiosConfig = this.makeAxiosConfiguration(header); - + async get(endpoint: string, client?: any, request?: any): Promise { + const metaData = await this.makeMetadataHeader(); + const getPromise = new Promise((resolve, reject) => { + client.get(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.innerLogger.debug(`get from:${endpoint} success`); + resolve(resp); + } + }); + }); try { - const result = await this.httpService - .get(header.url, axiosConfig) - .toPromise(); - - return result.data; + return await getPromise; } catch (err) { - this.innerLogger.error( - `GET '${header.url}' failed with error (${ - err?.response?.status - }): '${JSON.stringify(err?.response?.data)}'` - ); - if (err?.response?.status == 404) { - throw new NotFoundException(err?.response?.data); - } - - throw new InternalServerErrorException(err?.response?.data); + this.innerLogger.error(`GET ${endpoint} got error: ${err}`); + throw new NotFoundException(); } } async getAllApplicationsWithPagination( - organizationID: string + tenantID: string ): Promise { - return this.getAllWithPagination( - `applications?limit=100&organizationID=${organizationID}` + const req = new ListApplicationsRequest(); + req.setTenantId(await this.getDefaultOrganizationId()); + + const result = await this.getAllWithPagination( + `applications?limit=100&organizationID=${tenantID}`, + 100, + undefined, + this.applicationServiceClient, + req ); + const chirpstackApplicationResponseDto: ChirpstackApplicationResponseDto[] = []; + result.resultList.map(e => { + const resultItem: ChirpstackApplicationResponseDto = { + name: e.name, + description: e.description, + id: e.id, + tenantId: tenantID, + }; + chirpstackApplicationResponseDto.push(resultItem); + }); + return { + totalCount: result.totalCount, + result: chirpstackApplicationResponseDto, + }; } async getAllWithPagination( endpoint: string, limit?: number, - offset?: number + offset?: number, + client?: any, + request?: any ): Promise { - const header = this.setupHeader(endpoint, limit, offset); - const axiosConfig = this.makeAxiosConfiguration(header); - + const metaData = await this.makeMetadataHeader(); + request.setLimit(limit), request.setOffset(offset); + + const getListPromise = new Promise((resolve, reject) => { + client.list(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + const result = resp.toObject(); + resolve(result); + this.innerLogger.debug(`get all from:${endpoint} success`); + } + }); + }); try { - const result = await this.httpService - .get(header.url, axiosConfig) - .toPromise(); - this.innerLogger.debug( - `get all from:${endpoint} resulting in ${result.status.toString()} and message: ${ - result.statusText - }` - ); - return result.data; + return await getListPromise; } catch (err) { - this.innerLogger.error(`GET ${header.url} got error: ${err}`); + this.innerLogger.error(`GET ${endpoint} got error: ${err}`); throw new NotFoundException(); } } - public async getNetworkServers( + public async getTenants( limit?: number, offset?: number - ): Promise { - const res = await this.getAllWithPagination( - "network-servers", - limit, - offset + ): Promise { + const tenantClient = new TenantServiceClient( + this.baseUrlGRPC, + credentials.createInsecure() ); - return res; - } + const req = new ListTenantsRequest(); - public async getOrganizations( - limit?: number, - offset?: number - ): Promise { - const res = await this.getAllWithPagination( + const res = await this.getAllWithPagination( "organizations", limit, - offset + offset, + tenantClient, + req ); return res; } - public async getDefaultNetworkServerId(): Promise { - let id = null; - await this.getNetworkServers(1000, 0).then(response => { - response.result.forEach(element => { - if (element.name.toLowerCase() === "os2iot") { - id = element.id.toString(); - } - }); - }); - if (id) { - return id; - } - throw new InternalServerErrorException( - "Could not find any NetworkServer in Chirpstack named: 'OS2iot'" - ); - } - public async getDefaultOrganizationId(): Promise { let id = null; - await this.getOrganizations(1000, 0).then(response => { - response.result.forEach(element => { + await this.getTenants(1000, 0).then(response => { + response.resultList.forEach(element => { if ( element.name.toLowerCase() == "os2iot" || element.name.toLowerCase() == "chirpstack" diff --git a/src/services/device-management/multicast.service.ts b/src/services/chirpstack/multicast.service.ts similarity index 61% rename from src/services/device-management/multicast.service.ts rename to src/services/chirpstack/multicast.service.ts index e6db0393..1051e92b 100644 --- a/src/services/device-management/multicast.service.ts +++ b/src/services/chirpstack/multicast.service.ts @@ -9,21 +9,24 @@ import { Inject, Injectable, Logger, + NotFoundException, } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; import { DeleteResult, Repository, SelectQueryBuilder } from "typeorm"; import { CreateMulticastDto } from "../../entities/dto/create-multicast.dto"; import { UpdateMulticastDto } from "../../entities/dto/update-multicast.dto"; -import { ApplicationService } from "./application.service"; -import { AxiosResponse } from "axios"; +import { ApplicationService } from "../device-management/application.service"; import { ChirpstackMulticastContentsDto } from "@dto/chirpstack/chirpstack-multicast-contents.dto"; import { LorawanMulticastDefinition } from "@entities/lorawan-multicast.entity"; import { IoTDeviceType } from "@enum/device-type.enum"; import { AddDeviceToMulticastDto } from "@dto/chirpstack-add-device-multicast.dto"; import { LoRaWANDevice } from "@entities/lorawan-device.entity"; import { IoTDevice } from "@entities/iot-device.entity"; -import { MulticastDownlinkQueueResponseDto } from "@dto/chirpstack/chirpstack-multicast-downlink-queue-response.dto"; +import { + MulticastDownlinkQueueResponseDto, + MulticastQueueItem, +} from "@dto/chirpstack/chirpstack-multicast-downlink-queue-response.dto"; import { CreateMulticastDownlinkDto } from "@dto/create-multicast-downlink.dto"; import { CreateChirpstackMulticastQueueItemDto, @@ -31,24 +34,44 @@ import { } from "@dto/chirpstack/create-chirpstack-multicast-queue-item.dto"; import { ChirpstackDeviceService } from "@services/chirpstack/chirpstack-device.service"; import { ChirpstackDeviceContentsDto } from "@dto/chirpstack/chirpstack-device-contents.dto"; -import { HttpService } from "@nestjs/axios"; - +import { + AddDeviceToMulticastGroupRequest, + CreateMulticastGroupRequest, + DeleteMulticastGroupRequest, + EnqueueMulticastGroupQueueItemRequest, + FlushMulticastGroupQueueRequest, + GetMulticastGroupRequest, + GetMulticastGroupResponse, + ListMulticastGroupQueueRequest, + ListMulticastGroupQueueResponse, + MulticastGroup, + MulticastGroupQueueItem, + MulticastGroupType, + UpdateMulticastGroupRequest, +} from "@chirpstack/chirpstack-api/api/multicast_group_pb"; +import { MulticastGroupServiceClient } from "@chirpstack/chirpstack-api/api/multicast_group_grpc_pb"; +import { credentials, ServiceError } from "@grpc/grpc-js"; +import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { multicastGroup } from "@enum/multicast-type.enum"; @Injectable() export class MulticastService extends GenericChirpstackConfigurationService { constructor( - internalHttpService: HttpService, - @InjectRepository(Multicast) private multicastRepository: Repository, @Inject(forwardRef(() => ApplicationService)) // because of circular reference private applicationService: ApplicationService, private chirpStackDeviceService: ChirpstackDeviceService ) { - super(internalHttpService); + super(); } private readonly logger = new Logger(MulticastService.name); multicastGroupUrl = "multicast-groups"; + private multicastServiceClient = new MulticastGroupServiceClient( + this.baseUrlGRPC, + credentials.createInsecure() + ); + async findAndCountAllWithPagination( // inspired by datatarget and other places in this project. // Repository syntax doesn't yet support ordering by relation: https://github.com/typeorm/typeorm/issues/2620 @@ -62,10 +85,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { let queryBuilder = this.multicastRepository .createQueryBuilder("multicast") .innerJoinAndSelect("multicast.application", "application") - .innerJoinAndSelect( - "multicast.lorawanMulticastDefinition", - "lorawan-multicast" - ) + .innerJoinAndSelect("multicast.lorawanMulticastDefinition", "lorawan-multicast") .skip(query?.offset ? +query.offset : 0) .take(query?.limit ? +query.limit : 100) .orderBy(orderByColumn, direction); @@ -82,10 +102,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { } private getSortingForMulticasts(query: ListAllMulticastsDto) { let orderBy = `multicast.id`; - if ( - (query?.orderOn != null && query.orderOn == "id") || - query.orderOn == "groupName" - ) { + if ((query?.orderOn != null && query.orderOn == "id") || query.orderOn == "groupName") { orderBy = `multicast.${query.orderOn}`; } return orderBy; @@ -100,12 +117,9 @@ export class MulticastService extends GenericChirpstackConfigurationService { appId: query.applicationId, }); } else if (applicationIds) { - queryBuilder = queryBuilder.where( - '"application"."id" IN (:...allowedApplications)', - { - allowedApplications: applicationIds, - } - ); + queryBuilder = queryBuilder.where('"application"."id" IN (:...allowedApplications)', { + allowedApplications: applicationIds, + }); } return queryBuilder; } @@ -120,15 +134,10 @@ export class MulticastService extends GenericChirpstackConfigurationService { }); } - async create( - createMulticastDto: CreateMulticastDto, - userId: number - ): Promise { + async create(createMulticastDto: CreateMulticastDto, userId: number): Promise { //since the multicast is gonna be created in both the DB with relations and in chirpstack, two different objects is gonna be used. const dbMulticast = new Multicast(); dbMulticast.lorawanMulticastDefinition = new LorawanMulticastDefinition(); - const chirpStackMulticast = new CreateMulticastChirpStackDto(); - chirpStackMulticast.multicastGroup = new ChirpstackMulticastContentsDto(); const mappedDbMulticast = await this.mapMulticastDtoToDbMulticast( createMulticastDto, @@ -146,12 +155,11 @@ export class MulticastService extends GenericChirpstackConfigurationService { // If they all have same serviceID / appID then proceed. await this.createMulticastInChirpstack( createMulticastDto, - chirpStackMulticast, lorawanDevices, mappedDbMulticast ); } else { - throw new BadRequestException(ErrorCodes.DifferentServiceprofile); + throw new BadRequestException(ErrorCodes.InvalidPost); } } } @@ -160,25 +168,27 @@ export class MulticastService extends GenericChirpstackConfigurationService { async createMulticastInChirpstack( createMulticastDto: CreateMulticastDto | UpdateMulticastDto, - chirpStackMulticast: CreateMulticastChirpStackDto, lorawanDevices: LoRaWANDevice[], mappedDbMulticast: Multicast ): Promise { const mappedChirpStackMulticast = await this.mapMulticastDtoToChirpStackMulticast( createMulticastDto, - chirpStackMulticast, lorawanDevices[0] // used for setting appID ); - - const result = await this.post(this.multicastGroupUrl, mappedChirpStackMulticast); // This creates the multicast in chirpstack. Chirpstack returns an id as a string + const req = new CreateMulticastGroupRequest(); + req.setMulticastGroup(mappedChirpStackMulticast); + const result: PostReturnInterface = await this.post( + this.multicastGroupUrl, + this.multicastServiceClient, + req + ); // This creates the multicast in chirpstack. Chirpstack returns an id as a string await this.addDevices(createMulticastDto, result); // iotDevices are added to multicast in a seperate endpoint. this.handlePossibleError(result, createMulticastDto); - if (result.status === 200) { - mappedDbMulticast.lorawanMulticastDefinition.chirpstackGroupId = - result.data.id; + if (result.id) { + mappedDbMulticast.lorawanMulticastDefinition.chirpstackGroupId = result.id; } } @@ -223,26 +233,26 @@ export class MulticastService extends GenericChirpstackConfigurationService { ): Promise { const mappedChirpStackMulticast = await this.mapMulticastDtoToChirpStackMulticast( updateMulticastDto, - existingChirpStackMulticast, lorawanDevices[0] ); - - const result = await this.put( - this.multicastGroupUrl, - mappedChirpStackMulticast, - existingMulticast.lorawanMulticastDefinition.chirpstackGroupId - ); - this.handlePossibleError(result, updateMulticastDto); - - const added: IoTDevice[] = []; - const removed: IoTDevice[] = []; - this.compareDevices(existingMulticast, updateMulticastDto, added, removed); - await this.updateDevices( - // add's and removes devices from chirpstack - removed, - added, - existingMulticast.lorawanMulticastDefinition.chirpstackGroupId - ); + mappedChirpStackMulticast.setId(existingChirpStackMulticast.multicastGroup.id); + const req = new UpdateMulticastGroupRequest(); + req.setMulticastGroup(mappedChirpStackMulticast); + try { + await this.put(this.multicastGroupUrl, this.multicastServiceClient, req); + + const added: IoTDevice[] = []; + const removed: IoTDevice[] = []; + this.compareDevices(existingMulticast, updateMulticastDto, added, removed); + await this.updateDevices( + // add's and removes devices from chirpstack + removed, + added, + existingMulticast.lorawanMulticastDefinition.chirpstackGroupId + ); + } catch (e) { + throw new BadRequestException(e); + } } checkForLorawan( @@ -268,10 +278,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { } for (let i = 0; i < devices.length; i++) { - if ( - devices[i].applicationID !== - chirpStackMulticast.multicastGroup.applicationID - ) { + if (devices[i].applicationID !== chirpStackMulticast.multicastGroup.applicationID) { // if one of the application id is different than the first one, then we know that there is different // service profiles. Therefore, return false. return false; @@ -304,20 +311,34 @@ export class MulticastService extends GenericChirpstackConfigurationService { return true; // If the appId is equal for each element, then it's the same service profile } - async getChirpstackMulticast( - multicastId: string - ): Promise { - const res = await this.get( - `multicast-groups/${multicastId}` + async getChirpstackMulticast(multicastId: string): Promise { + const req = new GetMulticastGroupRequest(); + req.setId(multicastId); + const res = await this.get( + `multicast-groups/${multicastId}`, + this.multicastServiceClient, + req ); - return res; + const multicastDtoContent: ChirpstackMulticastContentsDto = { + applicationID: res.getMulticastGroup().getApplicationId(), + dr: res.getMulticastGroup().getDr(), + fCnt: res.getMulticastGroup().getFCnt(), + frequency: res.getMulticastGroup().getFrequency(), + mcAddr: res.getMulticastGroup().getMcAddr(), + mcAppSKey: res.getMulticastGroup().getMcAppSKey(), + mcNwkSKey: res.getMulticastGroup().getMcNwkSKey(), + name: res.getMulticastGroup().getName(), + groupType: multicastGroup.ClassC, + id: res.getMulticastGroup().getId(), + }; + + const returnDto: CreateMulticastChirpStackDto = { multicastGroup: multicastDtoContent }; + + return returnDto; } - async multicastDelete( - id: number, - existingMulticast: Multicast - ): Promise { + async multicastDelete(id: number, existingMulticast: Multicast): Promise { const loraDevices = this.checkForLorawan(existingMulticast); if (loraDevices.length > 0) { await this.deleteMulticastChirpstack( @@ -327,9 +348,11 @@ export class MulticastService extends GenericChirpstackConfigurationService { return this.multicastRepository.delete(id); } - async deleteMulticastChirpstack(id: string): Promise { + async deleteMulticastChirpstack(id: string): Promise { try { - return await this.delete(this.multicastGroupUrl, id); + const req = new DeleteMulticastGroupRequest(); + req.setId(id); + return await this.delete(this.multicastGroupUrl, this.multicastServiceClient, req); } catch (err) { throw err; } @@ -341,8 +364,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { ): Promise { multicast.groupName = multicastDto.name; multicast.lorawanMulticastDefinition.address = multicastDto.mcAddr; - multicast.lorawanMulticastDefinition.applicationSessionKey = - multicastDto.mcAppSKey; + multicast.lorawanMulticastDefinition.applicationSessionKey = multicastDto.mcAppSKey; multicast.lorawanMulticastDefinition.networkSessionKey = multicastDto.mcNwkSKey; multicast.lorawanMulticastDefinition.dataRate = multicastDto.dr; multicast.lorawanMulticastDefinition.frameCounter = multicastDto.fCnt; @@ -371,45 +393,38 @@ export class MulticastService extends GenericChirpstackConfigurationService { private async mapMulticastDtoToChirpStackMulticast( multicastDto: CreateMulticastDto | UpdateMulticastDto, - multicast: CreateMulticastChirpStackDto, device: LoRaWANDevice - ): Promise { - multicast.multicastGroup.name = multicastDto.name; - multicast.multicastGroup.mcAddr = multicastDto.mcAddr; - multicast.multicastGroup.mcAppSKey = multicastDto.mcAppSKey; - multicast.multicastGroup.mcNwkSKey = multicastDto.mcNwkSKey; - multicast.multicastGroup.dr = multicastDto.dr; - multicast.multicastGroup.fCnt = multicastDto.fCnt; - multicast.multicastGroup.frequency = multicastDto.frequency; - multicast.multicastGroup.groupType = multicastDto.groupType; + ): Promise { + const multicast = new MulticastGroup(); + + multicast.setName(multicastDto.name); + multicast.setMcAddr(multicastDto.mcAddr); + multicast.setMcAppSKey(multicastDto.mcAppSKey); + multicast.setMcNwkSKey(multicastDto.mcNwkSKey); + multicast.setDr(multicastDto.dr); + multicast.setFCnt(multicastDto.fCnt); + multicast.setFrequency(multicastDto.frequency); + multicast.setGroupType(MulticastGroupType.CLASS_C); if (!!device) { // if devices is included, at this point we know that devices is validated. Therefore we can use appID - multicast.multicastGroup.applicationID = device.chirpstackApplicationId.toString(); + multicast.setApplicationId(device.chirpstackApplicationId.toString()); } else { // used for update when all devices are removed - multicast.multicastGroup.applicationID = - multicast.multicastGroup.applicationID; + multicast.setApplicationId(multicast.getApplicationId()); } return multicast; } private handlePossibleError( - result: AxiosResponse, - dto: - | CreateMulticastDto - | UpdateMulticastDto - | CreateChirpstackMulticastQueueItemDto + result: PostReturnInterface, + dto: CreateMulticastDto | UpdateMulticastDto | CreateChirpstackMulticastQueueItemDto ): void { - if (result.status !== 200) { - this.logger.error( - `Error from Chirpstack: '${JSON.stringify( - dto - )}', got response: ${JSON.stringify(result.data)}` - ); + if (!result.id) { + this.logger.error(`Error from Chirpstack: '${JSON.stringify(dto)}', failed`); throw new BadRequestException({ success: false, - error: result.data, + error: result.id, }); } } @@ -425,11 +440,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { let lorawanDevice: LoRaWANDevice = new LoRaWANDevice(); lorawanDevice = device as LoRaWANDevice; return await this.delete( - this.multicastGroupUrl + - "/" + - chirpstackMulticastID + - "/" + - "devices", + this.multicastGroupUrl + "/" + chirpstackMulticastID + "/" + "devices", lorawanDevice.deviceEUI ); } @@ -443,11 +454,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { addDevice.multicastGroupID = chirpstackMulticastID; await this.post( - this.multicastGroupUrl + - "/" + - chirpstackMulticastID + - "/" + - "devices", + this.multicastGroupUrl + "/" + chirpstackMulticastID + "/" + "devices", addDevice ); } @@ -456,29 +463,49 @@ export class MulticastService extends GenericChirpstackConfigurationService { private async addDevices( multicastDto: CreateMulticastDto | UpdateMulticastDto, - chirpstackMulticastID: AxiosResponse // the id returned from chirpstack when the multicast is created in chirpstack. + chirpstackMulticastID: PostReturnInterface // the id returned from chirpstack when the multicast is created in chirpstack. ) { multicastDto.iotDevices.forEach(async device => { if (device.type === IoTDeviceType.LoRaWAN) { let lorawanDevice: LoRaWANDevice = new LoRaWANDevice(); lorawanDevice = device as LoRaWANDevice; // cast to LoRaWANDevice since it has DeviceEUI - const addDevice = new AddDeviceToMulticastDto(); - addDevice.devEUI = lorawanDevice.deviceEUI; - addDevice.multicastGroupID = chirpstackMulticastID.data.id; - - await this.post( - // post call to chirpstack - this.multicastGroupUrl + - "/" + - chirpstackMulticastID.data.id + - "/" + - "devices", - addDevice + const req = new AddDeviceToMulticastGroupRequest(); + req.setDevEui(lorawanDevice.deviceEUI); + req.setMulticastGroupId(chirpstackMulticastID.id); + + await this.addDeviceToMulticast( + this.multicastGroupUrl + "/" + chirpstackMulticastID.id + "/" + "devices", + this.multicastServiceClient, + req ); } }); } + async addDeviceToMulticast( + endpoint: string, + client?: MulticastGroupServiceClient, + request?: AddDeviceToMulticastGroupRequest + ): Promise { + const metaData = await this.makeMetadataHeader(); + const createPromise = new Promise((resolve, reject) => { + client.addDevice(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`post:${endpoint} success`); + resolve(resp.toObject()); + } + }); + }); + try { + return await createPromise; + } catch (err) { + this.logger.error(`POST ${endpoint} got error: ${err}`); + throw new BadRequestException(); + } + } + private compareDevices( oldMulticast: Multicast, newMulticast: UpdateMulticastDto, @@ -487,10 +514,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { ) { oldMulticast.iotDevices.forEach(dbDevice => { // if a device in the old multicast is not in the new one, then delete - if ( - newMulticast.iotDevices.findIndex(device => device.id === dbDevice.id) === - -1 - ) { + if (newMulticast.iotDevices.findIndex(device => device.id === dbDevice.id) === -1) { removed.push(dbDevice); } }); @@ -498,22 +522,32 @@ export class MulticastService extends GenericChirpstackConfigurationService { newMulticast.iotDevices.forEach(frontendDevice => { // if a device in the new multicast is not in the old one, then add if ( - oldMulticast.iotDevices.findIndex( - device => device.id === frontendDevice.id - ) === -1 + oldMulticast.iotDevices.findIndex(device => device.id === frontendDevice.id) === -1 ) { added.push(frontendDevice); } }); } - async getDownlinkQueue( - multicastID: string - ): Promise { - const res = await this.get( - `multicast-groups/${multicastID}/queue` - ); - return res; + async getDownlinkQueue(multicastID: string): Promise { + const req = new ListMulticastGroupQueueRequest(); + req.setMulticastGroupId(multicastID); + const res = await this.getQueue(this.multicastServiceClient, req); + + const queueDto: MulticastQueueItem[] = []; + res.getItemsList().forEach(queueItem => { + queueDto.push({ + multicastGroupId: queueItem.getMulticastGroupId(), + fCnt: queueItem.getFCnt(), + fPort: queueItem.getFPort(), + data: queueItem.getData_asB64(), + }); + }); + + const responseDto: MulticastDownlinkQueueResponseDto = { + deviceQueueItems: queueDto, + }; + return responseDto; } public async createDownlink( @@ -539,25 +573,29 @@ export class MulticastService extends GenericChirpstackConfigurationService { ): Promise { await this.deleteDownlinkQueue(dto.multicastQueueItem.multicastGroupID); try { - const res = await this.post( - `multicast-groups/${dto.multicastQueueItem.multicastGroupID}/queue`, - dto - ); - return res.data; + const req = new EnqueueMulticastGroupQueueItemRequest(); + const queueItem = new MulticastGroupQueueItem(); + queueItem.setData(dto.multicastQueueItem.data); + queueItem.setMulticastGroupId(dto.multicastQueueItem.multicastGroupID); + queueItem.setFPort(dto.multicastQueueItem.fPort); + req.setQueueItem(queueItem); + + const res = await this.postDownlink(this.multicastServiceClient, req); + return res; } catch (err) { const fcntError = "enqueue downlink payload error: get next downlink fcnt for deveui error"; if (err?.response?.data?.error?.startsWith(fcntError)) { - throw new BadRequestException( - ErrorCodes.DeviceIsNotActivatedInChirpstack - ); + throw new BadRequestException(ErrorCodes.DeviceIsNotActivatedInChirpstack); } throw err; } } async deleteDownlinkQueue(multicastID: string): Promise { - await this.delete(`multicast-groups/${multicastID}/queue`); + const req = new FlushMulticastGroupQueueRequest(); + req.setMulticastGroupId(multicastID); + await this.deleteQueue(this.multicastServiceClient, req); } private hexBytesToBase64(hexBytes: string): string { @@ -569,18 +607,14 @@ export class MulticastService extends GenericChirpstackConfigurationService { updateMulticastDto: UpdateMulticastDto, mappedMulticast: Multicast ): Promise { - const chirpStackMulticast = new CreateMulticastChirpStackDto(); - chirpStackMulticast.multicastGroup = new ChirpstackMulticastContentsDto(); - if (await this.checkForDifferentAppID(lorawanDevices)) { await this.createMulticastInChirpstack( updateMulticastDto, - chirpStackMulticast, lorawanDevices, mappedMulticast ); } else { - throw new BadRequestException(ErrorCodes.DifferentServiceprofile); + throw new BadRequestException(ErrorCodes.InvalidPost); } } @@ -608,10 +642,77 @@ export class MulticastService extends GenericChirpstackConfigurationService { oldMulticast ); } else { - throw new BadRequestException(ErrorCodes.NewDevicesWrongServiceProfile); + throw new BadRequestException(ErrorCodes.InvalidPost); } } else { - throw new BadRequestException(ErrorCodes.DifferentServiceprofile); + throw new BadRequestException(ErrorCodes.InvalidPost); + } + } + + async getQueue( + client: MulticastGroupServiceClient, + request: ListMulticastGroupQueueRequest + ): Promise { + const metaData = await this.makeMetadataHeader(); + const getPromise = new Promise((resolve, reject) => { + client.listQueue(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`get from Queue success`); + resolve(resp); + } + }); + }); + try { + return await getPromise; + } catch (err) { + throw new NotFoundException(); + } + } + + async deleteQueue( + client: MulticastGroupServiceClient, + request: FlushMulticastGroupQueueRequest + ): Promise { + const metaData = await this.makeMetadataHeader(); + const getPromise = new Promise((resolve, reject) => { + client.flushQueue(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`Delete queue success`); + resolve(resp); + } + }); + }); + try { + return await getPromise; + } catch (err) { + this.logger.error(`DELETE queue got error: ${err}`); + throw new BadRequestException(); + } + } + async postDownlink( + client: MulticastGroupServiceClient, + request: EnqueueMulticastGroupQueueItemRequest + ): Promise { + const metaData = await this.makeMetadataHeader(); + const createPromise = new Promise((resolve, reject) => { + client.enqueue(request, metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + this.logger.debug(`post downlink success`); + resolve(resp.toObject()); + } + }); + }); + try { + return await createPromise; + } catch (err) { + this.logger.error(`POST downlink got error: ${err}`); + throw new BadRequestException(); } } } diff --git a/src/services/chirpstack/network-server.service.ts b/src/services/chirpstack/network-server.service.ts deleted file mode 100644 index 290cf8ab..00000000 --- a/src/services/chirpstack/network-server.service.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Injectable, InternalServerErrorException, OnModuleInit } from "@nestjs/common"; -import { AxiosResponse } from "axios"; - -import { CreateNetworkServerDto } from "@dto/chirpstack/create-network-server.dto"; -import { ListAllNetworkServerResponseDto } from "@dto/chirpstack/list-all-network-server-response.dto"; -import { NetworkServerDto } from "@dto/chirpstack/network-server.dto"; - -import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; -import { ListAllAdrAlgorithmsResponseDto } from "@dto/chirpstack/list-all-adr-algorithms-response.dto"; - -@Injectable() -export class ChirpstackSetupNetworkServerService extends GenericChirpstackConfigurationService { - networkServerName = "OS2iot"; - - public async bootstrapChirpstackNetworkServerConfiguration(): Promise { - const networkServers = await this.getNetworkServers(100, 0); - const alreadyCreated = networkServers.result.some(networkServer => { - return ( - networkServer.name.toLocaleLowerCase() == - this.networkServerName.toLocaleLowerCase() - ); - }); - - if (!alreadyCreated) { - try { - await this.postNetworkServer(this.setupNetworkServerData()); - } catch (error) { - throw new InternalServerErrorException(error?.result?.data); - } - } - } - - public async postNetworkServer(data: CreateNetworkServerDto): Promise { - return await this.post("network-servers", data); - } - - public async putNetworkServer( - data: CreateNetworkServerDto, - id: number - ): Promise { - return await this.put("network-servers", data, id.toString()); - } - public async deleteNetworkServer(id: number): Promise { - return await this.delete("network-servers", id.toString()); - } - - public async getNetworkServerCount(): Promise { - const result: ListAllNetworkServerResponseDto = await this.getNetworkServers( - 1000, - 0 - ); - return result.totalCount; - } - - public setupNetworkServerData(): CreateNetworkServerDto { - const networkServerDto: NetworkServerDto = { - name: this.networkServerName, - server: this.networkServer, - }; - const createNetworkServerDto: CreateNetworkServerDto = { - networkServer: networkServerDto, - }; - - return createNetworkServerDto; - } - - public async getAdrAlgorithmsForDefaultNetworkServer(): Promise { - const networkServerId = await this.getDefaultNetworkServerId(); - return await this.get(`network-servers/${networkServerId}/adr-algorithms`); - } -} diff --git a/src/services/chirpstack/service-profile.service.ts b/src/services/chirpstack/service-profile.service.ts deleted file mode 100644 index fd1286a3..00000000 --- a/src/services/chirpstack/service-profile.service.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { ConflictException, Injectable } from "@nestjs/common"; -import { AxiosResponse } from "axios"; - -import { CreateServiceProfileDto } from "@dto/chirpstack/create-service-profile.dto"; -import { ListAllServiceProfilesResponseDto } from "@dto/chirpstack/list-all-service-profiles-response.dto"; -import { UpdateServiceProfileDto } from "@dto/chirpstack/update-service-profile.dto"; - -import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; -import { ChirpstackApplicationResponseDto } from "@dto/chirpstack/chirpstack-application-response.dto"; -import { ListAllChirpstackApplicationsResponseDto } from "@dto/chirpstack/list-all-applications-response.dto"; -import { ErrorCodes } from "@enum/error-codes.enum"; - -@Injectable() -export class ServiceProfileService extends GenericChirpstackConfigurationService { - public async createServiceProfile( - dto: CreateServiceProfileDto - ): Promise { - dto = await this.updateDto(dto); - const result = await this.post("service-profiles", dto); - return result; - } - - public async updateServiceProfile( - data: CreateServiceProfileDto, - id: string - ): Promise { - data = await this.updateDto(data); - return await this.put("service-profiles", data, id); - } - - public async deleteServiceProfile(id: string): Promise { - // If any devices have been made using the service profile then an application was made in chirpstack. - // We need to remove the application if it exists before deleting the service profile. - const applications = await this.get( - `applications?search=${id}&limit=100&offset=0` - ); - const applicationToDelete = applications.result.find( - x => x.name.indexOf(id) >= 0 - ); - if (applicationToDelete) { - // Check if there is any devices on the application - const deviceOnApplication = await this.get< - ListAllChirpstackApplicationsResponseDto - >(`devices?limit=10&applicationID=${applicationToDelete.id}`); - if (deviceOnApplication.totalCount > 0) { - throw new ConflictException(ErrorCodes.DeleteNotAllowedHasLoRaWANDevices); - } - - await this.delete("applications", applicationToDelete.id); - } - - return await this.delete("service-profiles", id); - } - - public async findAllServiceProfiles( - limit?: number, - offset?: number - ): Promise { - const res = await this.getAllWithPagination( - "service-profiles", - limit, - offset - ); - - return res; - } - - public async findOneServiceProfileById(id: string): Promise { - const result: CreateServiceProfileDto = await this.getOneById( - "service-profiles", - id - ); - return result; - } - - private async updateDto( - dto: CreateServiceProfileDto | UpdateServiceProfileDto - ): Promise> { - // Chirpstack requires 'gatewayProfileID' to be set (with value or null) - if (!dto?.serviceProfile?.id) { - dto.serviceProfile.id = null; - } - - dto.serviceProfile.networkServerID = await this.getDefaultNetworkServerId(); - dto.serviceProfile.organizationID = await this.getDefaultOrganizationId(); - - return dto; - } -} diff --git a/src/services/csv-generator.service.ts b/src/services/csv-generator.service.ts index a8e90aa7..50cd4d1f 100644 --- a/src/services/csv-generator.service.ts +++ b/src/services/csv-generator.service.ts @@ -1,9 +1,6 @@ import { Injectable } from "@nestjs/common"; import { IoTDevice } from "@entities/iot-device.entity"; -import { IoTDeviceType } from "@enum/device-type.enum"; -import { AuthenticationType } from "@enum/authentication-type.enum"; import { EncryptionHelperService } from "@services/encryption-helper.service"; -import { ActivationType } from "@enum/lorawan-activation-type.enum"; @Injectable() export class CsvGeneratorService { @@ -65,7 +62,6 @@ export class CsvGeneratorService { `${this.base64Encode(deviceCertificate) ?? ""},` + `${this.base64Encode(deviceCertificateKey) ?? ""},` + `${lorawanSettings?.devEUI ?? ""},` + - `${lorawanSettings?.serviceProfileID ?? ""},` + `${lorawanSettings?.deviceProfileID ?? ""},` + `${lorawanSettings?.skipFCntCheck ?? ""},` + `${lorawanSettings?.activationType ?? ""},` + @@ -102,7 +98,6 @@ const csvFields = [ "deviceCertificate", "deviceCertificateKey", "devEUI", - "serviceProfileID", "deviceProfileID", "skipFCntCheck", "activationType", diff --git a/src/services/data-management/device-integration-persistence.service.ts b/src/services/data-management/device-integration-persistence.service.ts index 9740e292..fba9216c 100644 --- a/src/services/data-management/device-integration-persistence.service.ts +++ b/src/services/data-management/device-integration-persistence.service.ts @@ -174,7 +174,7 @@ export class DeviceIntegrationPersistenceService extends AbstractKafkaConsumer { if (isValidLoRaWANPayload(payload)) { // There's signal info for each nearby gateway. Retrieve the strongest signal strength const rssi = Math.max(...payload.rxInfo.map(info => info.rssi)); - const snr = Math.max(...payload.rxInfo.map(info => info.loRaSNR)); + const snr = Math.max(...payload.rxInfo.map(info => info.snr)); message.rssi = Number.isInteger(rssi) ? rssi : message.rssi; message.snr = Number.isInteger(snr) ? snr : message.snr; } else { diff --git a/src/services/device-management/application.service.ts b/src/services/device-management/application.service.ts index ed7152d2..df44edfe 100644 --- a/src/services/device-management/application.service.ts +++ b/src/services/device-management/application.service.ts @@ -1,5 +1,4 @@ import { CreateApplicationDto } from "@dto/create-application.dto"; -import { CreateLoRaWANSettingsDto } from "@dto/create-lorawan-settings.dto"; import { ListAllApplicationsResponseDto } from "@dto/list-all-applications-response.dto"; import { ListAllApplicationsDto } from "@dto/list-all-applications.dto"; import { ListAllEntitiesDto } from "@dto/list-all-entities.dto"; @@ -20,14 +19,21 @@ import { import { ErrorCodes } from "@enum/error-codes.enum"; import { findValuesInRecord } from "@helpers/record.helper"; import { nameof } from "@helpers/type-helper"; -import { ConflictException, forwardRef, Inject, Injectable } from "@nestjs/common"; +import { + BadRequestException, + ConflictException, + forwardRef, + Inject, + Injectable, +} from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { ChirpstackDeviceService } from "@services/chirpstack/chirpstack-device.service"; import { OrganizationService } from "@services/user-management/organization.service"; import { PermissionService } from "@services/user-management/permission.service"; import { DeleteResult, In, Repository } from "typeorm"; -import { MulticastService } from "./multicast.service"; import { DataTargetService } from "@services/data-targets/data-target.service"; +import { MulticastService } from "@services/chirpstack/multicast.service"; +import { ApplicationChirpstackService } from "@services/chirpstack/chirpstack-application.service"; @Injectable() export class ApplicationService { @@ -43,7 +49,8 @@ export class ApplicationService { @Inject(forwardRef(() => PermissionService)) private permissionService: PermissionService, @Inject(forwardRef(() => DataTargetService)) - private dataTargetService: DataTargetService + private dataTargetService: DataTargetService, + private chirpstackApplicationService: ApplicationChirpstackService ) {} async findAndCountInList( @@ -98,10 +105,7 @@ export class ApplicationService { ): Promise { const sorting = this.getSortingForApplications(query); const [result, total] = await this.applicationRepository.findAndCount({ - where: - allowedOrganisations != null - ? { belongsTo: In(allowedOrganisations) } - : {}, + where: allowedOrganisations != null ? { belongsTo: In(allowedOrganisations) } : {}, take: +query.limit, skip: +query.offset, relations: ["iotDevices"], @@ -121,14 +125,11 @@ export class ApplicationService { let orderBy = `application.id`; if ( query.orderOn != null && - (query.orderOn == "id" || - query.orderOn == "name" || - query.orderOn == "updatedAt") + (query.orderOn == "id" || query.orderOn == "name" || query.orderOn == "updatedAt") ) { orderBy = `application.${query.orderOn}`; } - const order: "DESC" | "ASC" = - query?.sort?.toLocaleUpperCase() == "DESC" ? "DESC" : "ASC"; + const order: "DESC" | "ASC" = query?.sort?.toLocaleUpperCase() == "DESC" ? "DESC" : "ASC"; const [result, total] = await this.applicationRepository .createQueryBuilder("application") .innerJoin("application.permissions", "perm") @@ -180,32 +181,10 @@ export class ApplicationService { relations: ["createdBy", "updatedBy"], }, }); - if (app.iotDevices.some(x => x.type == IoTDeviceType.LoRaWAN)) { - await this.matchWithChirpstackStatusData(app); - } return app; } - private async matchWithChirpstackStatusData(app: Application) { - const allFromChirpstack = await this.chirpstackDeviceService.getAllDevicesStatus(); - app.iotDevices.forEach(x => { - if (x.type == IoTDeviceType.LoRaWAN) { - const loraDevice = x as LoRaWANDeviceWithChirpstackDataDto; - const matchingDevice = allFromChirpstack.result.find( - cs => cs.devEUI == loraDevice.deviceEUI - ); - if (matchingDevice) { - loraDevice.lorawanSettings = new CreateLoRaWANSettingsDto(); - loraDevice.lorawanSettings.deviceStatusBattery = - matchingDevice.deviceStatusBattery; - loraDevice.lorawanSettings.deviceStatusMargin = - matchingDevice.deviceStatusMargin; - } - } - }); - } - async findManyByIds(ids: number[]): Promise { if (ids == null || ids?.length == 0) { return []; @@ -213,10 +192,7 @@ export class ApplicationService { return await this.applicationRepository.findBy({ id: In(ids) }); } - async create( - createApplicationDto: CreateApplicationDto, - userId: number - ): Promise { + async create(createApplicationDto: CreateApplicationDto, userId: number): Promise { const application = new Application(); const mappedApplication = await this.mapApplicationDtoToApplication( @@ -230,11 +206,19 @@ export class ApplicationService { mappedApplication.createdBy = userId; mappedApplication.updatedBy = userId; - const app = await this.applicationRepository.save(mappedApplication); + try { + const chirpId = await this.chirpstackApplicationService.createApplication( + createApplicationDto + ); + mappedApplication.chirpstackId = chirpId.id; + const app = await this.applicationRepository.save(mappedApplication); - await this.permissionService.autoAddPermissionsToApplication(app); + await this.permissionService.autoAddPermissionsToApplication(app); - return app; + return app; + } catch (e) { + throw new BadRequestException(ErrorCodes.InvalidPost); + } } async update( @@ -258,6 +242,8 @@ export class ApplicationService { userId ); + await this.chirpstackApplicationService.updateApplication(mappedApplication) + mappedApplication.updatedBy = userId; return this.applicationRepository.save(mappedApplication, {}); } @@ -281,25 +267,30 @@ export class ApplicationService { await this.dataTargetService.delete(dataTarget.id); } - // Delete all LoRaWAN devices in ChirpStack - const loRaWANDevices = application.iotDevices.filter( - device => device.type === IoTDeviceType.LoRaWAN - ); + if (application.chirpstackId) { + await this.chirpstackApplicationService.deleteApplication(application.chirpstackId); + } else { + // Delete all LoRaWAN devices in ChirpStack + const loRaWANDevices = application.iotDevices.filter( + device => device.type === IoTDeviceType.LoRaWAN + ); - for (const device of loRaWANDevices) { - const lwDevice = device as LoRaWANDevice; - await this.chirpstackDeviceService.deleteDevice(lwDevice.deviceEUI); - } + for (const device of loRaWANDevices) { + const lwDevice = device as LoRaWANDevice; + await this.chirpstackDeviceService.deleteDevice(lwDevice.deviceEUI); + } - //delete all multicats - const multicasts = application.multicasts; - for (const multicast of multicasts) { - const dbMulticast = await this.multicastService.findOne(multicast.id); + //delete all multicats + const multicasts = application.multicasts; + for (const multicast of multicasts) { + const dbMulticast = await this.multicastService.findOne(multicast.id); - await this.multicastService.deleteMulticastChirpstack( - dbMulticast.lorawanMulticastDefinition.chirpstackGroupId - ); + await this.multicastService.deleteMulticastChirpstack( + dbMulticast.lorawanMulticastDefinition.chirpstackGroupId + ); + } } + return this.applicationRepository.delete(id); } @@ -371,12 +362,7 @@ export class ApplicationService { buildControlledPropertyDeviceType< T extends Record, Entity extends ControlledProperty | ApplicationDeviceType - >( - validKeys: T, - clientTypes: string[], - userId: number, - entity: { new (): Entity } - ): Entity[] { + >(validKeys: T, clientTypes: string[], userId: number, entity: { new (): Entity }): Entity[] { // Filter out invalid client values const matchingValues = findValuesInRecord(validKeys, clientTypes); @@ -412,16 +398,10 @@ export class ApplicationService { const loraDevices = data.filter( device => device.type === IoTDeviceType.LoRaWAN ) as LoRaWANDeviceWithChirpstackDataDto[]; - const applications = await this.chirpstackDeviceService.getLoRaWANApplications( - loraDevices - ); - const loraApplications = applications.map(app => app.application); + const applications = await this.chirpstackDeviceService.getLoRaWANApplications(loraDevices); for (const device of loraDevices) { - await this.chirpstackDeviceService.enrichLoRaWANDevice( - device, - loraApplications - ); + await this.chirpstackDeviceService.enrichLoRaWANDevice(device); } return { @@ -450,15 +430,11 @@ export class ApplicationService { return orderBy; } - private getSortingForApplications( - query: ListAllEntitiesDto - ): Record { + private getSortingForApplications(query: ListAllEntitiesDto): Record { const sorting: Record = {}; if ( query.orderOn != null && - (query.orderOn == "id" || - query.orderOn == "name" || - query.orderOn == "updatedAt") + (query.orderOn == "id" || query.orderOn == "name" || query.orderOn == "updatedAt") ) { sorting[query.orderOn] = query.sort.toLocaleUpperCase(); } else { diff --git a/src/services/device-management/iot-device-downlink.service.ts b/src/services/device-management/iot-device-downlink.service.ts index ba626ac0..62d5b758 100644 --- a/src/services/device-management/iot-device-downlink.service.ts +++ b/src/services/device-management/iot-device-downlink.service.ts @@ -18,6 +18,7 @@ import { CreateChirpstackDeviceQueueItemResponse, } from "@dto/chirpstack/create-chirpstack-device-queue-item.dto"; import { ChirpstackDeviceService } from "@services/chirpstack/chirpstack-device.service"; +import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; @Injectable() export class IoTDeviceDownlinkService { @@ -33,11 +34,11 @@ export class IoTDeviceDownlinkService { async createDownlink( dto: CreateIoTDeviceDownlinkDto, device: IoTDevice - ): Promise { - if (device.type == IoTDeviceType.LoRaWAN) { + ): Promise { + if (device.type === IoTDeviceType.LoRaWAN) { const cast = device; return await this.createLoraDownlink(dto, cast); - } else if (device.type == IoTDeviceType.SigFox) { + } else if (device.type === IoTDeviceType.SigFox) { const cast = device; return await this.createSigfoxDownlink(dto, cast); } else { @@ -75,7 +76,7 @@ export class IoTDeviceDownlinkService { private async createLoraDownlink( dto: CreateIoTDeviceDownlinkDto, cast: LoRaWANDevice - ): Promise { + ): Promise { const csDto: CreateChirpstackDeviceQueueItemDto = { deviceQueueItem: { fPort: dto.port, diff --git a/src/services/device-management/iot-device.service.ts b/src/services/device-management/iot-device.service.ts index 43149c53..1d00ebaa 100644 --- a/src/services/device-management/iot-device.service.ts +++ b/src/services/device-management/iot-device.service.ts @@ -56,14 +56,7 @@ import { SigFoxApiDeviceTypeService } from "@services/sigfox/sigfox-api-device-t import { SigFoxApiDeviceService } from "@services/sigfox/sigfox-api-device.service"; import { SigFoxGroupService } from "@services/sigfox/sigfox-group.service"; import { SigFoxMessagesService } from "@services/sigfox/sigfox-messages.service"; -import { - DeleteResult, - EntityManager, - ILike, - In, - Repository, - SelectQueryBuilder, -} from "typeorm"; +import { DeleteResult, EntityManager, ILike, In, Repository, SelectQueryBuilder } from "typeorm"; import { v4 as uuidv4 } from "uuid"; import { DeviceModelService } from "./device-model.service"; import { IoTLoRaWANDeviceService } from "./iot-lorawan-device.service"; @@ -167,15 +160,11 @@ export class IoTDeviceService { return iotDevice; } - async findManyWithApplicationAndMetadata( - ids: number[] - ): Promise { + async findManyWithApplicationAndMetadata(ids: number[]): Promise { return this.queryDatabaseForIoTDevices(ids); } - async enrichSigFoxDevice( - iotDevice: IoTDevice - ): Promise { + async enrichSigFoxDevice(iotDevice: IoTDevice): Promise { const sigfoxDevice = iotDevice as SigFoxDeviceWithBackendDataDto; const application = await this.applicationService.findOneWithOrganisation( @@ -187,17 +176,11 @@ export class IoTDeviceService { application.belongsTo.id ); - const thisDevice = await this.getDataFromSigFoxAboutDevice( - sigfoxGroup, - sigfoxDevice - ); + const thisDevice = await this.getDataFromSigFoxAboutDevice(sigfoxGroup, sigfoxDevice); if (!thisDevice) { throw new NotFoundException(ErrorCodes.SigfoxError); } - sigfoxDevice.sigfoxSettings = await this.mapSigFoxBackendDataToDto( - thisDevice, - sigfoxGroup - ); + sigfoxDevice.sigfoxSettings = await this.mapSigFoxBackendDataToDto(thisDevice, sigfoxGroup); return sigfoxDevice; } @@ -225,23 +208,18 @@ export class IoTDeviceService { limit: number, offset: number ): Promise { - const data: Promise< - IoTDeviceMinimalRaw[] - > = this.getQueryForFindAllByPayloadDecoder(payloadDecoderId) + const data: Promise = this.getQueryForFindAllByPayloadDecoder( + payloadDecoderId + ) .addSelect('"application"."id"', "applicationId") .addSelect('"application"."belongsToId"', "organizationId") .limit(limit) .offset(offset) .getRawMany(); - const count = this.getQueryForFindAllByPayloadDecoder( - payloadDecoderId - ).getCount(); + const count = this.getQueryForFindAllByPayloadDecoder(payloadDecoderId).getCount(); - const transformedData: IoTDeviceMinimal[] = await this.mapToIoTDeviceMinimal( - data, - req - ); + const transformedData: IoTDeviceMinimal[] = await this.mapToIoTDeviceMinimal(data, req); return { data: transformedData, @@ -304,10 +282,9 @@ export class IoTDeviceService { sigfoxGroup: SigFoxGroup, sigfoxDevice: SigFoxDeviceWithBackendDataDto ) { - const allDevices = await this.sigfoxApiDeviceService.getAllByGroupIds( - sigfoxGroup, - [sigfoxDevice.groupId] - ); + const allDevices = await this.sigfoxApiDeviceService.getAllByGroupIds(sigfoxGroup, [ + sigfoxDevice.groupId, + ]); const thisDevice = allDevices.data.find(x => x.id == sigfoxDevice.deviceId); return thisDevice; @@ -390,10 +367,7 @@ export class IoTDeviceService { }); } - async create( - createIoTDeviceDto: CreateIoTDeviceDto, - userId: number - ): Promise { + async create(createIoTDeviceDto: CreateIoTDeviceDto, userId: number): Promise { // Reuse the same logic for creating multiple devices. const iotDevice = await this.createMany([createIoTDeviceDto], userId); @@ -435,9 +409,7 @@ export class IoTDeviceService { } // Store or update valid devices on the database - const validIotDevices = validProcessedDevices.map( - iotDeviceMap => iotDeviceMap.iotDevice - ); + const validIotDevices = validProcessedDevices.map(iotDeviceMap => iotDeviceMap.iotDevice); const dbIotDevices = validIotDevices.length ? await this.iotDeviceRepository.save(validIotDevices) : []; @@ -461,9 +433,7 @@ export class IoTDeviceService { return await this.iotDeviceRepository.save(sigfoxDevice); } - async getDownlinkForSigfox( - device: SigFoxDevice - ): Promise { + async getDownlinkForSigfox(device: SigFoxDevice): Promise { if (device.downlinkPayload != null) { return { totalCount: 1, @@ -480,11 +450,7 @@ export class IoTDeviceService { }; } - async update( - id: number, - updateDto: UpdateIoTDeviceDto, - userId: number - ): Promise { + async update(id: number, updateDto: UpdateIoTDeviceDto, userId: number): Promise { const existingIoTDevice = await this.iotDeviceRepository.findOneByOrFail({ id }); const iotDeviceDtoMap: CreateIoTDeviceMapDto[] = [ { iotDevice: existingIoTDevice, iotDeviceDto: updateDto }, @@ -506,14 +472,12 @@ export class IoTDeviceService { const existingDevices = await this.iotDeviceRepository.findBy({ id: In(updateDto.data.map(device => device.id)), }); - const iotDeviceMaps: CreateIoTDeviceMapDto[] = updateDto.data.map( - updateDevice => ({ - iotDeviceDto: updateDevice, - iotDevice: existingDevices.find( - existingDevice => existingDevice.id === updateDevice.id - ), - }) - ); + const iotDeviceMaps: CreateIoTDeviceMapDto[] = updateDto.data.map(updateDevice => ({ + iotDeviceDto: updateDevice, + iotDevice: existingDevices.find( + existingDevice => existingDevice.id === updateDevice.id + ), + })); await this.validateDtoAndCreateIoTDevice(iotDeviceMaps, true); const validDevices = iotDeviceMaps.reduce((res: IoTDevice[], currentMap) => { @@ -551,7 +515,7 @@ export class IoTDeviceService { deleteResult = await transactionManager.delete(IoTDevice, device.id); // Now we can safely perform any actions against Chirpstack - if (device.type == IoTDeviceType.LoRaWAN) { + if (device.type === IoTDeviceType.LoRaWAN) { const lorawanDevice = device as LoRaWANDevice; this.logger.debug( `Deleting LoRaWANDevice ${lorawanDevice.id} / ${lorawanDevice.deviceEUI} in Chirpstack ...` @@ -632,9 +596,7 @@ export class IoTDeviceService { snr: data.snr, })) .sort( - (a, b) => - new Date(a.timestamp).getTime() - - new Date(b.timestamp).getTime() + (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime() ); const averagedStats = this.averageStatsForSameDay(sortedStats); return averagedStats; @@ -707,9 +669,7 @@ export class IoTDeviceService { for (const map of iotDeviceMaps) { const { iotDevice, iotDeviceDto } = map; try { - const application = applications.find( - app => app.id === iotDeviceDto.applicationId - ); + const application = applications.find(app => app.id === iotDeviceDto.applicationId); iotDevice.name = iotDeviceDto.name; iotDevice.application = application; @@ -734,10 +694,7 @@ export class IoTDeviceService { // Filter devices whose properties couldn't be set await this.mapDeviceModels(filterValidIotDeviceMaps(iotDeviceMaps)); // Filter devices which didn't have a valid device model - await this.mapChildDtoToIoTDevice( - filterValidIotDeviceMaps(iotDeviceMaps), - isUpdate - ); + await this.mapChildDtoToIoTDevice(filterValidIotDeviceMaps(iotDeviceMaps), isUpdate); } async mapDeviceModels(iotDevicesDtoMap: CreateIoTDeviceMapDto[]): Promise { @@ -750,9 +707,7 @@ export class IoTDeviceService { return ids; }, []); - const deviceModels = await this.deviceModelService.getByIdsWithRelations( - deviceModelIds - ); + const deviceModels = await this.deviceModelService.getByIdsWithRelations(deviceModelIds); const applicationIds = iotDevicesDtoMap.reduce((ids: number[], dto) => { if (dto.iotDeviceDto.applicationId) { @@ -761,9 +716,7 @@ export class IoTDeviceService { return ids; }, []); - const applications = await this.applicationService.findManyWithOrganisation( - applicationIds - ); + const applications = await this.applicationService.findManyWithOrganisation(applicationIds); // Ensure that each device model is assignable this.setDeviceModel(iotDevicesDtoMap, applications, deviceModels); @@ -809,9 +762,7 @@ export class IoTDeviceService { } } - resetHttpDeviceApiKey( - httpDevice: GenericHTTPDevice - ): Promise { + resetHttpDeviceApiKey(httpDevice: GenericHTTPDevice): Promise { httpDevice.apiKey = uuidv4(); return this.iotDeviceRepository.save(httpDevice); } @@ -848,17 +799,10 @@ export class IoTDeviceService { } else if (map.iotDevice.constructor.name === SigFoxDevice.name) { const cast = map.iotDevice as SigFoxDevice; map.iotDevice = await this.mapSigFoxDevice(map.iotDeviceDto, cast); - } else if ( - map.iotDevice.constructor.name === MQTTInternalBrokerDevice.name - ) { + } else if (map.iotDevice.constructor.name === MQTTInternalBrokerDevice.name) { const cast = map.iotDevice as MQTTInternalBrokerDevice; - map.iotDevice = await this.mapMQTTInternalBrokerDevice( - map.iotDeviceDto, - cast - ); - } else if ( - map.iotDevice.constructor.name === MQTTExternalBrokerDevice.name - ) { + map.iotDevice = await this.mapMQTTInternalBrokerDevice(map.iotDeviceDto, cast); + } else if (map.iotDevice.constructor.name === MQTTExternalBrokerDevice.name) { const cast = map.iotDevice as MQTTExternalBrokerDevice; map.iotDevice = await this.mapMQTTExternalBrokerDevice( map.iotDeviceDto, @@ -869,8 +813,7 @@ export class IoTDeviceService { } catch (error) { map.error = { message: - (error as Error)?.message ?? - ErrorCodes.FailedToCreateOrUpdateIotDevice, + (error as Error)?.message ?? ErrorCodes.FailedToCreateOrUpdateIotDevice, }; } } @@ -914,10 +857,7 @@ export class IoTDeviceService { cast.groupId = sigfoxGroup.sigfoxGroupId; await this.createOrUpdateSigFoxDevice(dto, sigfoxGroup, cast); - await this.sigfoxApiDeviceTypeService.addOrUpdateCallback( - sigfoxGroup, - cast.deviceTypeId - ); + await this.sigfoxApiDeviceTypeService.addOrUpdateCallback(sigfoxGroup, cast.deviceTypeId); return cast; } @@ -945,9 +885,7 @@ export class IoTDeviceService { if (err?.status == 429) { throw err; } - throw new BadRequestException( - ErrorCodes.DeviceDoesNotExistInSigFoxForGroup - ); + throw new BadRequestException(ErrorCodes.DeviceDoesNotExistInSigFoxForGroup); } } } @@ -999,18 +937,8 @@ export class IoTDeviceService { sigfoxDevice: SigFoxDevice ) { await Promise.all([ - this.updateSigFoxDevice( - currentSigFoxSettings, - dto, - sigfoxGroup, - sigfoxDevice - ), - this.changeDeviceTypeIfNeeded( - currentSigFoxSettings, - dto, - sigfoxGroup, - sigfoxDevice - ), + this.updateSigFoxDevice(currentSigFoxSettings, dto, sigfoxGroup, sigfoxDevice), + this.changeDeviceTypeIfNeeded(currentSigFoxSettings, dto, sigfoxGroup, sigfoxDevice), ]); } @@ -1028,11 +956,7 @@ export class IoTDeviceService { name: dto.name, }; - await this.sigfoxApiDeviceService.update( - sigfoxGroup, - sigfoxDevice.deviceId, - updateDto - ); + await this.sigfoxApiDeviceService.update(sigfoxGroup, sigfoxDevice.deviceId, updateDto); } private async changeDeviceTypeIfNeeded( @@ -1056,10 +980,7 @@ export class IoTDeviceService { } } - private async createInSigfoxBackend( - dto: CreateIoTDeviceDto, - sigfoxGroup: SigFoxGroup - ) { + private async createInSigfoxBackend(dto: CreateIoTDeviceDto, sigfoxGroup: SigFoxGroup) { const sigfoxDto: CreateSigFoxApiDeviceRequestDto = this.mapToSigFoxDto(dto); try { @@ -1096,7 +1017,7 @@ export class IoTDeviceService { lorawanDevice: LoRaWANDevice, isUpdate: boolean, lorawanDeviceEuis: ChirpstackDeviceId[] = null, - loraApplications: ListAllChirpstackApplicationsResponseDto = null + loraApplications: ListAllChirpstackApplicationsResponseDto = null, ): Promise { lorawanDevice.deviceEUI = dto.lorawanSettings.devEUI; @@ -1109,7 +1030,6 @@ export class IoTDeviceService { ) { throw new BadRequestException(ErrorCodes.IdInvalidOrAlreadyInUse); } - try { const chirpstackDeviceDto = this.chirpstackDeviceService.makeCreateChirpstackDeviceDto( dto.lorawanSettings, @@ -1117,19 +1037,23 @@ export class IoTDeviceService { ); const applicationId = await this.chirpstackDeviceService.findOrCreateDefaultApplication( - chirpstackDeviceDto, - loraApplications + loraApplications, + lorawanDevice ); lorawanDevice.chirpstackApplicationId = applicationId; - chirpstackDeviceDto.device.applicationID = applicationId.toString(); + chirpstackDeviceDto.device.applicationID = applicationId; // Create or update the LoRa device against Chirpstack API - await this.chirpstackDeviceService.createOrUpdateDevice( + const response = await this.chirpstackDeviceService.createOrUpdateDevice( chirpstackDeviceDto, lorawanDeviceEuis ); - lorawanDeviceEuis.push(chirpstackDeviceDto.device); - await this.doActivation(dto, isUpdate); + if (response) { + lorawanDeviceEuis.push(chirpstackDeviceDto.device); + await this.doActivation(dto, isUpdate); + } else { + throw new BadRequestException(ErrorCodes.InvalidPost); + } } catch (err) { this.logger.error(err); @@ -1137,20 +1061,16 @@ export class IoTDeviceService { if (err?.response?.data?.error == "object already exists") { throw new BadRequestException(ErrorCodes.NameInvalidOrAlreadyInUse); } - throw err; } return lorawanDevice; } - private async doActivation( - dto: CreateIoTDeviceDto, - isUpdate: boolean - ): Promise { - if (dto.lorawanSettings.activationType == ActivationType.OTAA) { + private async doActivation(dto: CreateIoTDeviceDto, isUpdate: boolean): Promise { + if (dto.lorawanSettings.activationType === ActivationType.OTAA) { // OTAA Activate if key is provided await this.doActivationByOTAA(dto, isUpdate); - } else if (dto.lorawanSettings.activationType == ActivationType.ABP) { + } else if (dto.lorawanSettings.activationType === ActivationType.ABP) { await this.doActivationByABP(dto, isUpdate); } } @@ -1181,8 +1101,7 @@ export class IoTDeviceService { dto.lorawanSettings.fCntUp, dto.lorawanSettings.nFCntDown, dto.lorawanSettings.networkSessionKey, - dto.lorawanSettings.applicationSessionKey, - isUpdate + dto.lorawanSettings.applicationSessionKey ); } else { throw new BadRequestException(ErrorCodes.MissingABPInfo); @@ -1198,9 +1117,7 @@ export class IoTDeviceService { cast.authenticationType = settings.authenticationType; switch (cast.authenticationType) { case AuthenticationType.PASSWORD: - cast.mqttpasswordhash = this.mqttService.hashPassword( - settings.mqttpassword - ); + cast.mqttpasswordhash = this.mqttService.hashPassword(settings.mqttpassword); cast.mqttpassword = this.encryptionHelperService.basicEncrypt( settings.mqttpassword ); @@ -1316,8 +1233,7 @@ export class IoTDeviceService { private async fixMQTTInternalBrokerTopics(dbIotDevices: IoTDevice[]) { const newMQTTInternalBrokers = dbIotDevices.filter( (d: MQTTInternalBrokerDevice) => - d.type === IoTDeviceType.MQTTInternalBroker && - d.mqtttopicname.includes("undefined") + d.type === IoTDeviceType.MQTTInternalBroker && d.mqtttopicname.includes("undefined") ); const remappedMQTT = []; for (const iotDevice of newMQTTInternalBrokers) { From a550178baf34b82a4b08ffb09e4296bbe968da18 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Thu, 30 Nov 2023 14:44:56 +0100 Subject: [PATCH 03/24] changed the metadataheader to using apikey. --- src/config/configuration.ts | 5 +- .../chirpstack/chirpstack-device.service.ts | 18 +++---- .../chirpstack/chirpstack-gateway.service.ts | 2 +- .../chirpstack/device-profile.service.ts | 2 +- ...eneric-chirpstack-configuration.service.ts | 48 +++++-------------- src/services/chirpstack/multicast.service.ts | 8 ++-- 6 files changed, 31 insertions(+), 52 deletions(-) diff --git a/src/config/configuration.ts b/src/config/configuration.ts index 1303c157..2dda5353 100644 --- a/src/config/configuration.ts +++ b/src/config/configuration.ts @@ -16,14 +16,14 @@ export default (): any => { }, backend: { baseurl: - process.env.BACKEND_BASEURL || "https://test-os2iot-backend.os2iot.dk", + process.env.BACKEND_BASEURL || "https://localhost:3000", deviceStatsIntervalInDays: parseInt(process.env.DEVICE_STATS_INTERVAL_IN_DAYS, 10) || 29, }, kombit: { entryPoint: process.env.KOMBIT_ENTRYPOINT || - "https://adgangsstyring.eksterntest-stoettesystemerne.dk/runtime/saml2/issue.idp", + "https://adgangsstyring.eksterntest-stoettesystemerne.dk/runtime/saml2/issue.idp", certificatePublicKey: process.env.KOMBIT_CERTIFICATEPUBLICKEY || "INSERT_KOMBIT_CERT", // Public certificate from Kombit Test server certificatePrivateKey: process.env.KOMBIT_CERTIFICATEPRIVATEKEY || null, roleUri: @@ -32,6 +32,7 @@ export default (): any => { }, chirpstack: { jwtsecret: process.env.CHIRPSTACK_JWTSECRET || "verysecret", + apikey: process.env.CHIRPSTACK_API_KEY || "apikey" }, logLevels: process.env.LOG_LEVEL ? GetLogLevels(process.env.LOG_LEVEL) diff --git a/src/services/chirpstack/chirpstack-device.service.ts b/src/services/chirpstack/chirpstack-device.service.ts index 15f3da2c..83eadfe4 100644 --- a/src/services/chirpstack/chirpstack-device.service.ts +++ b/src/services/chirpstack/chirpstack-device.service.ts @@ -549,7 +549,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi req.setStart(from_time_timestamp); req.setEnd(to_time); req.setAggregation(Aggregation.DAY); - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const getDeviceMetricsPromise = new Promise( (resolve, reject) => { @@ -680,7 +680,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi client: DeviceServiceClient, request: GetDeviceKeysRequest ): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.getKeys(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -698,7 +698,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi } } async postKeys(client: DeviceServiceClient, request: CreateDeviceKeysRequest): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const createPromise = new Promise((resolve, reject) => { client.createKeys(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -717,7 +717,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi } } async putKeys(client: DeviceServiceClient, request: UpdateDeviceKeysRequest): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const updatePromise = new Promise((resolve, reject) => { client.updateKeys(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -740,7 +740,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi client: DeviceServiceClient, request: GetDeviceQueueItemsRequest ): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.getQueue(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -761,7 +761,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi client: DeviceServiceClient, request: FlushDeviceQueueRequest ): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.flushQueue(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -784,7 +784,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi client: DeviceServiceClient, request: EnqueueDeviceQueueItemRequest ): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const createPromise = new Promise((resolve, reject) => { client.enqueue(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -807,7 +807,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi client: DeviceServiceClient, request: GetDeviceActivationRequest ): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.getActivation(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -829,7 +829,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi client?: DeviceServiceClient, request?: ActivateDeviceRequest ): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const createPromise = new Promise((resolve, reject) => { client.activate(request, metaData, (err: ServiceError, resp: any) => { if (err) { diff --git a/src/services/chirpstack/chirpstack-gateway.service.ts b/src/services/chirpstack/chirpstack-gateway.service.ts index 02109bed..697c3976 100644 --- a/src/services/chirpstack/chirpstack-gateway.service.ts +++ b/src/services/chirpstack/chirpstack-gateway.service.ts @@ -274,7 +274,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ request.setEnd(to_time); request.setAggregation(Aggregation.DAY); - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const getGatewayMetricsPromise = new Promise( (resolve, reject) => { diff --git a/src/services/chirpstack/device-profile.service.ts b/src/services/chirpstack/device-profile.service.ts index 055c5ddd..a6cc1c68 100644 --- a/src/services/chirpstack/device-profile.service.ts +++ b/src/services/chirpstack/device-profile.service.ts @@ -337,7 +337,7 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService } async getAdrAlgorithms(): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const getPromise = new Promise( (resolve, reject) => { this.deviceProfileClient.listAdrAlgorithms( diff --git a/src/services/chirpstack/generic-chirpstack-configuration.service.ts b/src/services/chirpstack/generic-chirpstack-configuration.service.ts index dc2fd000..579514b5 100644 --- a/src/services/chirpstack/generic-chirpstack-configuration.service.ts +++ b/src/services/chirpstack/generic-chirpstack-configuration.service.ts @@ -5,14 +5,11 @@ import { Logger, NotFoundException, } from "@nestjs/common"; -import { AxiosRequestConfig } from "axios"; import { HeaderDto } from "@dto/chirpstack/header.dto"; import { AuthorizationType } from "@enum/authorization-type.enum"; import { JwtToken } from "./jwt-token"; import { ListAllChirpstackApplicationsResponseDto } from "@dto/chirpstack/list-all-applications-response.dto"; import { Metadata, ServiceError, credentials } from "@grpc/grpc-js"; -import { InternalServiceClient } from "@chirpstack/chirpstack-api/api/internal_grpc_pb"; -import { LoginRequest } from "@chirpstack/chirpstack-api/api/internal_pb"; import configuration from "@config/configuration"; import { TenantServiceClient } from "@chirpstack/chirpstack-api/api/tenant_grpc_pb"; import { ListTenantsRequest, ListTenantsResponse } from "@chirpstack/chirpstack-api/api/tenant_pb"; @@ -57,36 +54,17 @@ export class GenericChirpstackConfigurationService { return headerDto; } - - //TODO::: Should this be called once or in every function? If once, what if token expires? - async makeMetadataHeader(): Promise { - return new Promise((resolve, reject) => { - // Create the client for the 'internal' service - const internalServiceClient = new InternalServiceClient( - this.baseUrlGRPC, - credentials.createInsecure() - ); - - // Create and build the login request message - const loginRequest = new LoginRequest(); - loginRequest.setEmail("admin"); - loginRequest.setPassword(configuration()["chirpstack"]["password"]); - const metadata = new Metadata(); - - // Send the login request - internalServiceClient.login(loginRequest, (error: ServiceError, response: any) => { - if (error) { - reject(error); - } else { - metadata.set("authorization", "Bearer " + response.getJwt()); - resolve(metadata); - } - }); - }); + makeMetadataHeader(): Metadata { + const metadata = new Metadata(); + metadata.set( + "authorization", + "Bearer " + configuration()["chirpstack"]["apikey"], + ); + return metadata; } async post(endpoint: string, client?: any, request?: any): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const createPromise = new Promise((resolve, reject) => { client.create(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -105,7 +83,7 @@ export class GenericChirpstackConfigurationService { } } async put(endpoint: string, client?: any, request?: any): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const updatePromise = new Promise((resolve, reject) => { client.update(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -126,7 +104,7 @@ export class GenericChirpstackConfigurationService { } async getOneById(endpoint: string, id: string, client?: any, request?: any): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); request.setId(id); const getPromise = new Promise((resolve, reject) => { client.get(request, metaData, (err: ServiceError, resp: any) => { @@ -149,7 +127,7 @@ export class GenericChirpstackConfigurationService { async delete(endpoint: string, client?: any, request?: any): Promise { //MAYBE return boolean of result (succes vs failure) if (client) { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const deletePromise = new Promise((resolve, reject) => { client.delete(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -171,7 +149,7 @@ export class GenericChirpstackConfigurationService { } async get(endpoint: string, client?: any, request?: any): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.get(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -226,7 +204,7 @@ export class GenericChirpstackConfigurationService { client?: any, request?: any ): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); request.setLimit(limit), request.setOffset(offset); const getListPromise = new Promise((resolve, reject) => { diff --git a/src/services/chirpstack/multicast.service.ts b/src/services/chirpstack/multicast.service.ts index 1051e92b..1e3ad679 100644 --- a/src/services/chirpstack/multicast.service.ts +++ b/src/services/chirpstack/multicast.service.ts @@ -487,7 +487,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { client?: MulticastGroupServiceClient, request?: AddDeviceToMulticastGroupRequest ): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const createPromise = new Promise((resolve, reject) => { client.addDevice(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -653,7 +653,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { client: MulticastGroupServiceClient, request: ListMulticastGroupQueueRequest ): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.listQueue(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -675,7 +675,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { client: MulticastGroupServiceClient, request: FlushMulticastGroupQueueRequest ): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.flushQueue(request, metaData, (err: ServiceError, resp: any) => { if (err) { @@ -697,7 +697,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { client: MulticastGroupServiceClient, request: EnqueueMulticastGroupQueueItemRequest ): Promise { - const metaData = await this.makeMetadataHeader(); + const metaData = this.makeMetadataHeader(); const createPromise = new Promise((resolve, reject) => { client.enqueue(request, metaData, (err: ServiceError, resp: any) => { if (err) { From cd698e9dcc5f4e1095f6765c50ca2256086a2e2d Mon Sep 17 00:00:00 2001 From: August Andersen Date: Thu, 30 Nov 2023 14:52:03 +0100 Subject: [PATCH 04/24] cleanup --- src/entities/dto/chirpstack/header.dto.ts | 14 ----------- ...eneric-chirpstack-configuration.service.ts | 24 ------------------- 2 files changed, 38 deletions(-) delete mode 100644 src/entities/dto/chirpstack/header.dto.ts diff --git a/src/entities/dto/chirpstack/header.dto.ts b/src/entities/dto/chirpstack/header.dto.ts deleted file mode 100644 index bb36cbfd..00000000 --- a/src/entities/dto/chirpstack/header.dto.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ApiProperty } from "@nestjs/swagger"; -export class HeaderDto { - @ApiProperty({ required: true }) - url: string; - - @ApiProperty({ required: true }) - timeout: number; - - @ApiProperty({ required: true }) - authorizationType: string; - - @ApiProperty({ required: true }) - authorizationHeader: string; -} diff --git a/src/services/chirpstack/generic-chirpstack-configuration.service.ts b/src/services/chirpstack/generic-chirpstack-configuration.service.ts index 579514b5..f58912f6 100644 --- a/src/services/chirpstack/generic-chirpstack-configuration.service.ts +++ b/src/services/chirpstack/generic-chirpstack-configuration.service.ts @@ -5,9 +5,6 @@ import { Logger, NotFoundException, } from "@nestjs/common"; -import { HeaderDto } from "@dto/chirpstack/header.dto"; -import { AuthorizationType } from "@enum/authorization-type.enum"; -import { JwtToken } from "./jwt-token"; import { ListAllChirpstackApplicationsResponseDto } from "@dto/chirpstack/list-all-applications-response.dto"; import { Metadata, ServiceError, credentials } from "@grpc/grpc-js"; import configuration from "@config/configuration"; @@ -26,9 +23,6 @@ export class GenericChirpstackConfigurationService { baseUrlGRPC = `${process.env.CHIRPSTACK_HOSTNAME || "localhost"}:${ process.env.CHIRPSTACK_PORT || "8084" }`; - baseUrl = `http://${process.env.CHIRPSTACK_APPLICATION_SERVER_HOSTNAME || "localhost"}:${ - process.env.CHIRPSTACK_APPLICATION_SERVER_PORT || "8080" - }`; private readonly innerLogger = new Logger(GenericChirpstackConfigurationService.name); protected applicationServiceClient = new ApplicationServiceClient( @@ -36,24 +30,6 @@ export class GenericChirpstackConfigurationService { credentials.createInsecure() ); - setupHeader(endPoint: string, limit?: number, offset?: number): HeaderDto { - const timeoutMs = 30 * 1000; - let url = this.baseUrl + "/api/" + endPoint; - - // If limits are supplied, add these as query params - if (limit != null && offset != null) { - url += `${endPoint.indexOf("?") >= 0 ? "&" : "?"}limit=${limit}&offset=${offset}`; - } - - const headerDto: HeaderDto = { - url, - timeout: timeoutMs, - authorizationType: AuthorizationType.HEADER_BASED_AUTHORIZATION, - authorizationHeader: "Bearer " + JwtToken.setupToken(), - }; - - return headerDto; - } makeMetadataHeader(): Metadata { const metadata = new Metadata(); metadata.set( From 27fbde068243c98a62f28f6a825e68057760d6f4 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Fri, 8 Dec 2023 12:20:59 +0100 Subject: [PATCH 05/24] everything but gateways work --- package-lock.json | 7824 +---------------- .../chirpstack-many-device-response.ts | 3 - .../dto/chirpstack/gateway-response.dto.ts | 4 +- .../chirpstack/single-gateway-response.dto.ts | 4 +- .../chirpstack-administration.module.ts | 1 - .../chirpstack/chirpstack-device.service.ts | 114 +- .../chirpstack/chirpstack-gateway.service.ts | 176 +- .../chirpstack/gateway-boostrapper.service.ts | 16 +- .../gateway-status-history.service.ts | 13 +- .../device-management/application.service.ts | 3 +- .../device-management/iot-device.service.ts | 17 +- .../lorawan-device-database-enrich-job.ts | 21 +- 12 files changed, 354 insertions(+), 7842 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0ad7bac0..45e2179d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "os2iot-backend", "version": "0.0.1", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -9,8 +9,9 @@ "version": "0.0.1", "license": "Mozilla Public License Version 2.0", "dependencies": { - "@nestjs/axios": "^3.0.0", + "@chirpstack/chirpstack-api": "4.5.1", "@grpc/grpc-js": "1.9.9", + "@nestjs/axios": "^3.0.0", "@nestjs/common": "^9.1.2", "@nestjs/config": "^2.2.0", "@nestjs/core": "^9.1.2", @@ -22,7 +23,7 @@ "@nestjs/swagger": "^6.1.2", "@nestjs/typeorm": "^9.0.1", "@types/bcryptjs": "^2.4.2", - "@types/geojson": "^7946.0.7", + "@types/geojson": "^7946.0.13", "@types/kafkajs": "^1.9.0", "@types/passport-saml": "^1.1.3", "@types/pem": "^1.9.6", @@ -73,7 +74,7 @@ "@types/cron": "^1.7.2", "@types/crypto-js": "^4.1.1", "@types/express": "^4.17.9", - "@types/geojson": "^7946.0.7", + "@types/geojson": "^7946.0.13", "@types/kafkajs": "^1.9.0", "@types/lodash": "^4.14.165", "@types/node": "^14.14.14", @@ -415,6 +416,12 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", @@ -971,9 +978,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", - "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -994,9 +1001,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", - "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1031,11 +1038,6 @@ "node": ">=6" } }, - "node_modules/@grpc/proto-loader/node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, "node_modules/@grpc/proto-loader/node_modules/protobufjs": { "version": "7.2.5", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", @@ -1563,20 +1565,6 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@nestjs/axios": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-3.0.1.tgz", @@ -1666,6 +1654,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@nestjs/cli/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@nestjs/cli/node_modules/rimraf": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", @@ -2281,9 +2278,9 @@ "dev": true }, "node_modules/@types/google-protobuf": { - "version": "3.15.10", - "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.10.tgz", - "integrity": "sha512-uiyKJCa8hbmPE4yxwjbkMOALaBAiOVcatW/yEGbjTqwAh4kzNgQPWRlJMNPXpB5CPUM66xsYufiSX9WKHZCE9g==" + "version": "3.15.12", + "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.12.tgz", + "integrity": "sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ==" }, "node_modules/@types/graceful-fs": { "version": "4.1.9", @@ -2553,16 +2550,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.1.tgz", - "integrity": "sha512-5bQDGkXaxD46bPvQt08BUz9YSaO4S0fB1LB5JHQuXTfkGPI3+UUeS387C/e9jRie5GqT8u5kFTrMvAjtX4O5kA==", + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz", + "integrity": "sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.13.1", - "@typescript-eslint/type-utils": "6.13.1", - "@typescript-eslint/utils": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1", + "@typescript-eslint/scope-manager": "6.13.2", + "@typescript-eslint/type-utils": "6.13.2", + "@typescript-eslint/utils": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2588,15 +2585,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.1.tgz", - "integrity": "sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==", + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.2.tgz", + "integrity": "sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.13.1", - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/typescript-estree": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1", + "@typescript-eslint/scope-manager": "6.13.2", + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/typescript-estree": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2", "debug": "^4.3.4" }, "engines": { @@ -2616,13 +2613,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz", - "integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==", + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz", + "integrity": "sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1" + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2633,13 +2630,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.1.tgz", - "integrity": "sha512-A2qPlgpxx2v//3meMqQyB1qqTg1h1dJvzca7TugM3Yc2USDY+fsRBiojAEo92HO7f5hW5mjAUF6qobOPzlBCBQ==", + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz", + "integrity": "sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.13.1", - "@typescript-eslint/utils": "6.13.1", + "@typescript-eslint/typescript-estree": "6.13.2", + "@typescript-eslint/utils": "6.13.2", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -2660,9 +2657,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz", - "integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==", + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz", + "integrity": "sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2673,13 +2670,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz", - "integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==", + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz", + "integrity": "sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1", + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2700,17 +2697,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.1.tgz", - "integrity": "sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==", + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.2.tgz", + "integrity": "sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.13.1", - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/typescript-estree": "6.13.1", + "@typescript-eslint/scope-manager": "6.13.2", + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/typescript-estree": "6.13.2", "semver": "^7.5.4" }, "engines": { @@ -2725,12 +2722,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz", - "integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==", + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz", + "integrity": "sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.13.1", + "@typescript-eslint/types": "6.13.2", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2961,14 +2958,25 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", - "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", "devOptional": true, "engines": { "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -3138,19 +3146,6 @@ "node": ">=10" } }, - "node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -3428,9 +3423,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "dev": true, "funding": [ { @@ -3447,9 +3442,9 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, "bin": { @@ -3587,9 +3582,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001565", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz", - "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", + "version": "1.0.30001566", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", + "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", "dev": true, "funding": [ { @@ -3671,11 +3666,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -4425,9 +4415,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.600", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.600.tgz", - "integrity": "sha512-KD6CWjf1BnQG+NsXuyiTDDT1eV13sKuYsOUioXkQweYTQIbgHkXPry9K7M+7cKtYHnSUPitVaLrXYB1jTkkYrw==", + "version": "1.4.608", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.608.tgz", + "integrity": "sha512-J2f/3iIIm3Mo0npneITZ2UPe4B1bg8fTNrFjD8715F/k1BvbviRuqYGkET1PgprrczXYTHFvotbBOmUp6KE0uA==", "dev": true }, "node_modules/emittery": { @@ -4525,15 +4515,15 @@ } }, "node_modules/eslint": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", - "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.54.0", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -5369,6 +5359,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/google-protobuf": { + "version": "3.21.2", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", + "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -5380,11 +5375,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/google-protobuf": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", - "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -5438,11 +5428,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "node_modules/hasown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - }, "dependencies": { "function-bind": "^1.1.2" }, @@ -5497,6 +5491,18 @@ "node": ">= 0.8" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -5836,6 +5842,21 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", @@ -6747,9 +6768,9 @@ } }, "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" }, "node_modules/lru-cache": { "version": "7.18.3", @@ -6792,20 +6813,20 @@ } }, "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dependencies": { - "semver": "^7.5.3" + "semver": "^6.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-dir/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", @@ -6969,9 +6990,9 @@ } }, "node_modules/minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "engines": { "node": ">=8" } @@ -6998,11 +7019,6 @@ "engines": { "node": ">=8" } - }, - "dev": true, - "engines": { - "node": ">=8" - } }, "node_modules/mkdirp": { "version": "0.5.6", @@ -7030,9 +7046,9 @@ } }, "node_modules/mqtt": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.7.tgz", - "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==", + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.8.tgz", + "integrity": "sha512-2xT75uYa0kiPEF/PE0VPdavmEkoBzMT/UL9moid0rAvlCtV48qBwxD62m7Ld/4j8tSkIO1E/iqRl/S72SEOhOw==", "dependencies": { "commist": "^1.0.0", "concat-stream": "^2.0.0", @@ -7082,11 +7098,6 @@ "node": ">=10" } }, - "node_modules/mqtt/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -7205,9 +7216,9 @@ "integrity": "sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==" }, "node_modules/node-abi": { - "version": "3.51.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.51.0.tgz", - "integrity": "sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==", + "version": "3.52.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.52.0.tgz", + "integrity": "sha512-JJ98b02z16ILv7859irtXn4oUaFWADtvkzy2c0IAatNVX2Mc9Yoh8z6hZInn3QwvMEYhHuQloYi+TTQy67SIdQ==", "dependencies": { "semver": "^7.3.5" }, @@ -7675,15 +7686,6 @@ "node": "14 || >=16.14" } }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/path-to-regexp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", @@ -8061,6 +8063,11 @@ "pbts": "bin/pbts" } }, + "node_modules/protobufjs/node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -8242,9 +8249,9 @@ } }, "node_modules/reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", + "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" }, "node_modules/regenerator-runtime": { "version": "0.14.0", @@ -8469,11 +8476,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -8525,6 +8527,11 @@ "node": ">= 0.8.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, "node_modules/set-function-length": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", @@ -8610,8 +8617,7 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/simple-concat": { "version": "1.0.1", @@ -8955,7 +8961,7 @@ "node": ">=6" } }, - "node_modules/tar-fs": { + "node_modules/tar": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", @@ -8971,17 +8977,7 @@ "node": ">=10" } }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, + "node_modules/tar-fs": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", @@ -8992,6 +8988,11 @@ "tar-stream": "^2.1.4" } }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, "node_modules/tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", @@ -9007,10 +9008,21 @@ "node": ">=6" } }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/terser": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", - "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", + "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -10081,10 +10093,9 @@ } }, "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { "version": "1.10.2", @@ -10113,9 +10124,6 @@ } }, "node_modules/yargs-parser": { - }, - "engines": { - "node": ">=12" "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", @@ -10144,7447 +10152,5 @@ "url": "https://github.com/sponsors/sindresorhus" } } - }, - "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true - }, - "@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@angular-devkit/core": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.0.1.tgz", - "integrity": "sha512-2uz98IqkKJlgnHbWQ7VeL4pb+snGAZXIama2KXi+k9GsRntdcw+udX8rL3G9SdUGUF+m6+147Y1oRBMHsO/v4w==", - "dev": true, - "requires": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "@angular-devkit/schematics": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.0.1.tgz", - "integrity": "sha512-A9D0LTYmiqiBa90GKcSuWb7hUouGIbm/AHbJbjL85WLLRbQA2PwKl7P5Mpd6nS/ZC0kfG4VQY3VOaDvb3qpI9g==", - "dev": true, - "requires": { - "@angular-devkit/core": "16.0.1", - "jsonc-parser": "3.2.0", - "magic-string": "0.30.0", - "ora": "5.4.1", - "rxjs": "7.8.1" - } - }, - "@angular-devkit/schematics-cli": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-16.0.1.tgz", - "integrity": "sha512-6KLA125dpgd6oJGtiO2JpZAb92uOG3njQGIt7NFcuQGW/5GO7J41vMXH9cBAfdtbV8SIggSmR/cIEE9ijfj6YQ==", - "dev": true, - "requires": { - "@angular-devkit/core": "16.0.1", - "@angular-devkit/schematics": "16.0.1", - "ansi-colors": "4.1.3", - "inquirer": "8.2.4", - "symbol-observable": "4.0.0", - "yargs-parser": "21.1.1" - }, - "dependencies": { - "inquirer": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" - } - } - } - }, - "@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", - "dev": true - }, - "@babel/core": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", - "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.5", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.5", - "@babel/parser": "^7.23.5", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.5", - "convert-source-map": "^2.0.0", - "debug": "^4.3.4", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", - "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", - "dev": true, - "requires": { - "@babel/types": "^7.23.5", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "requires": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dev": true, - "requires": { - "@babel/types": "^7.22.15" - } - }, - "@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", - "dev": true - }, - "@babel/helpers": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", - "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", - "dev": true, - "requires": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.5" - } - }, - "@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", - "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - } - }, - "@babel/runtime": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", - "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", - "requires": { - "regenerator-runtime": "^0.14.0" - } - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - } - }, - "@babel/traverse": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", - "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.5", - "@babel/types": "^7.23.5", - "debug": "^4.3.4", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", - "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@chirpstack/chirpstack-api": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@chirpstack/chirpstack-api/-/chirpstack-api-4.5.1.tgz", - "integrity": "sha512-GAKb2/EAodgruOs4TF7la3EpZwXrlNJq8uQASvmRRTqFA4XUXsyna1BB+2QZmXxRt/VOA1POM/BsYUY47b2KIQ==", - "requires": { - "@grpc/grpc-js": "^1.9.0", - "@mapbox/node-pre-gyp": "^1.0.11", - "@types/google-protobuf": "^3.15.6", - "google-protobuf": "^3.21.2" - } - }, - "@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true - }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } - } - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", - "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.4", - "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": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", - "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", - "dev": true - }, - "@grpc/grpc-js": { - "version": "1.9.9", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.9.tgz", - "integrity": "sha512-vQ1qwi/Kiyprt+uhb1+rHMpyk4CVRMTGNUGGPRGS7pLNfWkdCHrGEnT6T3/JyC2VZgoOX/X1KwdoU0WYQAeYcQ==", - "requires": { - "@grpc/proto-loader": "^0.7.8", - "@types/node": ">=12.12.47" - } - }, - "@grpc/proto-loader": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", - "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", - "requires": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.4", - "yargs": "^17.7.2" - }, - "dependencies": { - "long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "protobufjs": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", - "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - } - } - } - }, - "@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.3.4", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dev": true, - "requires": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dev": true, - "requires": { - "@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.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.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, - "requires": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - } - }, - "@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, - "requires": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - } - }, - "@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "requires": { - "jest-get-type": "^29.6.3" - } - }, - "@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, - "requires": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - } - }, - "@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, - "requires": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - } - }, - "@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@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", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.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.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": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.27.8" - } - }, - "@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "requires": { - "@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": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, - "requires": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@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.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": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "requires": { - "@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": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "devOptional": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "devOptional": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "@lukeed/csprng": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", - "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==" - }, - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "dependencies": { - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@nestjs/axios": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-3.0.1.tgz", - "integrity": "sha512-VlOZhAGDmOoFdsmewn8AyClAdGpKXQQaY1+3PGB+g6ceurGIdTxZgRX3VXc1T6Zs60PedWjg3A82TDOB05mrzQ==", - "requires": {} - }, - "@nestjs/cli": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-9.5.0.tgz", - "integrity": "sha512-Z7q+3vNsQSG2d2r2Hl/OOj5EpfjVx3OfnJ9+KuAsOdw1sKLm7+Zc6KbhMFTd/eIvfx82ww3Nk72xdmfPYCulWA==", - "dev": true, - "requires": { - "@angular-devkit/core": "16.0.1", - "@angular-devkit/schematics": "16.0.1", - "@angular-devkit/schematics-cli": "16.0.1", - "@nestjs/schematics": "^9.0.4", - "chalk": "4.1.2", - "chokidar": "3.5.3", - "cli-table3": "0.6.3", - "commander": "4.1.1", - "fork-ts-checker-webpack-plugin": "8.0.0", - "inquirer": "8.2.5", - "node-emoji": "1.11.0", - "ora": "5.4.1", - "os-name": "4.0.1", - "rimraf": "4.4.1", - "shelljs": "0.8.5", - "source-map-support": "0.5.21", - "tree-kill": "1.2.2", - "tsconfig-paths": "4.2.0", - "tsconfig-paths-webpack-plugin": "4.0.1", - "typescript": "4.9.5", - "webpack": "^5.89.0", - "webpack-node-externals": "3.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "glob": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", - "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" - } - }, - "minimatch": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", - "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "rimraf": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", - "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", - "dev": true, - "requires": { - "glob": "^9.2.0" - } - } - } - }, - "@nestjs/common": { - "version": "9.4.3", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.4.3.tgz", - "integrity": "sha512-Gd6D4IaYj01o14Bwv81ukidn4w3bPHCblMUq+SmUmWLyosK+XQmInCS09SbDDZyL8jy86PngtBLTdhJ2bXSUig==", - "requires": { - "iterare": "1.2.1", - "tslib": "2.5.3", - "uid": "2.0.2" - } - }, - "@nestjs/config": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-2.3.4.tgz", - "integrity": "sha512-IGdSF+0F9MJO6dCRTEahdxPz4iVijjtolcFBxnY+2QYM3bXYQvAgzskGZi+WkAFJN/VzR3TEp60gN5sI74GxPA==", - "requires": { - "dotenv": "16.1.4", - "dotenv-expand": "10.0.0", - "lodash": "4.17.21", - "uuid": "9.0.0" - }, - "dependencies": { - "uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" - } - } - }, - "@nestjs/core": { - "version": "9.4.3", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.4.3.tgz", - "integrity": "sha512-Qi63+wi55Jh4sDyaj5Hhx2jOpKqT386aeo+VOKsxnd+Ql9VvkO/FjmuwBGUyzkJt29ENYc+P0Sx/k5LtstNpPQ==", - "requires": { - "@nuxtjs/opencollective": "0.3.2", - "fast-safe-stringify": "2.1.1", - "iterare": "1.2.1", - "path-to-regexp": "3.2.0", - "tslib": "2.5.3", - "uid": "2.0.2" - } - }, - "@nestjs/jwt": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-9.0.0.tgz", - "integrity": "sha512-ZsXGY/wMYKzEhymw2+dxiwrHTRKIKrGszx6r2EjQqNLypdXMQu0QrujwZJ8k3+XQV4snmuJwwNakQoA2ILfq8w==", - "requires": { - "@types/jsonwebtoken": "8.5.8", - "jsonwebtoken": "^9.0.0" - } - }, - "@nestjs/mapped-types": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-1.2.2.tgz", - "integrity": "sha512-3dHxLXs3M0GPiriAcCFFJQHoDFUuzTD5w6JDhE7TyfT89YKpe6tcCCIqOZWdXmt9AZjjK30RkHRSFF+QEnWFQg==", - "requires": {} - }, - "@nestjs/passport": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-9.0.3.tgz", - "integrity": "sha512-HplSJaimEAz1IOZEu+pdJHHJhQyBOPAYWXYHfAPQvRqWtw4FJF1VXl1Qtk9dcXQX1eKytDtH+qBzNQc19GWNEg==", - "requires": {} - }, - "@nestjs/platform-express": { - "version": "9.4.3", - "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-9.4.3.tgz", - "integrity": "sha512-FpdczWoRSC0zz2dNL9u2AQLXKXRVtq4HgHklAhbL59X0uy+mcxhlSThG7DHzDMkoSnuuHY8ojDVf7mDxk+GtCw==", - "requires": { - "body-parser": "1.20.2", - "cors": "2.8.5", - "express": "4.18.2", - "multer": "1.4.4-lts.1", - "tslib": "2.5.3" - } - }, - "@nestjs/schedule": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-2.2.3.tgz", - "integrity": "sha512-PxoGdoBwZQ6SzGfFcERTk7mDxrmesNt2cfqKgtLsFpjYNpV6ZYlKw9Ku8C0ZIjdhy0tBbysj+Fsi3sYua6o6Eg==", - "requires": { - "cron": "2.3.1", - "uuid": "9.0.0" - }, - "dependencies": { - "uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" - } - } - }, - "@nestjs/schematics": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-9.2.0.tgz", - "integrity": "sha512-wHpNJDPzM6XtZUOB3gW0J6mkFCSJilzCM3XrHI1o0C8vZmFE1snbmkIXNyoi1eV0Nxh1BMymcgz5vIMJgQtTqw==", - "dev": true, - "requires": { - "@angular-devkit/core": "16.0.1", - "@angular-devkit/schematics": "16.0.1", - "jsonc-parser": "3.2.0", - "pluralize": "8.0.0" - } - }, - "@nestjs/swagger": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-6.3.0.tgz", - "integrity": "sha512-Gnig189oa1tD+h0BYIfUwhp/wvvmTn6iO3csR2E4rQrDTgCxSxZDlNdfZo3AC+Rmf8u0KX4ZAX1RZN1qXTtC7A==", - "requires": { - "@nestjs/mapped-types": "1.2.2", - "js-yaml": "4.1.0", - "lodash": "4.17.21", - "path-to-regexp": "3.2.0", - "swagger-ui-dist": "4.18.2" - } - }, - "@nestjs/testing": { - "version": "9.4.3", - "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-9.4.3.tgz", - "integrity": "sha512-LDT8Ai2eKnTzvnPaJwWOK03qTaFap5uHHsJCv6dL0uKWk6hyF9jms8DjyVaGsaujCaXDG8izl1mDEER0OmxaZA==", - "dev": true, - "requires": { - "tslib": "2.5.3" - } - }, - "@nestjs/typeorm": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-9.0.1.tgz", - "integrity": "sha512-A2BgLIPsMtmMI0bPKEf4bmzgFPsnvHqNBx3KkvaJ7hJrBQy0OqYOb+Rr06ifblKWDWS2tUPNrAFQbZjtk3PI+g==", - "requires": { - "uuid": "8.3.2" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@nuxtjs/opencollective": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", - "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==", - "requires": { - "chalk": "^4.1.0", - "consola": "^2.15.0", - "node-fetch": "^2.6.1" - } - }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0" - } - }, - "@sqltools/formatter": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", - "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "devOptional": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true - }, - "@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true - }, - "@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "requires": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.7", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", - "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", - "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", - "dev": true, - "requires": { - "@babel/types": "^7.20.7" - } - }, - "@types/bcryptjs": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz", - "integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==", - "dev": true - }, - "@types/bluebird": { - "version": "3.5.42", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.42.tgz", - "integrity": "sha512-Jhy+MWRlro6UjVi578V/4ZGNfeCOcNCp0YaFNIUGFKlImowqwb1O/22wDVk3FDGMLqxdpOV3qQHD5fPEH4hK6A==", - "dev": true - }, - "@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/cache-manager": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/cache-manager/-/cache-manager-4.0.6.tgz", - "integrity": "sha512-8qL93MF05/xrzFm/LSPtzNEOE1eQF3VwGHAcQEylgp5hDSTe41jtFwbSYAPfyYcVa28y1vYSjIt0c1fLLUiC/Q==", - "dev": true - }, - "@types/compression": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", - "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", - "dev": true, - "requires": { - "@types/express": "*" - } - }, - "@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-KoooCrD56qlLskXPLGUiJxOMnv5l/8m7cQD2OxJ73NPMhuSz9PmvwRD6EpjDyKBVrdJDdQ4bQK7JFNHnNmax0w==", - "dev": true, - "requires": { - "@types/express": "*" - } - }, - "@types/cookiejar": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", - "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", - "dev": true - }, - "@types/cron": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@types/cron/-/cron-1.7.3.tgz", - "integrity": "sha512-iPmUXyIJG1Js+ldPYhOQcYU3kCAQ2FWrSkm1FJPoii2eYSn6wEW6onPukNTT0bfiflexNSRPl6KWmAIqS+36YA==", - "dev": true, - "requires": { - "@types/node": "*", - "moment": ">=2.14.0" - } - }, - "@types/crypto-js": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.1.tgz", - "integrity": "sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw==", - "dev": true - }, - "@types/eslint": { - "version": "8.44.8", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.8.tgz", - "integrity": "sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.41", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", - "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "@types/geojson": { - "version": "7946.0.13", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz", - "integrity": "sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ==", - "dev": true - }, - "@types/google-protobuf": { - "version": "3.15.10", - "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.10.tgz", - "integrity": "sha512-uiyKJCa8hbmPE4yxwjbkMOALaBAiOVcatW/yEGbjTqwAh4kzNgQPWRlJMNPXpB5CPUM66xsYufiSX9WKHZCE9g==" - }, - "@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "@types/jsonwebtoken": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.8.tgz", - "integrity": "sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A==", - "requires": { - "@types/node": "*" - } - }, - "@types/kafkajs": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@types/kafkajs/-/kafkajs-1.9.0.tgz", - "integrity": "sha512-R9VDNbiw+vNfxWjjFHUrLMF/Dfc7asGXzKtYUwI4FaT24Chf5ZNkfvce54p4dkLMxPcsrEsVazAK0Jp2ib4Zxw==", - "dev": true, - "requires": { - "kafkajs": "*" - } - }, - "@types/lodash": { - "version": "4.14.202", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", - "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", - "dev": true - }, - "@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" - }, - "@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==" - }, - "@types/nodemailer": { - "version": "6.4.14", - "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.14.tgz", - "integrity": "sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "dev": true - }, - "@types/passport": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.16.tgz", - "integrity": "sha512-FD0qD5hbPWQzaM0wHUnJ/T0BBCJBxCeemtnCwc/ThhTg3x9jfrAcRUmj5Dopza+MfFS9acTe3wk7rcVnRIp/0A==", - "dev": true, - "requires": { - "@types/express": "*" - } - }, - "@types/passport-jwt": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-3.0.13.tgz", - "integrity": "sha512-fjHaC6Bv8EpMMqzTnHP32SXlZGaNfBPC/Po5dmRGYi2Ky7ljXPbGnOy+SxZqa6iZvFgVhoJ1915Re3m93zmcfA==", - "dev": true, - "requires": { - "@types/express": "*", - "@types/jsonwebtoken": "*", - "@types/passport-strategy": "*" - } - }, - "@types/passport-local": { - "version": "1.0.38", - "resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.38.tgz", - "integrity": "sha512-nsrW4A963lYE7lNTv9cr5WmiUD1ibYJvWrpE13oxApFsRt77b0RdtZvKbCdNIY4v/QZ6TRQWaDDEwV1kCTmcXg==", - "dev": true, - "requires": { - "@types/express": "*", - "@types/passport": "*", - "@types/passport-strategy": "*" - } - }, - "@types/passport-saml": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@types/passport-saml/-/passport-saml-1.1.7.tgz", - "integrity": "sha512-pMKJvWlS06ZGXtWVbfULSYDYv9XlvDBhCmzkbuYOqfeVqfpgr2SJKRKvAZ3RK0TzNE2vO67WRSnMbPPz68TyEg==", - "dev": true, - "requires": { - "@types/express": "*", - "@types/passport": "*" - } - }, - "@types/passport-strategy": { - "version": "0.2.38", - "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz", - "integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==", - "dev": true, - "requires": { - "@types/express": "*", - "@types/passport": "*" - } - }, - "@types/pem": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/@types/pem/-/pem-1.14.4.tgz", - "integrity": "sha512-Xt6qY6kX1RD4UmYNhWCCf3OSJrRcwbQIaJ/mQSjjAHxIjXMHx/vHNPOgEU3HdVKS1k/U5CZ6ClQlRo8egkl8xg==", - "requires": { - "@types/node": "*" - } - }, - "@types/qs": { - "version": "6.9.10", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", - "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", - "dev": true - }, - "@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", - "dev": true, - "requires": { - "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true - }, - "@types/superagent": { - "version": "4.1.24", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.24.tgz", - "integrity": "sha512-mEafCgyKiMFin24SDzWN7yAADt4gt6YawFiNMp0QS5ZPboORfyxFt0s3VzJKhTaKg9py/4FUmrHLTNfJKt9Rbw==", - "dev": true, - "requires": { - "@types/cookiejar": "*", - "@types/node": "*" - } - }, - "@types/supertest": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.16.tgz", - "integrity": "sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg==", - "dev": true, - "requires": { - "@types/superagent": "*" - } - }, - "@types/uuid": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", - "dev": true - }, - "@types/validator": { - "version": "13.11.7", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz", - "integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==" - }, - "@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/xml2js": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz", - "integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.1.tgz", - "integrity": "sha512-5bQDGkXaxD46bPvQt08BUz9YSaO4S0fB1LB5JHQuXTfkGPI3+UUeS387C/e9jRie5GqT8u5kFTrMvAjtX4O5kA==", - "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.13.1", - "@typescript-eslint/type-utils": "6.13.1", - "@typescript-eslint/utils": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - } - }, - "@typescript-eslint/parser": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.1.tgz", - "integrity": "sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "6.13.1", - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/typescript-estree": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz", - "integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1" - } - }, - "@typescript-eslint/type-utils": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.1.tgz", - "integrity": "sha512-A2qPlgpxx2v//3meMqQyB1qqTg1h1dJvzca7TugM3Yc2USDY+fsRBiojAEo92HO7f5hW5mjAUF6qobOPzlBCBQ==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "6.13.1", - "@typescript-eslint/utils": "6.13.1", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - } - }, - "@typescript-eslint/types": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz", - "integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz", - "integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - } - }, - "@typescript-eslint/utils": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.1.tgz", - "integrity": "sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.13.1", - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/typescript-estree": "6.13.1", - "semver": "^7.5.4" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz", - "integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "6.13.1", - "eslint-visitor-keys": "^3.4.1" - } - }, - "@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", - "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", - "dev": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", - "dev": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", - "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", - "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", - "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", - "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", - "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", - "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "@xmldom/xmldom": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz", - "integrity": "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==" - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "devOptional": true - }, - "acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, - "requires": {} - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", - "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", - "devOptional": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "requires": { - "ajv": "^8.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "app-root-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", - "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==" - }, - "append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" - }, - "aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" - }, - "are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true - }, - "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", - "requires": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "axios-cache-adapter": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/axios-cache-adapter/-/axios-cache-adapter-2.7.3.tgz", - "integrity": "sha512-A+ZKJ9lhpjthOEp4Z3QR/a9xC4du1ALaAsejgRGrH9ef6kSDxdFrhRpulqsh9khsEnwXxGfgpUuDp1YXMNMEiQ==", - "requires": { - "cache-control-esm": "1.0.0", - "md5": "^2.2.1" - } - }, - "babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, - "requires": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "dependencies": { - "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@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-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@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-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "^4.3.4", - "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.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "buffer-writer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", - "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" - }, - "busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "requires": { - "streamsearch": "^1.1.0" - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "cache-control-esm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cache-control-esm/-/cache-control-esm-1.0.0.tgz", - "integrity": "sha512-Fa3UV4+eIk4EOih8FTV6EEsVKO0W5XWtNs6FC3InTfVz+EjurjPfDXY5wZDo/lxjDxg5RjNcurLyxEJBcEUx9g==" - }, - "cache-manager": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-4.1.0.tgz", - "integrity": "sha512-ZGM6dLxrP65bfOZmcviWMadUOCICqpLs92+P/S5tj8onz+k+tB7Gr+SAgOUHCQtfm2gYEQDHiKeul4+tYPOJ8A==", - "requires": { - "async": "3.2.3", - "lodash.clonedeep": "^4.5.0", - "lru-cache": "^7.10.1" - } - }, - "call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "requires": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001565", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz", - "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==" - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true - }, - "ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true - }, - "class-transformer": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", - "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" - }, - "class-validator": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz", - "integrity": "sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==", - "requires": { - "@types/validator": "^13.7.10", - "libphonenumber-js": "^1.10.14", - "validator": "^13.7.0" - } - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-highlight": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", - "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", - "requires": { - "chalk": "^4.0.0", - "highlight.js": "^10.7.1", - "mz": "^2.4.0", - "parse5": "^5.1.1", - "parse5-htmlparser2-tree-adapter": "^6.0.0", - "yargs": "^16.0.0" - }, - "dependencies": { - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "6.0.0-alpha.0", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" - } - } - }, - "cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true - }, - "cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", - "dev": true, - "requires": { - "@colors/colors": "1.5.0", - "string-width": "^4.2.0" - } - }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true - }, - "commist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz", - "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", - "requires": { - "leven": "^2.1.0", - "minimist": "^1.1.0" - }, - "dependencies": { - "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==" - } - } - }, - "component-emitter": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", - "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", - "dev": true - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "^4.3.4", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "consola": { - "version": "2.15.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", - "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, - "content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" - }, - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" - }, - "cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", - "requires": { - "cookie": "0.4.1", - "cookie-signature": "1.0.6" - } - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "cookiejar": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", - "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", - "dev": true - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, - "cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - } - }, - "create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, - "requires": { - "@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" - } - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true - }, - "cron": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/cron/-/cron-2.3.1.tgz", - "integrity": "sha512-1eRRlIT0UfIqauwbG9pkg3J6CX9A6My2ytJWqAXoK0T9oJnUZTzGBNPxao0zjodIbPgf8UQWjE62BMb9eVllSQ==", - "requires": { - "luxon": "^3.2.1" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==" - }, - "crypto-js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", - "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" - }, - "date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "requires": { - "@babel/runtime": "^7.21.0" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "requires": { - "mimic-response": "^3.1.0" - } - }, - "dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", - "dev": true, - "requires": {} - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true - }, - "defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "requires": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "detect-libc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==" - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "dev": true, - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true - }, - "diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dotenv": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.1.4.tgz", - "integrity": "sha512-m55RtE8AsPeJBpOIFKihEmqUcoVncQIwo7x9U8ZwLEZw9ZpXboz2c+rvog+jUaJvVrZ5kBOeYQBX5+8Aa/OZQw==" - }, - "dotenv-expand": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", - "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==" - }, - "duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "requires": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "electron-to-chromium": { - "version": "1.4.600", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.600.tgz", - "integrity": "sha512-KD6CWjf1BnQG+NsXuyiTDDT1eV13sKuYsOUioXkQweYTQIbgHkXPry9K7M+7cKtYHnSUPitVaLrXYB1jTkkYrw==", - "dev": true - }, - "emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", - "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", - "dev": true - }, - "es6-promisify": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-7.0.0.tgz", - "integrity": "sha512-ginqzK3J90Rd4/Yz7qRrqUeIpe3TwSXTPPZtPne7tGBPeAaQiU8qt4fpKApnxHcq1AwtUdHVg5P77x/yrggG8Q==" - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", - "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.54.0", - "@humanwhocodes/config-array": "^0.11.13", - "@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.4", - "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" - }, - "dependencies": { - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - } - } - }, - "eslint-config-prettier": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", - "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", - "dev": true, - "requires": {} - }, - "eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true - }, - "espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "requires": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" - }, - "expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "requires": { - "@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": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "^4.3.4", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "^4.3.4", - "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", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - } - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "requires": { - "@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" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - } - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "^4.3.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "requires": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true - }, - "follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" - }, - "fork-ts-checker-webpack-plugin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz", - "integrity": "sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "cosmiconfig": "^7.0.1", - "deepmerge": "^4.2.2", - "fs-extra": "^10.0.0", - "memfs": "^3.4.1", - "minimatch": "^3.0.4", - "node-abort-controller": "^3.0.1", - "schema-utils": "^3.1.1", - "semver": "^7.3.5", - "tapable": "^2.2.1" - } - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "formidable": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", - "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", - "dev": true, - "requires": { - "dezalgo": "^1.0.4", - "hexoid": "^1.0.0", - "once": "^1.4.0", - "qs": "^6.11.0" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "fs-monkey": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", - "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" - }, - "gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - } - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "requires": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - } - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "google-protobuf": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", - "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "requires": { - "get-intrinsic": "^1.2.2" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - }, - "requires": { - "function-bind": "^1.1.2" - } - }, - "help-me": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/help-me/-/help-me-3.0.0.tgz", - "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==", - "requires": { - "glob": "^7.1.6", - "readable-stream": "^3.6.0" - } - }, - "hexoid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", - "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", - "dev": true - }, - "highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "inquirer": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", - "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" - } - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "requires": { - "hasown": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "isolated-vm": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-4.6.0.tgz", - "integrity": "sha512-MEnfC/54q5PED3VJ9UJYJPOlU6mYFHS3ivR9E8yeNNBEFRFUNBnY0xO4Rj3D/SOtFKPNmsQp9NWUYSKZqAoZiA==", - "requires": { - "prebuild-install": "^7.1.1" - } - }, - "istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", - "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - } - }, - "istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.3.4", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "iterare": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", - "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==" - }, - "jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", - "dev": true, - "requires": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - } - }, - "jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - } - }, - "jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", - "dev": true, - "requires": { - "@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": "^1.0.0", - "is-generator-fn": "^2.0.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.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, - "requires": { - "@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", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - } - }, - "jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@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.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.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - } - }, - "jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - } - }, - "jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", - "dev": true, - "requires": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - } - }, - "jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "dev": true, - "requires": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - } - }, - "jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true - }, - "jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, - "requires": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", - "dev": true, - "requires": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - } - }, - "jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - } - }, - "jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@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.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "dev": true, - "requires": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - } - }, - "jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true - }, - "jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - } - }, - "jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", - "dev": true, - "requires": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - } - }, - "jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", - "dev": true, - "requires": { - "@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.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" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - } - } - }, - "jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", - "dev": true, - "requires": { - "@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.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": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, - "requires": { - "@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/types": "^7.3.3", - "@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.7.0", - "graceful-fs": "^4.2.9", - "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.7.0", - "semver": "^7.5.3" - } - }, - "jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "requires": { - "@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": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "requires": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", - "dev": true, - "requires": { - "@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.7.0", - "string-length": "^4.0.1" - } - }, - "jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", - "requires": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "kafkajs": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/kafkajs/-/kafkajs-2.2.4.tgz", - "integrity": "sha512-j/YeapB1vfPT2iOIUn/vxdyKEuhuY2PxMBvf5JWux6iSaukAccrMtXEY/Lb7OvavDhOWME589bpLrEdnVHjfjA==" - }, - "keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "libphonenumber-js": { - "version": "1.10.51", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.51.tgz", - "integrity": "sha512-vY2I+rQwrDQzoPds0JeTEpeWzbUJgqoV0O4v31PauHBb/e+1KCXKylHcDnBMgJZ9fH9mErsEbROJY3Z3JtqEmg==" - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" - }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" - }, - "luxon": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", - "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==" - }, - "macos-release": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", - "integrity": "sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==", - "dev": true - }, - "magic-string": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", - "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.4.13" - } - }, - "make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "requires": { - "semver": "^7.5.3" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "md5": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", - "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", - "requires": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "~1.1.6" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" - }, - "memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "dev": true, - "requires": { - "fs-monkey": "^1.0.4" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" - }, - "minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", - "dev": true - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "requires": { - "minimist": "^1.2.6" - } - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, - "moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "dev": true - }, - "mqtt": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.7.tgz", - "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==", - "requires": { - "commist": "^1.0.0", - "concat-stream": "^2.0.0", - "debug": "^4.3.4", - "duplexify": "^4.1.1", - "help-me": "^3.0.0", - "inherits": "^2.0.3", - "lru-cache": "^6.0.0", - "minimist": "^1.2.5", - "mqtt-packet": "^6.8.0", - "number-allocator": "^1.0.9", - "pump": "^3.0.0", - "readable-stream": "^3.6.0", - "reinterval": "^1.1.0", - "rfdc": "^1.3.0", - "split2": "^3.1.0", - "ws": "^7.5.5", - "xtend": "^4.0.2" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "mqtt-packet": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.10.0.tgz", - "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", - "requires": { - "bl": "^4.0.2", - "debug": "^4.3.4", - "process-nextick-args": "^2.0.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "multer": { - "version": "1.4.4-lts.1", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", - "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==", - "requires": { - "append-field": "^1.0.0", - "busboy": "^1.0.0", - "concat-stream": "^1.5.2", - "mkdirp": "^0.5.4", - "object-assign": "^4.1.1", - "type-is": "^1.6.4", - "xtend": "^4.0.0" - }, - "dependencies": { - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "njwt": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/njwt/-/njwt-1.2.0.tgz", - "integrity": "sha512-i+cdqwxo7EUimJCHPSAEpQEWrz4ilsVefL+FRhWrjMqq8HHiQ8dwi9GUWUfj3Vt6XMY2PXSjMn9JeVB3/Jp6pg==", - "requires": { - "@types/node": "^15.0.1", - "ecdsa-sig-formatter": "^1.0.5", - "uuid": "^8.3.2" - }, - "dependencies": { - "@types/node": { - "version": "15.14.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.9.tgz", - "integrity": "sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==" - } - } - }, - "node-abi": { - "version": "3.51.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.51.0.tgz", - "integrity": "sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==", - "requires": { - "semver": "^7.3.5" - } - }, - "node-abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", - "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", - "dev": true - }, - "node-emoji": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", - "dev": true, - "requires": { - "lodash": "^4.17.21" - } - }, - "node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true - }, - "nodemailer": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.7.tgz", - "integrity": "sha512-rUtR77ksqex/eZRLmQ21LKVH5nAAsVicAtAYudK7JgwenEDZ0UIQ1adUGqErz7sMkWYxWTTU1aeP2Jga6WQyJw==" - }, - "nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "requires": { - "abbrev": "1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "requires": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "number-allocator": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz", - "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==", - "requires": { - "debug": "^4.3.4", - "js-sdsl": "4.3.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "requires": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - } - }, - "ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "requires": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - } - }, - "os-name": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/os-name/-/os-name-4.0.1.tgz", - "integrity": "sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw==", - "dev": true, - "requires": { - "macos-release": "^2.5.0", - "windows-release": "^4.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "packet-reader": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", - "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" - }, - "parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "requires": { - "parse5": "^6.0.1" - }, - "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - } - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "passport": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", - "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", - "requires": { - "passport-strategy": "1.x.x", - "pause": "0.0.1", - "utils-merge": "^1.0.1" - } - }, - "passport-headerapikey": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/passport-headerapikey/-/passport-headerapikey-1.2.2.tgz", - "integrity": "sha512-4BvVJRrWsNJPrd3UoZfcnnl4zvUWYKEtfYkoDsaOKBsrWHYmzTApCjs7qUbncOLexE9ul0IRiYBFfBG0y9IVQA==", - "requires": { - "lodash": "^4.17.15", - "passport-strategy": "^1.0.0" - } - }, - "passport-jwt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", - "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", - "requires": { - "jsonwebtoken": "^9.0.0", - "passport-strategy": "^1.0.0" - } - }, - "passport-local": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", - "integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==", - "requires": { - "passport-strategy": "1.x.x" - } - }, - "passport-saml": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/passport-saml/-/passport-saml-3.2.4.tgz", - "integrity": "sha512-JSgkFXeaexLNQh1RrOvJAgjLnZzH/S3HbX/mWAk+i7aulnjqUe7WKnPl1NPnJWqP7Dqsv0I2Xm6KIFHkftk0HA==", - "requires": { - "@xmldom/xmldom": "^0.7.6", - "debug": "^4.3.4", - "passport-strategy": "^1.0.0", - "xml-crypto": "^2.1.3", - "xml-encryption": "^2.0.0", - "xml2js": "^0.6.2", - "xmlbuilder": "^15.1.1" - } - }, - "passport-strategy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", - "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==" - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", - "dev": true, - "requires": { - "lru-cache": "^9.1.1 || ^10.0.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", - "dev": true - }, - "minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true - } - } - }, - "path-to-regexp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", - "integrity": "sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==" - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pause": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", - "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" - }, - "pem": { - "version": "1.14.8", - "resolved": "https://registry.npmjs.org/pem/-/pem-1.14.8.tgz", - "integrity": "sha512-ZpbOf4dj9/fQg5tQzTqv4jSKJQsK7tPl0pm4/pvPcZVjZcJg7TMfr3PBk6gJH97lnpJDu4e4v8UUqEz5daipCg==", - "requires": { - "es6-promisify": "^7.0.0", - "md5": "^2.3.0", - "os-tmpdir": "^1.0.2", - "which": "^2.0.2" - } - }, - "pg": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", - "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", - "requires": { - "buffer-writer": "2.0.0", - "packet-reader": "1.0.0", - "pg-cloudflare": "^1.1.1", - "pg-connection-string": "^2.6.2", - "pg-pool": "^3.6.1", - "pg-protocol": "^1.6.0", - "pg-types": "^2.1.0", - "pgpass": "1.x" - } - }, - "pg-cloudflare": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", - "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", - "optional": true - }, - "pg-connection-string": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", - "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" - }, - "pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" - }, - "pg-pool": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", - "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", - "requires": {} - }, - "pg-protocol": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", - "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" - }, - "pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "requires": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - } - }, - "pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "requires": { - "split2": "^4.1.0" - }, - "dependencies": { - "split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" - } - } - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true - }, - "postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" - }, - "postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" - }, - "postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" - }, - "postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "requires": { - "xtend": "^4.0.0" - } - }, - "prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", - "requires": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true - }, - "pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "protobufjs": { - "version": "6.11.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", - "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": ">=13.7.0", - "long": "^4.0.0" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" - }, - "pure-rand": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", - "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", - "dev": true - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" - } - } - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" - }, - "regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" - }, - "reinterval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", - "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "requires": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" - }, - "schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "^4.3.4", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "requires": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" - }, - "simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "requires": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "requires": { - "readable-stream": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "superagent": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", - "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", - "dev": true, - "requires": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.4", - "debug": "^4.3.4", - "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", - "formidable": "^2.1.2", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.11.0", - "semver": "^7.3.8" - }, - "dependencies": { - "mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true - } - } - }, - "supertest": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", - "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", - "dev": true, - "requires": { - "methods": "^1.1.2", - "superagent": "^8.0.5" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "swagger-ui-dist": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.18.2.tgz", - "integrity": "sha512-oVBoBl9Dg+VJw8uRWDxlyUyHoNEDC0c1ysT6+Boy6CTgr2rUcLcfPon4RvxgS2/taNW6O0+US+Z/dlAsWFjOAQ==" - }, - "swagger-ui-express": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.3.tgz", - "integrity": "sha512-CDje4PndhTD2HkgyKH3pab+LKspDeB/NhPN2OF1j+piYIamQqBYwAXWESOT1Yju2xFg51bRW9sUng2WxDjzArw==", - "requires": { - "swagger-ui-dist": ">=4.11.0" - } - }, - "symbol-observable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", - "dev": true - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - }, - "tar-fs": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - } - } - }, - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, - "terser": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", - "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", - "dev": true, - "requires": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - } - } - }, - "terser-webpack-plugin": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", - "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.17", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.16.8" - }, - "dependencies": { - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true - }, - "ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", - "dev": true, - "requires": {} - }, - "ts-jest": { - "version": "29.1.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", - "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" - } - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "devOptional": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - } - }, - "tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "requires": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - } - } - }, - "tsconfig-paths-webpack-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.0.1.tgz", - "integrity": "sha512-m5//KzLoKmqu2MVix+dgLKq70MnFi8YL8sdzQZ6DblmCdfuq/y3OqvJd5vMndg2KEVCOeNz8Es4WVZhYInteLw==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.7.0", - "tsconfig-paths": "^4.1.2" - } - }, - "tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" - }, - "typeorm": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.17.tgz", - "integrity": "sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig==", - "requires": { - "@sqltools/formatter": "^1.2.5", - "app-root-path": "^3.1.0", - "buffer": "^6.0.3", - "chalk": "^4.1.2", - "cli-highlight": "^2.1.11", - "date-fns": "^2.29.3", - "debug": "^4.3.4", - "dotenv": "^16.0.3", - "glob": "^8.1.0", - "mkdirp": "^2.1.3", - "reflect-metadata": "^0.1.13", - "sha.js": "^2.4.11", - "tslib": "^2.5.0", - "uuid": "^9.0.0", - "yargs": "^17.6.2" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "requires": { - "balanced-match": "^1.0.0" - } - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "mkdirp": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", - "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==" - }, - "uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" - } - } - }, - "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "devOptional": true - }, - "uid": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", - "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", - "requires": { - "@lukeed/csprng": "^1.0.0" - } - }, - "universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" - }, - "update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true - }, - "v8-to-istanbul": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", - "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - } - }, - "validator": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", - "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" - }, - "wait-for-expect": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-3.0.2.tgz", - "integrity": "sha512-cfS1+DZxuav1aBYbaO/kE06EOS8yRw7qOFoD3XtjTkYvCvh3zUvNST8DXK/nPaeqIzIv3P3kL3lRJn8iwOiSag==" - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "webpack": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", - "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - } - } - }, - "webpack-node-externals": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz", - "integrity": "sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==", - "dev": true - }, - "webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" - } - }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "windows-release": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", - "integrity": "sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==", - "dev": true, - "requires": { - "execa": "^4.0.2" - }, - "dependencies": { - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true - } - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "requires": {} - }, - "xml-crypto": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-2.1.5.tgz", - "integrity": "sha512-xOSJmGFm+BTXmaPYk8pPV3duKo6hJuZ5niN4uMzoNcTlwYs0jAu/N3qY+ud9MhE4N7eMRuC1ayC7Yhmb7MmAWg==", - "requires": { - "@xmldom/xmldom": "^0.7.9", - "xpath": "0.0.32" - } - }, - "xml-encryption": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xml-encryption/-/xml-encryption-2.0.0.tgz", - "integrity": "sha512-4Av83DdvAgUQQMfi/w8G01aJshbEZP9ewjmZMpS9t3H+OCZBDvyK4GJPnHGfWiXlArnPbYvR58JB9qF2x9Ds+Q==", - "requires": { - "@xmldom/xmldom": "^0.7.0", - "escape-html": "^1.0.3", - "xpath": "0.0.32" - } - }, - "xml2js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", - "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "dependencies": { - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" - } - } - }, - "xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==" - }, - "xpath": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz", - "integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==" - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "6.0.0-alpha.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-6.0.0-alpha.0.tgz", - "integrity": "sha512-J9CO+Qo98a30YwPMgXt1IetZS4823Y+KzBEWHPQYaO2sWcwtvVascTF0eNdUgU0Me3Efl36PnCygmVPdzqQmJg==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true - }, - "yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "6.0.0-alpha.0", - "yargs-parser": "^21.1.1" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } } } diff --git a/src/entities/dto/chirpstack/chirpstack-many-device-response.ts b/src/entities/dto/chirpstack/chirpstack-many-device-response.ts index 1d245102..9c0f1de2 100644 --- a/src/entities/dto/chirpstack/chirpstack-many-device-response.ts +++ b/src/entities/dto/chirpstack/chirpstack-many-device-response.ts @@ -1,15 +1,12 @@ export interface ChirpstackManyDeviceResponseContents { devEUI: string; name: string; - applicationID: string; description: string; deviceProfileID: string; deviceProfileName: string; deviceStatusBattery: number; deviceStatusMargin: number; deviceStatusExternalPowerSource: boolean; - deviceStatusBatteryLevelUnavailable: boolean; - deviceStatusBatteryLevel: number; lastSeenAt?: Date; } diff --git a/src/entities/dto/chirpstack/gateway-response.dto.ts b/src/entities/dto/chirpstack/gateway-response.dto.ts index 58df2da2..a77f87ad 100644 --- a/src/entities/dto/chirpstack/gateway-response.dto.ts +++ b/src/entities/dto/chirpstack/gateway-response.dto.ts @@ -1,5 +1,6 @@ import { Location } from "@chirpstack/chirpstack-api/common/common_pb"; import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; +import { CommonLocationDto } from "./common-location.dto"; export class GatewayResponseGrpcDto { id: number; @@ -10,11 +11,12 @@ export class GatewayResponseGrpcDto { txPacketsEmitted: number; organizationId: number; organizationName: string; - location?: Location.AsObject; + location: CommonLocationDto; createdAt?: Timestamp.AsObject; updatedAt?: Timestamp.AsObject; lastSeenAt?: Timestamp.AsObject; internalOrganizationId?: number; updatedBy?: number; createdBy?: number; + tags: { [id: string]: string }; } diff --git a/src/entities/dto/chirpstack/single-gateway-response.dto.ts b/src/entities/dto/chirpstack/single-gateway-response.dto.ts index 9431419f..f3f99e9a 100644 --- a/src/entities/dto/chirpstack/single-gateway-response.dto.ts +++ b/src/entities/dto/chirpstack/single-gateway-response.dto.ts @@ -1,8 +1,8 @@ import { GatewayStatsElementDto } from "@dto/chirpstack/gateway-stats.response.dto"; -import { GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto"; +import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; export class SingleGatewayResponseDto { - gateway: GatewayResponseDto; + gateway: GatewayResponseGrpcDto; stats?: GatewayStatsElementDto[]; } diff --git a/src/modules/device-integrations/chirpstack-administration.module.ts b/src/modules/device-integrations/chirpstack-administration.module.ts index f7f95503..a2a6e4cd 100644 --- a/src/modules/device-integrations/chirpstack-administration.module.ts +++ b/src/modules/device-integrations/chirpstack-administration.module.ts @@ -10,7 +10,6 @@ import { ChirpstackDeviceService } from "@services/chirpstack/chirpstack-device. import { ChirpstackGatewayService } from "@services/chirpstack/chirpstack-gateway.service"; import { DeviceProfileService } from "@services/chirpstack/device-profile.service"; import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; -import { SharedModule } from "@modules/shared.module"; import { OrganizationModule } from "@modules/user-management/organization.module"; @Module({ diff --git a/src/services/chirpstack/chirpstack-device.service.ts b/src/services/chirpstack/chirpstack-device.service.ts index c87be1a8..177d0385 100644 --- a/src/services/chirpstack/chirpstack-device.service.ts +++ b/src/services/chirpstack/chirpstack-device.service.ts @@ -1,10 +1,7 @@ import { BadRequestException, Injectable, Logger, NotFoundException } from "@nestjs/common"; -import { AxiosResponse } from "axios"; +import { Application as ApplicationDb } from "@entities/application.entity"; -import { - ChirpstackDeviceActivationContentsDto, - ChirpstackDeviceActivationDto, -} from "@dto/chirpstack/chirpstack-device-activation-response.dto"; +import { ChirpstackDeviceActivationContentsDto } from "@dto/chirpstack/chirpstack-device-activation-response.dto"; import { ChirpstackDeviceContentsDto } from "@dto/chirpstack/chirpstack-device-contents.dto"; import { ChirpstackDeviceKeysContentDto } from "@dto/chirpstack/chirpstack-device-keys-response.dto"; import { ChirpstackSingleApplicationResponseDto } from "@dto/chirpstack/chirpstack-single-application-response.dto"; @@ -20,17 +17,17 @@ import { DeviceQueueItem, } from "@dto/chirpstack/chirpstack-device-downlink-queue-response.dto"; import { ErrorCodes } from "@enum/error-codes.enum"; -import { ChirpstackManyDeviceResponseDto } from "@dto/chirpstack/chirpstack-many-device-response"; +import { + ChirpstackManyDeviceResponseContents, + ChirpstackManyDeviceResponseDto, +} from "@dto/chirpstack/chirpstack-many-device-response"; import { IoTDevice } from "@entities/iot-device.entity"; import { LoRaWANDeviceWithChirpstackDataDto } from "@dto/lorawan-device-with-chirpstack-data.dto"; import { ActivationType } from "@enum/lorawan-activation-type.enum"; import { ChirpstackDeviceId } from "@dto/chirpstack/chirpstack-device-id.dto"; import { ChirpstackApplicationResponseDto } from "@dto/chirpstack/chirpstack-application-response.dto"; import { groupBy } from "lodash"; -import { - LoRaWANStatsElementDto, - LoRaWANStatsResponseDto, -} from "@dto/chirpstack/device/lorawan-stats.response.dto"; +import { LoRaWANStatsElementDto, LoRaWANStatsResponseDto } from "@dto/chirpstack/device/lorawan-stats.response.dto"; import { ConfigService } from "@nestjs/config"; import { DeviceServiceClient } from "@chirpstack/chirpstack-api/api/device_grpc_pb"; import { DeviceProfileService } from "@services/chirpstack/device-profile.service"; @@ -65,11 +62,12 @@ import { GetDeviceRequest, GetDeviceResponse, ListDevicesRequest, + ListDevicesResponse, UpdateDeviceKeysRequest, UpdateDeviceRequest, } from "@chirpstack/chirpstack-api/api/device_pb"; import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; -import { dateToTimestamp } from "@helpers/date.helper"; +import { dateToTimestamp, timestampToDate } from "@helpers/date.helper"; import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; import { Aggregation } from "@chirpstack/chirpstack-api/common/common_pb"; import { DeviceMetricsDto, MetricProperties } from "@dto/chirpstack/chirpstack-device-metrics.dto"; @@ -87,10 +85,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi this.deviceStatsIntervalInDays = configService.get("backend.deviceStatsIntervalInDays"); } - private deviceServiceClient = new DeviceServiceClient( - this.baseUrlGRPC, - credentials.createInsecure() - ); + private deviceServiceClient = new DeviceServiceClient(this.baseUrlGRPC, credentials.createInsecure()); private readonly logger = new Logger(ChirpstackDeviceService.name); @@ -120,27 +115,23 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi // if application exist use it let applicationId = applications.result.find( element => - element.id === iotDevice.chirpstackApplicationId || - element.id === iotDevice.application.chirpstackId + element.id === iotDevice.chirpstackApplicationId || element.id === iotDevice.application.chirpstackId )?.id; // otherwise create new application if (!applicationId) { applicationId = await this.createNewApplication( + applicationId, organizationID, iotDevice.application.name, iotDevice.application.id + ); } return applicationId; } - private async createNewApplication( - applicationId: string, - organizationID: string, - name: string, - id: number - ) { + private async createNewApplication(applicationId: string, organizationID: string, name: string, id: number) { applicationId = await this.createApplication({ application: { name: `${this.defaultApplicationName}-${name}`, @@ -152,7 +143,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi where: { id: id }, }); existingApplication.chirpstackId = applicationId; - await this.applicationRepository.save(existingApplication) + await this.applicationRepository.save(existingApplication); return applicationId; } @@ -254,16 +245,36 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi return true; } - async getAllDevicesStatus(): Promise { + async getAllDevicesStatus(app: ApplicationDb): Promise { const req = new ListDevicesRequest(); - req.setLimit(10000); - req.setOffset(0); - const test = await this.get( + req.setApplicationId(app.chirpstackId); + const devices = await this.getAllWithPagination( `devices`, + 10000, + 0, this.deviceServiceClient, req - - return test; + ); + const responseDto: ChirpstackManyDeviceResponseContents[] = []; + + devices.resultList.map(e => { + const responseItem: ChirpstackManyDeviceResponseContents = { + devEUI: e.devEui, + name: e.name, + description: e.description, + lastSeenAt: e.lastSeenAt ? timestampToDate(e.lastSeenAt) : undefined, + deviceStatusBattery: e.deviceStatus?.batteryLevel, + deviceStatusMargin: e.deviceStatus?.margin, + deviceStatusExternalPowerSource: e.deviceStatus?.externalPowerSource, + deviceProfileID: e.deviceProfileId, + deviceProfileName: e.deviceProfileName + }; + responseDto.push(responseItem); + }); + return { + totalCount: devices.totalCount.toString(), + result: responseDto, + }; } private async createOrUpdateABPActivation( @@ -404,11 +415,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi const req = new GetDeviceRequest(); req.setDevEui(id); - const res = await this.get( - `devices/${id}`, - this.deviceServiceClient, - req - ); + const res = await this.get(`devices/${id}`, this.deviceServiceClient, req); const deviceDto: ChirpstackDeviceContentsDto = { deviceStatusBattery: res.getDeviceStatus()?.getBatteryLevel(), @@ -531,7 +538,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi async getStats(deviceEUI: string): Promise { const now = new Date(); const to_time = dateToTimestamp(now); - const from_time = new Date(new Date().setDate(now.getDate() - this.deviceStatsIntervalInDays)).toISOString(); + const from_time = new Date(new Date().setDate(now.getDate() - this.deviceStatsIntervalInDays)); const from_time_timestamp: Timestamp = dateToTimestamp(from_time); const req = new GetDeviceLinkMetricsRequest(); @@ -541,17 +548,15 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi req.setAggregation(Aggregation.DAY); const metaData = this.makeMetadataHeader(); - const getDeviceMetricsPromise = new Promise( - (resolve, reject) => { - this.deviceServiceClient.getLinkMetrics(req, metaData, (err, resp) => { - if (err) { - reject(err); - } else { - resolve(resp); - } - }); - } - ); + const getDeviceMetricsPromise = new Promise((resolve, reject) => { + this.deviceServiceClient.getLinkMetrics(req, metaData, (err, resp) => { + if (err) { + reject(err); + } else { + resolve(resp); + } + }); + }); try { const metrics = await getDeviceMetricsPromise; return this.mapMetrics(metrics); @@ -666,10 +671,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi return applicationIdObject.id; } - async getKeys( - client: DeviceServiceClient, - request: GetDeviceKeysRequest - ): Promise { + async getKeys(client: DeviceServiceClient, request: GetDeviceKeysRequest): Promise { const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.getKeys(request, metaData, (err: ServiceError, resp: any) => { @@ -747,10 +749,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi throw new NotFoundException(); } } - async deleteQueue( - client: DeviceServiceClient, - request: FlushDeviceQueueRequest - ): Promise { + async deleteQueue(client: DeviceServiceClient, request: FlushDeviceQueueRequest): Promise { const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.flushQueue(request, metaData, (err: ServiceError, resp: any) => { @@ -815,10 +814,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi throw new NotFoundException(); } } - async postActivation( - client?: DeviceServiceClient, - request?: ActivateDeviceRequest - ): Promise { + async postActivation(client?: DeviceServiceClient, request?: ActivateDeviceRequest): Promise { const metaData = this.makeMetadataHeader(); const createPromise = new Promise((resolve, reject) => { client.activate(request, metaData, (err: ServiceError, resp: any) => { diff --git a/src/services/chirpstack/chirpstack-gateway.service.ts b/src/services/chirpstack/chirpstack-gateway.service.ts index 39d8e74d..e7f7d64b 100644 --- a/src/services/chirpstack/chirpstack-gateway.service.ts +++ b/src/services/chirpstack/chirpstack-gateway.service.ts @@ -5,11 +5,11 @@ import { Logger, NotFoundException, } from "@nestjs/common"; -import { AxiosResponse } from "axios"; +import * as BluebirdPromise from "bluebird"; import { ChirpstackErrorResponseDto } from "@dto/chirpstack/chirpstack-error-response.dto"; import { ChirpstackResponseStatus } from "@dto/chirpstack/chirpstack-response.dto"; import { CreateGatewayDto } from "@dto/chirpstack/create-gateway.dto"; -import { GatewayStatsElementDto } from "@dto/chirpstack/gateway-stats.response.dto"; +import { GatewayStatsElementDto, GatewayStatsResponseDto } from "@dto/chirpstack/gateway-stats.response.dto"; import { ListAllGatewaysResponseGrpcDto } from "@dto/chirpstack/list-all-gateways.dto"; import { SingleGatewayResponseDto } from "@dto/chirpstack/single-gateway-response.dto"; import { UpdateGatewayContentsDto, UpdateGatewayDto } from "@dto/chirpstack/update-gateway.dto"; @@ -17,22 +17,18 @@ import { ErrorCodes } from "@enum/error-codes.enum"; import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; import { GatewayContentsDto } from "@dto/chirpstack/gateway-contents.dto"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; -import { - checkIfUserHasAccessToOrganization, - OrganizationAccessScope, +import { checkIfUserHasAccessToOrganization, OrganizationAccessScope } from "@helpers/security-helper"; import { InjectRepository } from "@nestjs/typeorm"; -import { Gateway } from "@entities/gateway.entity"; +import { Gateway as GatewayDb } from "@entities/gateway.entity"; import { Repository } from "typeorm"; import { OrganizationService } from "@services/user-management/organization.service"; -import { GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto"; import { CommonLocationDto } from "@dto/chirpstack/common-location.dto"; -} from "@helpers/security-helper"; import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; import { GatewayServiceClient } from "@chirpstack/chirpstack-api/api/gateway_grpc_pb"; import { CreateGatewayRequest, DeleteGatewayRequest, - Gateway, + Gateway as GatewayCs, GetGatewayMetricsRequest, GetGatewayMetricsResponse, GetGatewayRequest, @@ -47,11 +43,12 @@ import { Aggregation, Location } from "@chirpstack/chirpstack-api/common/common_ import { dateToTimestamp } from "@helpers/date.helper"; @Injectable() export class ChirpstackGatewayService extends GenericChirpstackConfigurationService { - constructor() { - super(); - @InjectRepository(Gateway) - private gatewayRepository: Repository, + constructor( + @InjectRepository(GatewayDb) + private gatewayRepository: Repository, private organizationService: OrganizationService + ) { + super(); } GATEWAY_STATS_INTERVAL_IN_DAYS = 29; private readonly logger = new Logger(ChirpstackGatewayService.name, { @@ -60,14 +57,8 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ private readonly ORG_ID_KEY = "internalOrganizationId"; private readonly UPDATED_BY_KEY = "os2iot-updated-by"; private readonly CREATED_BY_KEY = "os2iot-created-by"; - private gatewayClient = new GatewayServiceClient( - this.baseUrlGRPC, - credentials.createInsecure() - ); - async createNewGateway( - dto: CreateGatewayDto, - userId: number - ): Promise { + private gatewayClient = new GatewayServiceClient(this.baseUrlGRPC, credentials.createInsecure()); + async createNewGateway(dto: CreateGatewayDto, userId: number): Promise { dto.gateway = await this.updateDtoContents(dto.gateway); dto.gateway.tags = this.addOrganizationToTags(dto); @@ -85,23 +76,18 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ const location = new Location(); this.mapToLocationChirpstack(location, dto); - const gatewayCs = new Gateway(); + const gatewayCs = new GatewayCs(); await this.mapToGatewayChirpstack(gatewayCs, dto, location); Object.entries(dto.gateway.tags).forEach(([key, value]) => { - gateway.getTagsMap().set(key, value); + gatewayCs.getTagsMap().set(key, value); }); - req.setGateway(gateway); - await this.gatewayRepository.save(gateway); + req.setGateway(gatewayCs); try { await this.gatewayRepository.save(gateway); await this.post("gateways", this.gatewayClient, req); return { success: true }; } catch (e) { - this.logger.error( - `Error from Chirpstack: '${JSON.stringify(dto)}', got response: ${JSON.stringify( - e - )}` - ); + this.logger.error(`Error from Chirpstack: '${JSON.stringify(dto)}', got response: ${JSON.stringify(e)}`); throw new BadRequestException({ success: false, error: e, @@ -110,7 +96,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ } async mapToGatewayChirpstack( - gateway: Gateway, + gateway: GatewayCs, dto: CreateGatewayDto | UpdateGatewayDto, location: Location, gatewayId?: string @@ -120,9 +106,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ gateway.setName(dto.gateway.name); gateway.setLocation(location); gateway.setStatsInterval(30); - gateway.setTenantId( - dto.gateway.tenantId ? dto.gateway.tenantId : await this.getDefaultOrganizationId() - ); + gateway.setTenantId(dto.gateway.tenantId ? dto.gateway.tenantId : await this.getDefaultOrganizationId()); } mapToLocationChirpstack(location: Location, dto: CreateGatewayDto | UpdateGatewayDto) { location.setAccuracy(dto.gateway.location.accuracy); @@ -164,7 +148,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ const gateways = await query.getMany(); return { - result: gateways.map(this.mapGatewayToResponseDto), + resultList: gateways.map(this.mapGatewayToResponseDto), totalCount: gateways.length, }; } @@ -177,10 +161,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ const gw = await this.getOne(x.gatewayId); x.internalOrganizationId = gw.gateway.internalOrganizationId; } catch (err) { - this.logger.error( - `Failed to fetch gateway details for id ${x.gatewayId}`, - err - ); + this.logger.error(`Failed to fetch gateway details for id ${x.gatewayId}`, err); x.internalOrganizationId = null; } }, @@ -190,39 +171,24 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ ) ); } - async mapSingleGatewayResponse(result: GetGatewayResponse, gatewayId: string) { - const gatewayReponseObject: SingleGatewayResponseDto = { - createdAt: result.getCreatedAt()?.toDate(), - lastSeenAt: result.getLastSeenAt()?.toObject(), - updatedAt: result.getUpdatedAt()?.toDate(), - stats: await this.getGatewayStats(gatewayId), - gateway: result.getGateway()?.toObject(), - }; - gatewayReponseObject.gateway.internalOrganizationId = +result - .getGateway() - .getTagsMap() - .get(this.ORG_ID_KEY); - gatewayReponseObject.gateway.createdBy = +result - .getGateway() - .getTagsMap() - .get(this.CREATED_BY_KEY); - gatewayReponseObject.gateway.updatedBy = +result - .getGateway() - .getTagsMap() - .get(this.UPDATED_BY_KEY); - - //Filter out specific tags. - gatewayReponseObject.gateway.tagsMap = gatewayReponseObject.gateway.tagsMap.filter( - ([key]) => { - return ( - key !== this.ORG_ID_KEY && - key !== this.CREATED_BY_KEY && - key !== this.UPDATED_BY_KEY - ); - } - ); - return gatewayReponseObject; - } + // async mapSingleGatewayResponse(result: GetGatewayResponse, gatewayId: string) { + // const gatewayReponseObject: SingleGatewayResponseDto = { + // createdAt: result.getCreatedAt()?.toDate(), + // lastSeenAt: result.getLastSeenAt()?.toObject(), + // updatedAt: result.getUpdatedAt()?.toDate(), + // stats: await this.getGatewayStats(gatewayId), + // gateway: result.getGateway()?.toObject(), + // }; + // gatewayReponseObject.gateway.internalOrganizationId = +result.getGateway().getTagsMap().get(this.ORG_ID_KEY); + // gatewayReponseObject.gateway.createdBy = +result.getGateway().getTagsMap().get(this.CREATED_BY_KEY); + // gatewayReponseObject.gateway.updatedBy = +result.getGateway().getTagsMap().get(this.UPDATED_BY_KEY); + + // //Filter out specific tags. + // gatewayReponseObject.gateway.tagsMap = gatewayReponseObject.gateway.tagsMap.filter(([key]) => { + // return key !== this.ORG_ID_KEY && key !== this.CREATED_BY_KEY && key !== this.UPDATED_BY_KEY; + // }); + // return gatewayReponseObject; + // } async getOne(gatewayId: string): Promise { if (gatewayId?.length != 16) { throw new BadRequestException("Invalid gateway id"); @@ -239,7 +205,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ const now = new Date(); const statsFrom = new Date(new Date().setDate(now.getDate() - this.GATEWAY_STATS_INTERVAL_IN_DAYS)); - result.stats = (await this.getGatewayStats(gatewayId, statsFrom, now)).result; + result.stats = (await this.getGatewayStats(gatewayId, statsFrom, now)); result.gateway = this.mapGatewayToResponseDto(gateway); return result; @@ -252,9 +218,9 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ } } - async getGatewayStats(gatewayId: string, from: Date, to: Date): Promise { - const to_time = dateToTimestamp(to); - const from_time_timestamp: Timestamp = dateToTimestamp(from); + async getGatewayStats(gatewayId: string, from: Date, to: Date): Promise { + const to_time = dateToTimestamp(to); + const from_time_timestamp: Timestamp = dateToTimestamp(from); const request = new GetGatewayMetricsRequest(); request.setGatewayId(gatewayId); @@ -264,17 +230,15 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ const metaData = this.makeMetadataHeader(); - const getGatewayMetricsPromise = new Promise( - (resolve, reject) => { - this.gatewayClient.getMetrics(request, metaData, (err, resp) => { - if (err) { - reject(err); - } else { - resolve(resp); - } - }); - } - ); + const getGatewayMetricsPromise = new Promise((resolve, reject) => { + this.gatewayClient.getMetrics(request, metaData, (err, resp) => { + if (err) { + reject(err); + } else { + resolve(resp); + } + }); + }); try { const metrics = await getGatewayMetricsPromise; return this.mapPackets(metrics); @@ -342,32 +306,26 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ const gateway = this.mapContentsDtoToGateway(dto.gateway); gateway.gatewayId = gatewayId; gateway.updatedBy = req.user.userId; - - + const request = new UpdateGatewayRequest(); const location = new Location(); this.mapToLocationChirpstack(location, dto); - const gateway = new Gateway(); + const gatewayCs = new GatewayCs(); - await this.mapToGatewayChirpstack(gateway, dto, location, gatewayId); - + await this.mapToGatewayChirpstack(gatewayCs, dto, location, gatewayId); Object.entries(dto.gateway.tags).forEach(([key, value]) => { - gateway.getTagsMap().set(key, value); + gatewayCs.getTagsMap().set(key, value); }); - request.setGateway(gateway); + request.setGateway(gatewayCs); try { await this.gatewayRepository.update({ gatewayId }, gateway); await this.put("gateways", this.gatewayClient, request); return { success: true }; } catch (e) { - this.logger.error( - `Error from Chirpstack: '${JSON.stringify(dto)}', got response: ${JSON.stringify( - e - )}` - ); + this.logger.error(`Error from Chirpstack: '${JSON.stringify(dto)}', got response: ${JSON.stringify(e)}`); throw new BadRequestException({ success: false, error: e, @@ -394,11 +352,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ tags[this.ORG_ID_KEY] = `${existing.gateway.organizationId}`; // TODO: Interpolated string will never be null? if (tags[this.ORG_ID_KEY] != null) { - checkIfUserHasAccessToOrganization( - req, - +tags[this.ORG_ID_KEY], - OrganizationAccessScope.GatewayWrite - ); + checkIfUserHasAccessToOrganization(req, +tags[this.ORG_ID_KEY], OrganizationAccessScope.GatewayWrite); } return tags; } @@ -438,7 +392,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ } public mapContentsDtoToGateway(dto: GatewayContentsDto) { - const gateway = new Gateway(); + const gateway = new GatewayDb(); gateway.name = dto.name; gateway.gatewayId = dto.gatewayId; gateway.description = dto.description; @@ -452,14 +406,14 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ return gateway; } - private mapGatewayToResponseDto(gateway: Gateway): GatewayResponseDto { - const responseDto = gateway as unknown as GatewayResponseDto; + private mapGatewayToResponseDto(gateway: GatewayDb): GatewayResponseGrpcDto { + const responseDto = gateway as unknown as GatewayResponseGrpcDto; responseDto.organizationId = gateway.organization.id; responseDto.organizationName = gateway.organization.name; - responseDto.tags = JSON.parse(gateway.tags); - responseDto.tags["internalOrganizationId"] = undefined; - responseDto.tags["os2iot-updated-by"] = undefined; - responseDto.tags["os2iot-created-by"] = undefined; + // responseDto.tags = JSON.parse(gateway.tags); + // responseDto.tags["internalOrganizationId"] = undefined; + // responseDto.tags["os2iot-updated-by"] = undefined; + // responseDto.tags["os2iot-created-by"] = undefined; const commonLocation = new CommonLocationDto(); commonLocation.latitude = gateway.location.coordinates[1]; diff --git a/src/services/chirpstack/gateway-boostrapper.service.ts b/src/services/chirpstack/gateway-boostrapper.service.ts index 472330b9..8d26ddcc 100644 --- a/src/services/chirpstack/gateway-boostrapper.service.ts +++ b/src/services/chirpstack/gateway-boostrapper.service.ts @@ -28,22 +28,24 @@ export class GatewayBootstrapperService implements OnApplicationBootstrap { } } - /** + /** * Populate the gateway status table with an entry for each new gateway. * @param gateways All chirpstack gateways * @param statusHistories Existing status histories to check against */ - private async seedGatewayStatus(gateways: ListAllGatewaysResponseDto, statusHistories: GatewayStatusHistory[]) { + private async seedGatewayStatus( gateways: ListAllGatewaysResponseGrpcDto, + statusHistories: GatewayStatusHistory[] + ) { const now = new Date(); const errorTime = new Date(); errorTime.setSeconds(errorTime.getSeconds() - 150); // Don't overwrite ones which already have a status history const newHistoriesForMissingGateways = gateways.resultList.reduce( - if (!statusHistories.some(history => history.mac === gateway.gatewayId)) { + (res: GatewayStatusHistory[], gateway) => { if (!statusHistories.some(history => history.mac === gateway.gatewayId)) { - // Best fit is to imitate the status logic from Chirpstack. + // Best fit is to imitate the status logic from Chirpstack. if (gateway.lastSeenAt) { const lastSeenDate = timestampToDate(gateway.lastSeenAt); @@ -57,8 +59,10 @@ export class GatewayBootstrapperService implements OnApplicationBootstrap { } } - return res; - }, []); + return res; + }, + [] + ); if (newHistoriesForMissingGateways.length) { await this.statusHistoryService.createMany(newHistoriesForMissingGateways); diff --git a/src/services/chirpstack/gateway-status-history.service.ts b/src/services/chirpstack/gateway-status-history.service.ts index abf21036..729e53ba 100644 --- a/src/services/chirpstack/gateway-status-history.service.ts +++ b/src/services/chirpstack/gateway-status-history.service.ts @@ -10,7 +10,7 @@ import { InjectRepository } from "@nestjs/typeorm"; import { In, MoreThanOrEqual, Repository } from "typeorm"; import { ChirpstackGatewayService } from "./chirpstack-gateway.service"; import { nameof } from "@helpers/type-helper"; -import { GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto"; +import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; type GatewayId = { gatewayId: string; name: string }; @Injectable() @@ -49,10 +49,7 @@ export class GatewayStatusHistoryService { latestStatusHistoryPerGatewayBeforePeriod ); - const data: GatewayStatus[] = this.mapStatusHistoryToGateways(gateways.result, statusHistories); - gateways.resultList, - statusHistories - ); + const data: GatewayStatus[] = this.mapStatusHistoryToGateways(gateways.resultList, statusHistories); return { data, @@ -60,7 +57,7 @@ export class GatewayStatusHistoryService { }; } - public async findOne(gateway: GatewayResponseDto, timeInterval: GatewayStatusInterval): Promise { + public async findOne(gateway: GatewayResponseGrpcDto, timeInterval: GatewayStatusInterval): Promise { const fromDate = gatewayStatusIntervalToDate(timeInterval); const statusHistoriesInPeriod = await this.gatewayStatusHistoryRepository.find({ @@ -129,7 +126,7 @@ export class GatewayStatusHistoryService { } private mapStatusHistoryToGateways( - gateways: GatewayResponseDto[], + gateways: GatewayResponseGrpcDto[], statusHistories: GatewayStatusHistory[] ): GatewayStatus[] { return gateways.map(gateway => { @@ -137,7 +134,7 @@ export class GatewayStatusHistoryService { }); } - private mapStatusHistoryToGateway(gateway: GatewayResponseDto, statusHistories: GatewayStatusHistory[]) { + private mapStatusHistoryToGateway(gateway: GatewayResponseGrpcDto, statusHistories: GatewayStatusHistory[]) { const statusTimestamps = statusHistories.reduce((res: GatewayStatus["statusTimestamps"], history) => { if (history.mac === gateway.gatewayId) { res.push({ diff --git a/src/services/device-management/application.service.ts b/src/services/device-management/application.service.ts index e2dad915..5cfcb856 100644 --- a/src/services/device-management/application.service.ts +++ b/src/services/device-management/application.service.ts @@ -31,6 +31,7 @@ import { DataTargetService } from "@services/data-targets/data-target.service"; import { DataTargetType } from "@enum/data-target-type.enum"; import { MulticastService } from "@services/chirpstack/multicast.service"; import { ApplicationChirpstackService } from "@services/chirpstack/chirpstack-application.service"; +import { CreateLoRaWANSettingsDto } from "@dto/create-lorawan-settings.dto"; @Injectable() export class ApplicationService { @@ -209,7 +210,7 @@ export class ApplicationService { } private async matchWithChirpstackStatusData(app: Application) { - const allFromChirpstack = await this.chirpstackDeviceService.getAllDevicesStatus(); + const allFromChirpstack = await this.chirpstackDeviceService.getAllDevicesStatus(app); app.iotDevices.forEach(x => { if (x.type === IoTDeviceType.LoRaWAN) { const loraDevice = x as LoRaWANDeviceWithChirpstackDataDto; diff --git a/src/services/device-management/iot-device.service.ts b/src/services/device-management/iot-device.service.ts index 0f8f5af8..0af3eb45 100644 --- a/src/services/device-management/iot-device.service.ts +++ b/src/services/device-management/iot-device.service.ts @@ -326,7 +326,6 @@ export class IoTDeviceService { await this.loRaWANDeviceRepository.save(devices); } - async findMQTTDevice(id: number): Promise { return await this.mqttInternalBrokerDeviceRepository.findOne({ where: { id }, @@ -923,10 +922,9 @@ export class IoTDeviceService { lorawanDevice: LoRaWANDevice, isUpdate: boolean, lorawanDeviceEuis: ChirpstackDeviceId[] = null, - loraApplications: ListAllChirpstackApplicationsResponseDto = null, + loraApplications: ListAllChirpstackApplicationsResponseDto = null ): Promise { lorawanDevice.deviceEUI = dto.lorawanSettings.devEUI; - if ( !isUpdate && (await this.chirpstackDeviceService.isDeviceAlreadyCreated(dto.lorawanSettings.devEUI, lorawanDeviceEuis)) @@ -945,7 +943,6 @@ export class IoTDeviceService { ); lorawanDevice.chirpstackApplicationId = applicationId; chirpstackDeviceDto.device.applicationID = applicationId; - // Create or update the LoRa device against Chirpstack API const response = await this.chirpstackDeviceService.createOrUpdateDevice( chirpstackDeviceDto, @@ -954,16 +951,14 @@ export class IoTDeviceService { if (response) { lorawanDeviceEuis.push(chirpstackDeviceDto.device); await this.doActivation(dto, isUpdate); - lorawanDevice.OTAAapplicationKey = dto.lorawanSettings.OTAAapplicationKey; - const deviceProfile = await this.deviceProfileService.findOneDeviceProfileById( - dto.lorawanSettings.deviceProfileID - ); - + lorawanDevice.OTAAapplicationKey = dto.lorawanSettings.OTAAapplicationKey; + const deviceProfile = await this.deviceProfileService.findOneDeviceProfileById( + dto.lorawanSettings.deviceProfileID + ); + lorawanDevice.deviceProfileName = deviceProfile.deviceProfile.name; } else { throw new BadRequestException(ErrorCodes.InvalidPost); } - ); - lorawanDevice.deviceProfileName = deviceProfile.deviceProfile.name; } catch (err) { this.logger.error(err); diff --git a/src/services/device-management/lorawan-device-database-enrich-job.ts b/src/services/device-management/lorawan-device-database-enrich-job.ts index 54d3dda9..1f091501 100644 --- a/src/services/device-management/lorawan-device-database-enrich-job.ts +++ b/src/services/device-management/lorawan-device-database-enrich-job.ts @@ -4,11 +4,12 @@ import { ChirpstackDeviceService } from "@services/chirpstack/chirpstack-device. import { IoTDeviceService } from "@services/device-management/iot-device.service"; import { ChirpstackGatewayService } from "@services/chirpstack/chirpstack-gateway.service"; import * as BluebirdPromise from "bluebird"; -import { ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways.dto"; +import { ListAllGatewaysResponseGrpcDto } from "@dto/chirpstack/list-all-gateways.dto"; import { OrganizationService } from "@services/user-management/organization.service"; import { InjectRepository } from "@nestjs/typeorm"; import { Gateway } from "@entities/gateway.entity"; import { Repository } from "typeorm"; +import { timestampToDate } from "@helpers/date.helper"; @Injectable() export class LorawanDeviceDatabaseEnrichJob { @@ -27,7 +28,7 @@ export class LorawanDeviceDatabaseEnrichJob { async fetchStatusForGateway() { // Select all gateways from our database and chirpstack (Cheaper than individual calls) const gateways = await this.gatewayService.getAll(); - const chirpStackGateways = await this.gatewayService.getAllWithPagination( + const chirpStackGateways = await this.gatewayService.getAllWithPagination( "gateways", 1000, 0 @@ -36,7 +37,7 @@ export class LorawanDeviceDatabaseEnrichJob { // Setup batched fetching of status (Only for today) await BluebirdPromise.all( BluebirdPromise.map( - gateways.result, + gateways.resultList, async gateway => { try { const fromTime = new Date(); @@ -50,8 +51,8 @@ export class LorawanDeviceDatabaseEnrichJob { new Date() ); // Save that to our database - const stats = statsToday.result[0]; - const chirpstackGateway = chirpStackGateways.result.find( + const stats = statsToday[0]; + const chirpstackGateway = chirpStackGateways.resultList.find( g => g.id.toString() === gateway.gatewayId ); @@ -59,7 +60,7 @@ export class LorawanDeviceDatabaseEnrichJob { gateway.gatewayId, stats.rxPacketsReceived, stats.txPacketsEmitted, - chirpstackGateway.lastSeenAt + timestampToDate(chirpstackGateway.lastSeenAt) ); } catch (err) { this.logger.error(`Gateway status fetch failed with: ${JSON.stringify(err)}`, err); @@ -100,7 +101,7 @@ export class LorawanDeviceDatabaseEnrichJob { @Timeout(10000) async importChirpstackGateways() { // Get all chirpstack gateways - const chirpStackGateways = await this.gatewayService.getAllWithPagination( + const chirpStackGateways = await this.gatewayService.getAllWithPagination( "gateways", 1000, 0 @@ -109,8 +110,8 @@ export class LorawanDeviceDatabaseEnrichJob { const dbGateways = await this.gatewayService.getAll(); // Filter for gateways not existing in our database - const unknownGateways = chirpStackGateways.result.filter( - g => dbGateways.result.findIndex(dbGateway => dbGateway.gatewayId === g.id.toString()) === -1 + const unknownGateways = chirpStackGateways.resultList.filter( + g => dbGateways.resultList.findIndex(dbGateway => dbGateway.gatewayId === g.id.toString()) === -1 ); await BluebirdPromise.all( @@ -118,7 +119,7 @@ export class LorawanDeviceDatabaseEnrichJob { unknownGateways, async x => { try { - const gw = (await this.gatewayService.get(`gateways/${x.id}`)) as any; + const gw = (await this.gatewayService.get(`gateways/${x.gatewayId}`)) as any; const organizationId = gw.gateway.tags["internalOrganizationId"]; const gateway = this.gatewayService.mapContentsDtoToGateway(gw.gateway); From 3130d82646bbf320583e1879385800dd4179c1da Mon Sep 17 00:00:00 2001 From: August Andersen Date: Sun, 10 Dec 2023 18:49:58 +0100 Subject: [PATCH 06/24] Made chirpstack work with gateways aswell after merge --- .../chirpstack-gateway.controller.ts | 4 +- .../dto/chirpstack/gateway-response.dto.ts | 14 +-- .../chirpstack/chirpstack-gateway.service.ts | 108 ++++++++++-------- .../data-management/search.service.ts | 2 +- .../lorawan-device-database-enrich-job.ts | 88 +++++++++----- 5 files changed, 125 insertions(+), 91 deletions(-) diff --git a/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts b/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts index e3c0bd50..336c17c8 100644 --- a/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts +++ b/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts @@ -134,10 +134,10 @@ export class ChirpstackGatewayController { ): Promise { try { const gw = await this.chirpstackGatewayService.getOne(gatewayId); - if (gw.gateway.organizationId != null) { + if (gw.gateway.internalOrganizationId != null) { checkIfUserHasAccessToOrganization( req, - +gw.gateway.organizationId, + +gw.gateway.internalOrganizationId, OrganizationAccessScope.GatewayWrite ); } diff --git a/src/entities/dto/chirpstack/gateway-response.dto.ts b/src/entities/dto/chirpstack/gateway-response.dto.ts index a77f87ad..a6a45cd9 100644 --- a/src/entities/dto/chirpstack/gateway-response.dto.ts +++ b/src/entities/dto/chirpstack/gateway-response.dto.ts @@ -1,22 +1,20 @@ -import { Location } from "@chirpstack/chirpstack-api/common/common_pb"; import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; import { CommonLocationDto } from "./common-location.dto"; export class GatewayResponseGrpcDto { - id: number; + id?: number; gatewayId: string; name: string; description?: string; - rxPacketsReceived: number; - txPacketsEmitted: number; - organizationId: number; - organizationName: string; + rxPacketsReceived?: number; + txPacketsEmitted?: number; + internalOrganizationId?: number; + internalOrganizationName?: string; location: CommonLocationDto; createdAt?: Timestamp.AsObject; updatedAt?: Timestamp.AsObject; lastSeenAt?: Timestamp.AsObject; - internalOrganizationId?: number; updatedBy?: number; createdBy?: number; - tags: { [id: string]: string }; + tags?: { [id: string]: string }; } diff --git a/src/services/chirpstack/chirpstack-gateway.service.ts b/src/services/chirpstack/chirpstack-gateway.service.ts index e7f7d64b..a08479ed 100644 --- a/src/services/chirpstack/chirpstack-gateway.service.ts +++ b/src/services/chirpstack/chirpstack-gateway.service.ts @@ -40,7 +40,7 @@ import { import { credentials } from "@grpc/grpc-js"; import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; import { Aggregation, Location } from "@chirpstack/chirpstack-api/common/common_pb"; -import { dateToTimestamp } from "@helpers/date.helper"; +import { dateToTimestamp, timestampToDate } from "@helpers/date.helper"; @Injectable() export class ChirpstackGatewayService extends GenericChirpstackConfigurationService { constructor( @@ -81,6 +81,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ Object.entries(dto.gateway.tags).forEach(([key, value]) => { gatewayCs.getTagsMap().set(key, value); }); + req.setGateway(gatewayCs); try { await this.gatewayRepository.save(gateway); @@ -152,43 +153,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ totalCount: gateways.length, }; } - private async enrichWithOrganizationId(results: GatewayResponseGrpcDto[]) { - await BluebirdPromise.all( - BluebirdPromise.map( - results, - async x => { - try { - const gw = await this.getOne(x.gatewayId); - x.internalOrganizationId = gw.gateway.internalOrganizationId; - } catch (err) { - this.logger.error(`Failed to fetch gateway details for id ${x.gatewayId}`, err); - x.internalOrganizationId = null; - } - }, - { - concurrency: 50, - } - ) - ); - } - // async mapSingleGatewayResponse(result: GetGatewayResponse, gatewayId: string) { - // const gatewayReponseObject: SingleGatewayResponseDto = { - // createdAt: result.getCreatedAt()?.toDate(), - // lastSeenAt: result.getLastSeenAt()?.toObject(), - // updatedAt: result.getUpdatedAt()?.toDate(), - // stats: await this.getGatewayStats(gatewayId), - // gateway: result.getGateway()?.toObject(), - // }; - // gatewayReponseObject.gateway.internalOrganizationId = +result.getGateway().getTagsMap().get(this.ORG_ID_KEY); - // gatewayReponseObject.gateway.createdBy = +result.getGateway().getTagsMap().get(this.CREATED_BY_KEY); - // gatewayReponseObject.gateway.updatedBy = +result.getGateway().getTagsMap().get(this.UPDATED_BY_KEY); - - // //Filter out specific tags. - // gatewayReponseObject.gateway.tagsMap = gatewayReponseObject.gateway.tagsMap.filter(([key]) => { - // return key !== this.ORG_ID_KEY && key !== this.CREATED_BY_KEY && key !== this.UPDATED_BY_KEY; - // }); - // return gatewayReponseObject; - // } + async getOne(gatewayId: string): Promise { if (gatewayId?.length != 16) { throw new BadRequestException("Invalid gateway id"); @@ -205,7 +170,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ const now = new Date(); const statsFrom = new Date(new Date().setDate(now.getDate() - this.GATEWAY_STATS_INTERVAL_IN_DAYS)); - result.stats = (await this.getGatewayStats(gatewayId, statsFrom, now)); + result.stats = await this.getGatewayStats(gatewayId, statsFrom, now); result.gateway = this.mapGatewayToResponseDto(gateway); return result; @@ -306,6 +271,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ const gateway = this.mapContentsDtoToGateway(dto.gateway); gateway.gatewayId = gatewayId; gateway.updatedBy = req.user.userId; + gateway.updatedAt = new Date(); const request = new UpdateGatewayRequest(); const location = new Location(); @@ -349,7 +315,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ ): Promise<{ [id: string]: string }> { const existing = await this.getOne(gatewayId); const tags = dto.gateway.tags; - tags[this.ORG_ID_KEY] = `${existing.gateway.organizationId}`; + tags[this.ORG_ID_KEY] = `${existing.gateway.internalOrganizationId}`; // TODO: Interpolated string will never be null? if (tags[this.ORG_ID_KEY] != null) { checkIfUserHasAccessToOrganization(req, +tags[this.ORG_ID_KEY], OrganizationAccessScope.GatewayWrite); @@ -384,9 +350,8 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ } if (contentsDto?.tagsString) { - contentsDto.tags = JSON.parse(contentsDto.tagsString); // TODO: Updaze for new format when chirpstack 4 + contentsDto.tags = JSON.parse(contentsDto.tagsString); } - contentsDto.id = contentsDto.gatewayId; return contentsDto; } @@ -401,25 +366,68 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ type: "Point", coordinates: [dto.location.longitude, dto.location.latitude], }; - gateway.tags = JSON.stringify(dto.tags); + const tempTags = dto.tags; + tempTags[this.ORG_ID_KEY] = undefined; + tempTags[this.CREATED_BY_KEY] = undefined; + tempTags[this.UPDATED_BY_KEY] = undefined; + gateway.tags = JSON.stringify(tempTags); return gateway; } + public mapCsGwToGateway(gw: GatewayCs, gwResponse: GetGatewayResponse) { + const gateway = new GatewayDb(); + gateway.name = gw.getName(); + gateway.gatewayId = gw.getGatewayId(); + gateway.description = gw.getDescription(); + gateway.altitude = gw.getLocation().getAltitude(); + gateway.location = { + type: "Point", + coordinates: [gw.getLocation().getLongitude(), gw.getLocation().getLatitude()], + }; + const jsonRepresentation: Record = gw + .getTagsMap() + .toArray() + .reduce((obj: Record, [key, value]) => { + obj[key] = value; + return obj; + }, {}); + jsonRepresentation["internalOrganizationId"] = undefined; + jsonRepresentation["os2iot-updated-by"] = undefined; + jsonRepresentation["os2iot-created-by"] = undefined; + gateway.tags = JSON.stringify(jsonRepresentation); + (gateway.lastSeenAt = gwResponse.getLastSeenAt() + ? timestampToDate(gwResponse.getLastSeenAt().toObject()) + : undefined), + (gateway.createdAt = gwResponse.getCreatedAt() + ? timestampToDate(gwResponse.getCreatedAt().toObject()) + : undefined); + (gateway.updatedAt = gwResponse.getUpdatedAt() + ? timestampToDate(gwResponse.getUpdatedAt().toObject()) + : undefined), + (gateway.rxPacketsReceived = 0); + gateway.txPacketsEmitted = 0; + gateway.createdBy = + gw.getTagsMap().get("os2iot-created-by") !== undefined + ? Number(gw.getTagsMap().get("os2iot-created-by")) + : undefined; + gateway.updatedBy = + gw.getTagsMap().get("os2iot-updated-by") !== undefined + ? Number(gw.getTagsMap().get("os2iot-updated-by")) + : undefined; + + return gateway; + } private mapGatewayToResponseDto(gateway: GatewayDb): GatewayResponseGrpcDto { const responseDto = gateway as unknown as GatewayResponseGrpcDto; - responseDto.organizationId = gateway.organization.id; - responseDto.organizationName = gateway.organization.name; - // responseDto.tags = JSON.parse(gateway.tags); - // responseDto.tags["internalOrganizationId"] = undefined; - // responseDto.tags["os2iot-updated-by"] = undefined; - // responseDto.tags["os2iot-created-by"] = undefined; + responseDto.internalOrganizationId = gateway.organization.id; + responseDto.internalOrganizationName = gateway.organization.name; const commonLocation = new CommonLocationDto(); commonLocation.latitude = gateway.location.coordinates[1]; commonLocation.longitude = gateway.location.coordinates[0]; commonLocation.altitude = gateway.altitude; - + responseDto.tags = JSON.parse(gateway.tags); responseDto.location = commonLocation; return responseDto; diff --git a/src/services/data-management/search.service.ts b/src/services/data-management/search.service.ts index 58a1a589..fa097e75 100644 --- a/src/services/data-management/search.service.ts +++ b/src/services/data-management/search.service.ts @@ -114,7 +114,7 @@ export class SearchService { const detailedInfo = await this.gatewayService.getOne(x.gatewayId); - resultDto.organizationId = detailedInfo.gateway.organizationId; + resultDto.organizationId = detailedInfo.gateway.internalOrganizationId; return resultDto; }) ); diff --git a/src/services/device-management/lorawan-device-database-enrich-job.ts b/src/services/device-management/lorawan-device-database-enrich-job.ts index 1f091501..1a631155 100644 --- a/src/services/device-management/lorawan-device-database-enrich-job.ts +++ b/src/services/device-management/lorawan-device-database-enrich-job.ts @@ -10,6 +10,15 @@ import { InjectRepository } from "@nestjs/typeorm"; import { Gateway } from "@entities/gateway.entity"; import { Repository } from "typeorm"; import { timestampToDate } from "@helpers/date.helper"; +import { + ListGatewaysResponse, + ListGatewaysRequest, + GetGatewayRequest, + GetGatewayResponse, +} from "@chirpstack/chirpstack-api/api/gateway_pb"; +import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; +import { GatewayServiceClient } from "@chirpstack/chirpstack-api/api/gateway_grpc_pb"; +import { credentials } from "@grpc/grpc-js"; @Injectable() export class LorawanDeviceDatabaseEnrichJob { @@ -21,6 +30,8 @@ export class LorawanDeviceDatabaseEnrichJob { @InjectRepository(Gateway) private gatewayRepository: Repository ) {} + baseUrlGRPC = `${process.env.CHIRPSTACK_HOSTNAME || "localhost"}:${process.env.CHIRPSTACK_PORT || "8084"}`; + private gatewayClient = new GatewayServiceClient(this.baseUrlGRPC, credentials.createInsecure()); private readonly logger = new Logger(LorawanDeviceDatabaseEnrichJob.name, { timestamp: true }); @@ -28,11 +39,7 @@ export class LorawanDeviceDatabaseEnrichJob { async fetchStatusForGateway() { // Select all gateways from our database and chirpstack (Cheaper than individual calls) const gateways = await this.gatewayService.getAll(); - const chirpStackGateways = await this.gatewayService.getAllWithPagination( - "gateways", - 1000, - 0 - ); + const responseList = await this.getAllGateways(); // Setup batched fetching of status (Only for today) await BluebirdPromise.all( @@ -52,15 +59,13 @@ export class LorawanDeviceDatabaseEnrichJob { ); // Save that to our database const stats = statsToday[0]; - const chirpstackGateway = chirpStackGateways.resultList.find( - g => g.id.toString() === gateway.gatewayId - ); + const chirpstackGateway = responseList.resultList.find(g => g.gatewayId === gateway.gatewayId); await this.gatewayService.updateGatewayStats( gateway.gatewayId, stats.rxPacketsReceived, stats.txPacketsEmitted, - timestampToDate(chirpstackGateway.lastSeenAt) + chirpstackGateway.lastSeenAt ? timestampToDate(chirpstackGateway.lastSeenAt) : undefined ); } catch (err) { this.logger.error(`Gateway status fetch failed with: ${JSON.stringify(err)}`, err); @@ -100,36 +105,28 @@ export class LorawanDeviceDatabaseEnrichJob { // This is run once on startup and will create any gateways that exist in chirpstack but not our database @Timeout(10000) async importChirpstackGateways() { - // Get all chirpstack gateways - const chirpStackGateways = await this.gatewayService.getAllWithPagination( - "gateways", - 1000, - 0 - ); - + const responseList = await this.getAllGateways(); const dbGateways = await this.gatewayService.getAll(); - // Filter for gateways not existing in our database - const unknownGateways = chirpStackGateways.resultList.filter( - g => dbGateways.resultList.findIndex(dbGateway => dbGateway.gatewayId === g.id.toString()) === -1 + const unknownGateways = responseList.resultList.filter( + g => dbGateways.resultList.findIndex(dbGateway => dbGateway.gatewayId === g.gatewayId) === -1 ); - await BluebirdPromise.all( BluebirdPromise.map( unknownGateways, async x => { try { - const gw = (await this.gatewayService.get(`gateways/${x.gatewayId}`)) as any; - const organizationId = gw.gateway.tags["internalOrganizationId"]; + const req = new GetGatewayRequest(); + req.setGatewayId(x.gatewayId); - const gateway = this.gatewayService.mapContentsDtoToGateway(gw.gateway); - gateway.id = 0; - gateway.gatewayId = gw.gateway.id; - gateway.lastSeenAt = gw.lastSeenAt; - gateway.createdAt = new Date(Date.parse(gw.createdAt)); - gateway.rxPacketsReceived = 0; - gateway.txPacketsEmitted = 0; - gateway.createdBy = gw.gateway.tags["os2iot-created-by"]; + const gwResponse = await this.gatewayService.get( + `gateways/${x.gatewayId}`, + this.gatewayClient, + req + ); + const csGw = gwResponse.getGateway(); + const organizationId = +csGw.getTagsMap().get("internalOrganizationId"); + const gateway = this.gatewayService.mapCsGwToGateway(csGw, gwResponse); gateway.organization = await this.organizationService.findById(organizationId); await this.gatewayRepository.save(gateway); } catch (err) { @@ -142,4 +139,35 @@ export class LorawanDeviceDatabaseEnrichJob { ) ); } + async getAllGateways(): Promise { + const limit = 1000; + const listReq = new ListGatewaysRequest(); + // Get all chirpstack gateways + const chirpStackGateways = await this.gatewayService.getAllWithPagination( + "gateways", + limit, + 0, + this.gatewayClient, + listReq + ); + + const responseItem: GatewayResponseGrpcDto[] = []; + chirpStackGateways.resultList.map(e => { + const resultItem: GatewayResponseGrpcDto = { + gatewayId: e.gatewayId, + name: e.name, + location: e.location, + description: e.description, + createdAt: e.createdAt ?? undefined, + updatedAt: e.updatedAt ?? undefined, + lastSeenAt: e.lastSeenAt ?? undefined, + }; + responseItem.push(resultItem); + }); + const responseList: ListAllGatewaysResponseGrpcDto = { + totalCount: chirpStackGateways.totalCount, + resultList: responseItem, + }; + return responseList; + } } From 7654a290dd1b8e5cc8d3266210fb95e4b23ea8fd Mon Sep 17 00:00:00 2001 From: August Andersen Date: Sun, 10 Dec 2023 19:22:25 +0100 Subject: [PATCH 07/24] minor fixes in application --- .../chirpstack/chirpstack-gateway.service.ts | 2 +- .../device-management/application.service.ts | 45 ++++++++----------- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/src/services/chirpstack/chirpstack-gateway.service.ts b/src/services/chirpstack/chirpstack-gateway.service.ts index a08479ed..b79daa39 100644 --- a/src/services/chirpstack/chirpstack-gateway.service.ts +++ b/src/services/chirpstack/chirpstack-gateway.service.ts @@ -366,7 +366,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ type: "Point", coordinates: [dto.location.longitude, dto.location.latitude], }; - const tempTags = dto.tags; + const tempTags = { ...dto.tags }; tempTags[this.ORG_ID_KEY] = undefined; tempTags[this.CREATED_BY_KEY] = undefined; tempTags[this.UPDATED_BY_KEY] = undefined; diff --git a/src/services/device-management/application.service.ts b/src/services/device-management/application.service.ts index 5cfcb856..ebfbd5ef 100644 --- a/src/services/device-management/application.service.ts +++ b/src/services/device-management/application.service.ts @@ -15,13 +15,7 @@ import { ApplicationDeviceTypes, ApplicationDeviceTypeUnion, IoTDeviceType } fro import { ErrorCodes } from "@enum/error-codes.enum"; import { findValuesInRecord } from "@helpers/record.helper"; import { nameof } from "@helpers/type-helper"; -import { - BadRequestException, - ConflictException, - forwardRef, - Inject, - Injectable, -} from "@nestjs/common"; +import { BadRequestException, ConflictException, forwardRef, Inject, Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { ChirpstackDeviceService } from "@services/chirpstack/chirpstack-device.service"; import { OrganizationService } from "@services/user-management/organization.service"; @@ -242,9 +236,7 @@ export class ApplicationService { mappedApplication.updatedBy = userId; try { - const chirpId = await this.chirpstackApplicationService.createApplication( - createApplicationDto - ); + const chirpId = await this.chirpstackApplicationService.createApplication(createApplicationDto); mappedApplication.chirpstackId = chirpId.id; const app = await this.applicationRepository.save(mappedApplication); @@ -273,7 +265,7 @@ export class ApplicationService { userId ); - await this.chirpstackApplicationService.updateApplication(mappedApplication) + await this.chirpstackApplicationService.updateApplication(mappedApplication); mappedApplication.updatedBy = userId; return this.applicationRepository.save(mappedApplication, {}); @@ -298,26 +290,25 @@ export class ApplicationService { await this.dataTargetService.delete(dataTarget.id); } - if (application.chirpstackId) { - await this.chirpstackApplicationService.deleteApplication(application.chirpstackId); - } else { - // Delete all LoRaWAN devices in ChirpStack + // Delete all LoRaWAN devices in ChirpStack const loRaWANDevices = application.iotDevices.filter(device => device.type === IoTDeviceType.LoRaWAN); - for (const device of loRaWANDevices) { - const lwDevice = device as LoRaWANDevice; - await this.chirpstackDeviceService.deleteDevice(lwDevice.deviceEUI); - } + for (const device of loRaWANDevices) { + const lwDevice = device as LoRaWANDevice; + await this.chirpstackDeviceService.deleteDevice(lwDevice.deviceEUI); + } - //delete all multicats - const multicasts = application.multicasts; - for (const multicast of multicasts) { - const dbMulticast = await this.multicastService.findOne(multicast.id); + //delete all multicats + const multicasts = application.multicasts; + for (const multicast of multicasts) { + const dbMulticast = await this.multicastService.findOne(multicast.id); - await this.multicastService.deleteMulticastChirpstack( - dbMulticast.lorawanMulticastDefinition.chirpstackGroupId - ); - } + await this.multicastService.deleteMulticastChirpstack( + dbMulticast.lorawanMulticastDefinition.chirpstackGroupId + ); + } + if (application.chirpstackId) { + await this.chirpstackApplicationService.deleteApplication(application.chirpstackId); } return this.applicationRepository.delete(id); From 49b45678444085d7ca879c26354ebec6b59f3953 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Mon, 11 Dec 2023 12:52:29 +0100 Subject: [PATCH 08/24] Check for devices using deviceprofile before deleting. --- .../chirpstack/device-profile.service.ts | 103 ++++++++++-------- 1 file changed, 58 insertions(+), 45 deletions(-) diff --git a/src/services/chirpstack/device-profile.service.ts b/src/services/chirpstack/device-profile.service.ts index a6cc1c68..4f3c1994 100644 --- a/src/services/chirpstack/device-profile.service.ts +++ b/src/services/chirpstack/device-profile.service.ts @@ -1,5 +1,6 @@ import { BadRequestException, + ConflictException, Injectable, InternalServerErrorException, NotFoundException, @@ -14,10 +15,7 @@ import { UpdateDeviceProfileDto } from "@dto/chirpstack/update-device-profile.dt import { DeviceProfileDto } from "@dto/chirpstack/device-profile.dto"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; import { ErrorCodes } from "@enum/error-codes.enum"; -import { - checkIfUserHasAccessToOrganization, - OrganizationAccessScope, -} from "@helpers/security-helper"; +import { checkIfUserHasAccessToOrganization, OrganizationAccessScope } from "@helpers/security-helper"; import { DeviceProfileServiceClient } from "@chirpstack/chirpstack-api/api/device_profile_grpc_pb"; import { credentials, ServiceError } from "@grpc/grpc-js"; import { @@ -36,6 +34,10 @@ import { ListAllAdrAlgorithmsResponseDto } from "@dto/chirpstack/list-all-adr-al import { Empty } from "google-protobuf/google/protobuf/empty_pb"; import { AdrAlgorithmDto } from "@dto/chirpstack/adr-algorithm.dto"; import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { DeviceListItem, ListDevicesRequest, ListDevicesResponse } from "@chirpstack/chirpstack-api/api/device_pb"; +import { DeviceServiceClient } from "@chirpstack/chirpstack-api/api/device_grpc_pb"; +import { ListApplicationsRequest, ListApplicationsResponse } from "@chirpstack/chirpstack-api/api/application_pb"; +import { ApplicationServiceClient } from "@chirpstack/chirpstack-api/api/application_grpc_pb"; @Injectable() export class DeviceProfileService extends GenericChirpstackConfigurationService { @@ -43,14 +45,10 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService private readonly UPDATED_BY_KEY = "os2iot-updated-by"; private readonly CREATED_BY_KEY = "os2iot-created-by"; - private deviceProfileClient = new DeviceProfileServiceClient( - this.baseUrlGRPC, - credentials.createInsecure() - ); - public async createDeviceProfile( - dto: CreateDeviceProfileDto, - userId: number - ): Promise { + private deviceProfileClient = new DeviceProfileServiceClient(this.baseUrlGRPC, credentials.createInsecure()); + private deviceClient = new DeviceServiceClient(this.baseUrlGRPC, credentials.createInsecure()); + private applicationClient = new ApplicationServiceClient(this.baseUrlGRPC, credentials.createInsecure()); + public async createDeviceProfile(dto: CreateDeviceProfileDto, userId: number): Promise { if (await this.isNameInUse(dto.deviceProfile.name)) { throw new BadRequestException(ErrorCodes.NameInvalidOrAlreadyInUse); } @@ -113,10 +111,7 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService .some(x => x.name.toLocaleLowerCase() == name.toLocaleLowerCase()); } - private async updateTags( - deviceProfileId: string, - req: AuthenticatedRequest - ): Promise<{ [id: string]: string }> { + private async updateTags(deviceProfileId: string, req: AuthenticatedRequest): Promise<{ [id: string]: string }> { const request = new GetDeviceProfileRequest(); const result = await this.getOneById( "device-profiles", @@ -149,23 +144,51 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService this.deviceProfileClient, getReq ); + const deviceProfileId = result.getDeviceProfile().getId(); + const listReq = new ListDevicesRequest(); + const listAppReq = new ListApplicationsRequest(); + listAppReq.setTenantId(await this.getDefaultOrganizationId()); + + const applications = await this.getAllWithPagination( + "devices", + 1000, + 0, + this.applicationClient, + listAppReq + ); + + let devices: DeviceListItem.AsObject[] = []; + for (let index = 0; index < applications.resultList.length; index++) { + listReq.setApplicationId(applications.resultList[index].id); + const devicesForApp = await this.getAllWithPagination( + "devices", + 10000, + 0, + this.deviceClient, + listReq + ); + devices = devices.concat(devicesForApp.resultList); + } + + const match = devices.find(e => e.deviceProfileId === deviceProfileId); + if (match) { + throw new ConflictException(ErrorCodes.DeleteNotAllowedHasLoRaWANDevices); + } + if (result.getDeviceProfile().getTagsMap().get(this.ORG_ID_KEY) != null) { + [] = []; checkIfUserHasAccessToOrganization( req, +result.getDeviceProfile().getTagsMap().get(this.ORG_ID_KEY), OrganizationAccessScope.ApplicationWrite ); } - const deleteReq = new DeleteDeviceProfileRequest(); deleteReq.setId(result.getDeviceProfile().getId()); return await this.delete("device-profiles", this.deviceProfileClient, deleteReq); } - public async findAllDeviceProfiles( - limit?: number, - offset?: number - ): Promise { + public async findAllDeviceProfiles(limit?: number, offset?: number): Promise { const req = new ListDeviceProfilesRequest(); req.setTenantId(await this.getDefaultOrganizationId()); @@ -227,9 +250,7 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService return dto; } - private mapSingleDeviceProfileResponse( - result: GetDeviceProfileResponse - ): CreateDeviceProfileDto { + private mapSingleDeviceProfileResponse(result: GetDeviceProfileResponse): CreateDeviceProfileDto { const responseObject = result.getDeviceProfile().toObject(); const deviceProfileMapped = this.mapDeviceInfoContent(responseObject); const deviceProfileResponseObject: CreateDeviceProfileDto = { @@ -254,11 +275,7 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService deviceProfileResponseObject.deviceProfile.tagsMap = deviceProfileResponseObject.deviceProfile.tagsMap.filter( ([key]) => { - return ( - key !== this.ORG_ID_KEY && - key !== this.CREATED_BY_KEY && - key !== this.UPDATED_BY_KEY - ); + return key !== this.ORG_ID_KEY && key !== this.CREATED_BY_KEY && key !== this.UPDATED_BY_KEY; } ); return deviceProfileResponseObject; @@ -314,7 +331,9 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService deviceProfile.setSupportsClassB(data.deviceProfile.supportsClassB); deviceProfile.setSupportsClassC(data.deviceProfile.supportsClassC); deviceProfile.setSupportsOtaa(data.deviceProfile.supportsJoin); - deviceProfile.setDeviceStatusReqInterval(data.deviceProfile.devStatusReqFreq === undefined ? 1 : data.deviceProfile.devStatusReqFreq); + deviceProfile.setDeviceStatusReqInterval( + data.deviceProfile.devStatusReqFreq === undefined ? 1 : data.deviceProfile.devStatusReqFreq + ); isCreate ? deviceProfile.setTenantId(data.deviceProfile.organizationID) : {}; } @@ -338,21 +357,15 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService async getAdrAlgorithms(): Promise { const metaData = this.makeMetadataHeader(); - const getPromise = new Promise( - (resolve, reject) => { - this.deviceProfileClient.listAdrAlgorithms( - new Empty(), - metaData, - (err: ServiceError, resp: any) => { - if (err) { - reject(err); - } else { - resolve(resp); - } - } - ); - } - ); + const getPromise = new Promise((resolve, reject) => { + this.deviceProfileClient.listAdrAlgorithms(new Empty(), metaData, (err: ServiceError, resp: any) => { + if (err) { + reject(err); + } else { + resolve(resp); + } + }); + }); try { return await getPromise; } catch (err) { From c689c4d15815c75d5fd091f275655693fe6bfac5 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Mon, 11 Dec 2023 14:20:07 +0100 Subject: [PATCH 09/24] change default port to 8080 --- .../chirpstack/generic-chirpstack-configuration.service.ts | 2 +- .../device-management/lorawan-device-database-enrich-job.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/chirpstack/generic-chirpstack-configuration.service.ts b/src/services/chirpstack/generic-chirpstack-configuration.service.ts index f58912f6..8316b934 100644 --- a/src/services/chirpstack/generic-chirpstack-configuration.service.ts +++ b/src/services/chirpstack/generic-chirpstack-configuration.service.ts @@ -21,7 +21,7 @@ import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interfac @Injectable() export class GenericChirpstackConfigurationService { baseUrlGRPC = `${process.env.CHIRPSTACK_HOSTNAME || "localhost"}:${ - process.env.CHIRPSTACK_PORT || "8084" + process.env.CHIRPSTACK_PORT || "8080" }`; private readonly innerLogger = new Logger(GenericChirpstackConfigurationService.name); diff --git a/src/services/device-management/lorawan-device-database-enrich-job.ts b/src/services/device-management/lorawan-device-database-enrich-job.ts index 1a631155..0e2e14c1 100644 --- a/src/services/device-management/lorawan-device-database-enrich-job.ts +++ b/src/services/device-management/lorawan-device-database-enrich-job.ts @@ -30,7 +30,7 @@ export class LorawanDeviceDatabaseEnrichJob { @InjectRepository(Gateway) private gatewayRepository: Repository ) {} - baseUrlGRPC = `${process.env.CHIRPSTACK_HOSTNAME || "localhost"}:${process.env.CHIRPSTACK_PORT || "8084"}`; + baseUrlGRPC = `${process.env.CHIRPSTACK_HOSTNAME || "localhost"}:${process.env.CHIRPSTACK_PORT || "8080"}`; private gatewayClient = new GatewayServiceClient(this.baseUrlGRPC, credentials.createInsecure()); private readonly logger = new Logger(LorawanDeviceDatabaseEnrichJob.name, { timestamp: true }); From 2518755754549f1d66505df3bb98b6ecb984e384 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Tue, 12 Dec 2023 10:35:25 +0100 Subject: [PATCH 10/24] minor cleanup and addition of chirpstackId in application if not set yet. --- .../chirpstack/chirpstack-device.service.ts | 15 +++++- .../chirpstack/chirpstack-gateway.service.ts | 5 -- .../chirpstack/device-profile.service.ts | 9 +--- .../gateway-status-history.service.ts | 1 - ...eneric-chirpstack-configuration.service.ts | 46 +++++++------------ src/services/chirpstack/multicast.service.ts | 5 -- .../device-management/application.service.ts | 1 - 7 files changed, 31 insertions(+), 51 deletions(-) diff --git a/src/services/chirpstack/chirpstack-device.service.ts b/src/services/chirpstack/chirpstack-device.service.ts index 177d0385..36916e81 100644 --- a/src/services/chirpstack/chirpstack-device.service.ts +++ b/src/services/chirpstack/chirpstack-device.service.ts @@ -75,6 +75,7 @@ import { LoRaWANDevice } from "@entities/lorawan-device.entity"; import { InjectRepository } from "@nestjs/typeorm"; import { Repository } from "typeorm"; import { Application as DbApplication } from "@entities/application.entity"; +import { IoTDeviceType } from "@enum/device-type.enum"; @Injectable() export class ChirpstackDeviceService extends GenericChirpstackConfigurationService { @InjectRepository(DbApplication) @@ -85,7 +86,6 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi this.deviceStatsIntervalInDays = configService.get("backend.deviceStatsIntervalInDays"); } - private deviceServiceClient = new DeviceServiceClient(this.baseUrlGRPC, credentials.createInsecure()); private readonly logger = new Logger(ChirpstackDeviceService.name); @@ -247,6 +247,17 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi async getAllDevicesStatus(app: ApplicationDb): Promise { const req = new ListDevicesRequest(); + if (!app.chirpstackId) { + const loraDev = app.iotDevices.find(d => d.type === IoTDeviceType.LoRaWAN); + const cast = loraDev as LoRaWANDevice; + const getChirpstackDevice = await this.get( + "device", + this.deviceServiceClient, + new GetDeviceRequest().setDevEui(cast.deviceEUI) + ); + app.chirpstackId = getChirpstackDevice.getDevice().getApplicationId(); + await this.applicationRepository.save(app, {}); + } req.setApplicationId(app.chirpstackId); const devices = await this.getAllWithPagination( `devices`, @@ -267,7 +278,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi deviceStatusMargin: e.deviceStatus?.margin, deviceStatusExternalPowerSource: e.deviceStatus?.externalPowerSource, deviceProfileID: e.deviceProfileId, - deviceProfileName: e.deviceProfileName + deviceProfileName: e.deviceProfileName, }; responseDto.push(responseItem); }); diff --git a/src/services/chirpstack/chirpstack-gateway.service.ts b/src/services/chirpstack/chirpstack-gateway.service.ts index b79daa39..07b53d5e 100644 --- a/src/services/chirpstack/chirpstack-gateway.service.ts +++ b/src/services/chirpstack/chirpstack-gateway.service.ts @@ -5,7 +5,6 @@ import { Logger, NotFoundException, } from "@nestjs/common"; -import * as BluebirdPromise from "bluebird"; import { ChirpstackErrorResponseDto } from "@dto/chirpstack/chirpstack-error-response.dto"; import { ChirpstackResponseStatus } from "@dto/chirpstack/chirpstack-response.dto"; import { CreateGatewayDto } from "@dto/chirpstack/create-gateway.dto"; @@ -31,10 +30,7 @@ import { Gateway as GatewayCs, GetGatewayMetricsRequest, GetGatewayMetricsResponse, - GetGatewayRequest, GetGatewayResponse, - ListGatewaysRequest, - ListGatewaysResponse, UpdateGatewayRequest, } from "@chirpstack/chirpstack-api/api/gateway_pb"; import { credentials } from "@grpc/grpc-js"; @@ -57,7 +53,6 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ private readonly ORG_ID_KEY = "internalOrganizationId"; private readonly UPDATED_BY_KEY = "os2iot-updated-by"; private readonly CREATED_BY_KEY = "os2iot-created-by"; - private gatewayClient = new GatewayServiceClient(this.baseUrlGRPC, credentials.createInsecure()); async createNewGateway(dto: CreateGatewayDto, userId: number): Promise { dto.gateway = await this.updateDtoContents(dto.gateway); diff --git a/src/services/chirpstack/device-profile.service.ts b/src/services/chirpstack/device-profile.service.ts index 4f3c1994..1e05dc18 100644 --- a/src/services/chirpstack/device-profile.service.ts +++ b/src/services/chirpstack/device-profile.service.ts @@ -35,9 +35,7 @@ import { Empty } from "google-protobuf/google/protobuf/empty_pb"; import { AdrAlgorithmDto } from "@dto/chirpstack/adr-algorithm.dto"; import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; import { DeviceListItem, ListDevicesRequest, ListDevicesResponse } from "@chirpstack/chirpstack-api/api/device_pb"; -import { DeviceServiceClient } from "@chirpstack/chirpstack-api/api/device_grpc_pb"; import { ListApplicationsRequest, ListApplicationsResponse } from "@chirpstack/chirpstack-api/api/application_pb"; -import { ApplicationServiceClient } from "@chirpstack/chirpstack-api/api/application_grpc_pb"; @Injectable() export class DeviceProfileService extends GenericChirpstackConfigurationService { @@ -45,9 +43,6 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService private readonly UPDATED_BY_KEY = "os2iot-updated-by"; private readonly CREATED_BY_KEY = "os2iot-created-by"; - private deviceProfileClient = new DeviceProfileServiceClient(this.baseUrlGRPC, credentials.createInsecure()); - private deviceClient = new DeviceServiceClient(this.baseUrlGRPC, credentials.createInsecure()); - private applicationClient = new ApplicationServiceClient(this.baseUrlGRPC, credentials.createInsecure()); public async createDeviceProfile(dto: CreateDeviceProfileDto, userId: number): Promise { if (await this.isNameInUse(dto.deviceProfile.name)) { throw new BadRequestException(ErrorCodes.NameInvalidOrAlreadyInUse); @@ -153,7 +148,7 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService "devices", 1000, 0, - this.applicationClient, + this.applicationServiceClient, listAppReq ); @@ -164,7 +159,7 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService "devices", 10000, 0, - this.deviceClient, + this.deviceServiceClient, listReq ); devices = devices.concat(devicesForApp.resultList); diff --git a/src/services/chirpstack/gateway-status-history.service.ts b/src/services/chirpstack/gateway-status-history.service.ts index 729e53ba..448505dd 100644 --- a/src/services/chirpstack/gateway-status-history.service.ts +++ b/src/services/chirpstack/gateway-status-history.service.ts @@ -11,7 +11,6 @@ import { In, MoreThanOrEqual, Repository } from "typeorm"; import { ChirpstackGatewayService } from "./chirpstack-gateway.service"; import { nameof } from "@helpers/type-helper"; import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; -type GatewayId = { gatewayId: string; name: string }; @Injectable() export class GatewayStatusHistoryService { diff --git a/src/services/chirpstack/generic-chirpstack-configuration.service.ts b/src/services/chirpstack/generic-chirpstack-configuration.service.ts index 8316b934..f553325e 100644 --- a/src/services/chirpstack/generic-chirpstack-configuration.service.ts +++ b/src/services/chirpstack/generic-chirpstack-configuration.service.ts @@ -11,31 +11,28 @@ import configuration from "@config/configuration"; import { TenantServiceClient } from "@chirpstack/chirpstack-api/api/tenant_grpc_pb"; import { ListTenantsRequest, ListTenantsResponse } from "@chirpstack/chirpstack-api/api/tenant_pb"; import { ApplicationServiceClient } from "@chirpstack/chirpstack-api/api/application_grpc_pb"; -import { - ListApplicationsRequest, - ListApplicationsResponse, -} from "@chirpstack/chirpstack-api/api/application_pb"; +import { ListApplicationsRequest, ListApplicationsResponse } from "@chirpstack/chirpstack-api/api/application_pb"; import { ChirpstackApplicationResponseDto } from "@dto/chirpstack/chirpstack-application-response.dto"; import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { DeviceServiceClient } from "@chirpstack/chirpstack-api/api/device_grpc_pb"; +import { GatewayServiceClient } from "@chirpstack/chirpstack-api/api/gateway_grpc_pb"; +import { DeviceProfileServiceClient } from "@chirpstack/chirpstack-api/api/device_profile_grpc_pb"; +import { MulticastGroupServiceClient } from "@chirpstack/chirpstack-api/api/multicast_group_grpc_pb"; @Injectable() export class GenericChirpstackConfigurationService { - baseUrlGRPC = `${process.env.CHIRPSTACK_HOSTNAME || "localhost"}:${ - process.env.CHIRPSTACK_PORT || "8080" - }`; + baseUrlGRPC = `${process.env.CHIRPSTACK_HOSTNAME || "localhost"}:${process.env.CHIRPSTACK_PORT || "8080"}`; private readonly innerLogger = new Logger(GenericChirpstackConfigurationService.name); - protected applicationServiceClient = new ApplicationServiceClient( - this.baseUrlGRPC, - credentials.createInsecure() - ); + protected applicationServiceClient = new ApplicationServiceClient(this.baseUrlGRPC, credentials.createInsecure()); + protected deviceServiceClient = new DeviceServiceClient(this.baseUrlGRPC, credentials.createInsecure()); + protected gatewayClient = new GatewayServiceClient(this.baseUrlGRPC, credentials.createInsecure()); + protected deviceProfileClient = new DeviceProfileServiceClient(this.baseUrlGRPC, credentials.createInsecure()); + protected multicastServiceClient = new MulticastGroupServiceClient(this.baseUrlGRPC, credentials.createInsecure()); makeMetadataHeader(): Metadata { const metadata = new Metadata(); - metadata.set( - "authorization", - "Bearer " + configuration()["chirpstack"]["apikey"], - ); + metadata.set("authorization", "Bearer " + configuration()["chirpstack"]["apikey"]); return metadata; } @@ -144,9 +141,7 @@ export class GenericChirpstackConfigurationService { } } - async getAllApplicationsWithPagination( - tenantID: string - ): Promise { + async getAllApplicationsWithPagination(tenantID: string): Promise { const req = new ListApplicationsRequest(); req.setTenantId(await this.getDefaultOrganizationId()); @@ -202,14 +197,8 @@ export class GenericChirpstackConfigurationService { } } - public async getTenants( - limit?: number, - offset?: number - ): Promise { - const tenantClient = new TenantServiceClient( - this.baseUrlGRPC, - credentials.createInsecure() - ); + public async getTenants(limit?: number, offset?: number): Promise { + const tenantClient = new TenantServiceClient(this.baseUrlGRPC, credentials.createInsecure()); const req = new ListTenantsRequest(); const res = await this.getAllWithPagination( @@ -226,10 +215,7 @@ export class GenericChirpstackConfigurationService { let id = null; await this.getTenants(1000, 0).then(response => { response.resultList.forEach(element => { - if ( - element.name.toLowerCase() == "os2iot" || - element.name.toLowerCase() == "chirpstack" - ) { + if (element.name.toLowerCase() == "os2iot" || element.name.toLowerCase() == "chirpstack") { id = element.id; } }); diff --git a/src/services/chirpstack/multicast.service.ts b/src/services/chirpstack/multicast.service.ts index 1e3ad679..09ccc354 100644 --- a/src/services/chirpstack/multicast.service.ts +++ b/src/services/chirpstack/multicast.service.ts @@ -67,11 +67,6 @@ export class MulticastService extends GenericChirpstackConfigurationService { private readonly logger = new Logger(MulticastService.name); multicastGroupUrl = "multicast-groups"; - private multicastServiceClient = new MulticastGroupServiceClient( - this.baseUrlGRPC, - credentials.createInsecure() - ); - async findAndCountAllWithPagination( // inspired by datatarget and other places in this project. // Repository syntax doesn't yet support ordering by relation: https://github.com/typeorm/typeorm/issues/2620 diff --git a/src/services/device-management/application.service.ts b/src/services/device-management/application.service.ts index ebfbd5ef..dd7a0b5b 100644 --- a/src/services/device-management/application.service.ts +++ b/src/services/device-management/application.service.ts @@ -419,7 +419,6 @@ export class ApplicationService { const loraDevices = data.filter( device => device.type === IoTDeviceType.LoRaWAN ) as LoRaWANDeviceWithChirpstackDataDto[]; - const applications = await this.chirpstackDeviceService.getLoRaWANApplications(loraDevices); for (const device of loraDevices) { await this.chirpstackDeviceService.enrichLoRaWANDevice(device); From b34d1d6b17c8f4bbdd1431e0559da7f06b4d52ce Mon Sep 17 00:00:00 2001 From: August Andersen Date: Tue, 12 Dec 2023 11:18:11 +0100 Subject: [PATCH 11/24] bumped grpc package --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 22c12b92..17a9450e 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "dependencies": { "@nestjs/axios": "^3.0.0", "@chirpstack/chirpstack-api": "4.5.1", - "@grpc/grpc-js": "1.9.9", + "@grpc/grpc-js": "1.9.12", "@nestjs/common": "^9.1.2", "@nestjs/config": "^2.2.0", "@nestjs/core": "^9.1.2", From 51abe4b66abfde696bcb71910c3e357cd5a86d1a Mon Sep 17 00:00:00 2001 From: August Andersen Date: Tue, 12 Dec 2023 11:29:53 +0100 Subject: [PATCH 12/24] updated package-lock, using node v 16 as github does. --- package-lock.json | 7655 ++++++++++++++++- .../chirpstack/chirpstack-device.service.ts | 2 +- .../chirpstack/chirpstack-gateway.service.ts | 1 - .../chirpstack/device-profile.service.ts | 3 +- src/services/chirpstack/multicast.service.ts | 2 +- 5 files changed, 7559 insertions(+), 104 deletions(-) diff --git a/package-lock.json b/package-lock.json index 45e2179d..1025789b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "os2iot-backend", "version": "0.0.1", - "lockfileVersion": 3, + "lockfileVersion": 2, "requires": true, "packages": { "": { @@ -10,7 +10,7 @@ "license": "Mozilla Public License Version 2.0", "dependencies": { "@chirpstack/chirpstack-api": "4.5.1", - "@grpc/grpc-js": "1.9.9", + "@grpc/grpc-js": "1.9.12", "@nestjs/axios": "^3.0.0", "@nestjs/common": "^9.1.2", "@nestjs/config": "^2.2.0", @@ -329,21 +329,21 @@ } }, "node_modules/@babel/core": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", - "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", + "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.5", - "@babel/helper-compilation-targets": "^7.22.15", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.5", - "@babel/parser": "^7.23.5", + "@babel/helpers": "^7.23.6", + "@babel/parser": "^7.23.6", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.5", - "@babel/types": "^7.23.5", + "@babel/traverse": "^7.23.6", + "@babel/types": "^7.23.6", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -368,12 +368,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", - "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "dependencies": { - "@babel/types": "^7.23.5", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -383,14 +383,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -548,14 +548,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", - "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", + "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", "dev": true, "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.5", - "@babel/types": "^7.23.5" + "@babel/traverse": "^7.23.6", + "@babel/types": "^7.23.6" }, "engines": { "node": ">=6.9.0" @@ -647,9 +647,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", - "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -836,9 +836,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", - "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", + "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -861,20 +861,20 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", - "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.5", + "@babel/generator": "^7.23.6", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.5", - "@babel/types": "^7.23.5", - "debug": "^4.1.0", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -891,9 +891,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", - "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.23.4", @@ -1010,9 +1010,9 @@ } }, "node_modules/@grpc/grpc-js": { - "version": "1.9.9", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.9.tgz", - "integrity": "sha512-vQ1qwi/Kiyprt+uhb1+rHMpyk4CVRMTGNUGGPRGS7pLNfWkdCHrGEnT6T3/JyC2VZgoOX/X1KwdoU0WYQAeYcQ==", + "version": "1.9.12", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.12.tgz", + "integrity": "sha512-Um5MBuge32TS3lAKX02PGCnFM4xPT996yLgZNb5H03pn6NyJ4Iwn5YcPq6Jj9yxGRk7WOgaZFtVRH5iTdYBeUg==", "dependencies": { "@grpc/proto-loader": "^0.7.8", "@types/node": ">=12.12.47" @@ -2550,16 +2550,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz", - "integrity": "sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.14.0.tgz", + "integrity": "sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/type-utils": "6.13.2", - "@typescript-eslint/utils": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/type-utils": "6.14.0", + "@typescript-eslint/utils": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2585,15 +2585,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.2.tgz", - "integrity": "sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.14.0.tgz", + "integrity": "sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/typescript-estree": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/typescript-estree": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", "debug": "^4.3.4" }, "engines": { @@ -2613,13 +2613,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz", - "integrity": "sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.14.0.tgz", + "integrity": "sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2" + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2630,13 +2630,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz", - "integrity": "sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.14.0.tgz", + "integrity": "sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.13.2", - "@typescript-eslint/utils": "6.13.2", + "@typescript-eslint/typescript-estree": "6.14.0", + "@typescript-eslint/utils": "6.14.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -2657,9 +2657,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz", - "integrity": "sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.14.0.tgz", + "integrity": "sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2670,13 +2670,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz", - "integrity": "sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.14.0.tgz", + "integrity": "sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2697,17 +2697,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.2.tgz", - "integrity": "sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.14.0.tgz", + "integrity": "sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/typescript-estree": "6.13.2", + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/typescript-estree": "6.14.0", "semver": "^7.5.4" }, "engines": { @@ -2722,12 +2722,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz", - "integrity": "sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.14.0.tgz", + "integrity": "sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/types": "6.14.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3582,9 +3582,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001566", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", - "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", + "version": "1.0.30001568", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001568.tgz", + "integrity": "sha512-vSUkH84HontZJ88MiNrOau1EBrCqEQYgkC5gIySiDlpsm8sGVrhU7Kx4V6h0tnqaHzIHZv08HlJIwPbL4XL9+A==", "dev": true, "funding": [ { @@ -4415,9 +4415,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.608", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.608.tgz", - "integrity": "sha512-J2f/3iIIm3Mo0npneITZ2UPe4B1bg8fTNrFjD8715F/k1BvbviRuqYGkET1PgprrczXYTHFvotbBOmUp6KE0uA==", + "version": "1.4.610", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.610.tgz", + "integrity": "sha512-mqi2oL1mfeHYtOdCxbPQYV/PL7YrQlxbvFEZ0Ee8GbDdShimqt2/S6z2RWqysuvlwdOrQdqvE0KZrBTipAeJzg==", "dev": true }, "node_modules/emittery": { @@ -5325,9 +5325,9 @@ "dev": true }, "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -9268,9 +9268,9 @@ } }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -10152,5 +10152,7462 @@ "url": "https://github.com/sponsors/sindresorhus" } } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@angular-devkit/core": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.0.1.tgz", + "integrity": "sha512-2uz98IqkKJlgnHbWQ7VeL4pb+snGAZXIama2KXi+k9GsRntdcw+udX8rL3G9SdUGUF+m6+147Y1oRBMHsO/v4w==", + "dev": true, + "requires": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.0", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "@angular-devkit/schematics": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.0.1.tgz", + "integrity": "sha512-A9D0LTYmiqiBa90GKcSuWb7hUouGIbm/AHbJbjL85WLLRbQA2PwKl7P5Mpd6nS/ZC0kfG4VQY3VOaDvb3qpI9g==", + "dev": true, + "requires": { + "@angular-devkit/core": "16.0.1", + "jsonc-parser": "3.2.0", + "magic-string": "0.30.0", + "ora": "5.4.1", + "rxjs": "7.8.1" + } + }, + "@angular-devkit/schematics-cli": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-16.0.1.tgz", + "integrity": "sha512-6KLA125dpgd6oJGtiO2JpZAb92uOG3njQGIt7NFcuQGW/5GO7J41vMXH9cBAfdtbV8SIggSmR/cIEE9ijfj6YQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "16.0.1", + "@angular-devkit/schematics": "16.0.1", + "ansi-colors": "4.1.3", + "inquirer": "8.2.4", + "symbol-observable": "4.0.0", + "yargs-parser": "21.1.1" + }, + "dependencies": { + "inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + } + } + } + }, + "@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true + }, + "@babel/core": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", + "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.6", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.6", + "convert-source-map": "^2.0.0", + "debug": "^4.3.4", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "requires": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", + "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.6" + } + }, + "@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/runtime": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", + "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/traverse": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.4", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@chirpstack/chirpstack-api": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@chirpstack/chirpstack-api/-/chirpstack-api-4.5.1.tgz", + "integrity": "sha512-GAKb2/EAodgruOs4TF7la3EpZwXrlNJq8uQASvmRRTqFA4XUXsyna1BB+2QZmXxRt/VOA1POM/BsYUY47b2KIQ==", + "requires": { + "@grpc/grpc-js": "^1.9.0", + "@mapbox/node-pre-gyp": "^1.0.11", + "@types/google-protobuf": "^3.15.6", + "google-protobuf": "^3.21.2" + } + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "devOptional": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "devOptional": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.4", + "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": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "dev": true + }, + "@grpc/grpc-js": { + "version": "1.9.12", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.12.tgz", + "integrity": "sha512-Um5MBuge32TS3lAKX02PGCnFM4xPT996yLgZNb5H03pn6NyJ4Iwn5YcPq6Jj9yxGRk7WOgaZFtVRH5iTdYBeUg==", + "requires": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + } + }, + "@grpc/proto-loader": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", + "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "requires": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.4", + "yargs": "^17.7.2" + }, + "dependencies": { + "protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + } + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.3.4", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "requires": { + "@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.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.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "requires": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + } + }, + "@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "requires": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + } + }, + "@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "requires": { + "jest-get-type": "^29.6.3" + } + }, + "@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + } + }, + "@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "requires": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + } + }, + "@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@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", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.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.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": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.27.8" + } + }, + "@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "requires": { + "@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": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "requires": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + } + }, + "@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@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.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": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "requires": { + "@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": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "devOptional": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "devOptional": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==" + }, + "@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "requires": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + } + }, + "@nestjs/axios": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-3.0.1.tgz", + "integrity": "sha512-VlOZhAGDmOoFdsmewn8AyClAdGpKXQQaY1+3PGB+g6ceurGIdTxZgRX3VXc1T6Zs60PedWjg3A82TDOB05mrzQ==", + "requires": {} + }, + "@nestjs/cli": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-9.5.0.tgz", + "integrity": "sha512-Z7q+3vNsQSG2d2r2Hl/OOj5EpfjVx3OfnJ9+KuAsOdw1sKLm7+Zc6KbhMFTd/eIvfx82ww3Nk72xdmfPYCulWA==", + "dev": true, + "requires": { + "@angular-devkit/core": "16.0.1", + "@angular-devkit/schematics": "16.0.1", + "@angular-devkit/schematics-cli": "16.0.1", + "@nestjs/schematics": "^9.0.4", + "chalk": "4.1.2", + "chokidar": "3.5.3", + "cli-table3": "0.6.3", + "commander": "4.1.1", + "fork-ts-checker-webpack-plugin": "8.0.0", + "inquirer": "8.2.5", + "node-emoji": "1.11.0", + "ora": "5.4.1", + "os-name": "4.0.1", + "rimraf": "4.4.1", + "shelljs": "0.8.5", + "source-map-support": "0.5.21", + "tree-kill": "1.2.2", + "tsconfig-paths": "4.2.0", + "tsconfig-paths-webpack-plugin": "4.0.1", + "typescript": "4.9.5", + "webpack": "^5.89.0", + "webpack-node-externals": "3.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + } + }, + "minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true + }, + "rimraf": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", + "dev": true, + "requires": { + "glob": "^9.2.0" + } + } + } + }, + "@nestjs/common": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.4.3.tgz", + "integrity": "sha512-Gd6D4IaYj01o14Bwv81ukidn4w3bPHCblMUq+SmUmWLyosK+XQmInCS09SbDDZyL8jy86PngtBLTdhJ2bXSUig==", + "requires": { + "iterare": "1.2.1", + "tslib": "2.5.3", + "uid": "2.0.2" + } + }, + "@nestjs/config": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-2.3.4.tgz", + "integrity": "sha512-IGdSF+0F9MJO6dCRTEahdxPz4iVijjtolcFBxnY+2QYM3bXYQvAgzskGZi+WkAFJN/VzR3TEp60gN5sI74GxPA==", + "requires": { + "dotenv": "16.1.4", + "dotenv-expand": "10.0.0", + "lodash": "4.17.21", + "uuid": "9.0.0" + }, + "dependencies": { + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + } + } + }, + "@nestjs/core": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.4.3.tgz", + "integrity": "sha512-Qi63+wi55Jh4sDyaj5Hhx2jOpKqT386aeo+VOKsxnd+Ql9VvkO/FjmuwBGUyzkJt29ENYc+P0Sx/k5LtstNpPQ==", + "requires": { + "@nuxtjs/opencollective": "0.3.2", + "fast-safe-stringify": "2.1.1", + "iterare": "1.2.1", + "path-to-regexp": "3.2.0", + "tslib": "2.5.3", + "uid": "2.0.2" + } + }, + "@nestjs/jwt": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-9.0.0.tgz", + "integrity": "sha512-ZsXGY/wMYKzEhymw2+dxiwrHTRKIKrGszx6r2EjQqNLypdXMQu0QrujwZJ8k3+XQV4snmuJwwNakQoA2ILfq8w==", + "requires": { + "@types/jsonwebtoken": "8.5.8", + "jsonwebtoken": "^9.0.0" + } + }, + "@nestjs/mapped-types": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-1.2.2.tgz", + "integrity": "sha512-3dHxLXs3M0GPiriAcCFFJQHoDFUuzTD5w6JDhE7TyfT89YKpe6tcCCIqOZWdXmt9AZjjK30RkHRSFF+QEnWFQg==", + "requires": {} + }, + "@nestjs/passport": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-9.0.3.tgz", + "integrity": "sha512-HplSJaimEAz1IOZEu+pdJHHJhQyBOPAYWXYHfAPQvRqWtw4FJF1VXl1Qtk9dcXQX1eKytDtH+qBzNQc19GWNEg==", + "requires": {} + }, + "@nestjs/platform-express": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-9.4.3.tgz", + "integrity": "sha512-FpdczWoRSC0zz2dNL9u2AQLXKXRVtq4HgHklAhbL59X0uy+mcxhlSThG7DHzDMkoSnuuHY8ojDVf7mDxk+GtCw==", + "requires": { + "body-parser": "1.20.2", + "cors": "2.8.5", + "express": "4.18.2", + "multer": "1.4.4-lts.1", + "tslib": "2.5.3" + } + }, + "@nestjs/schedule": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-2.2.3.tgz", + "integrity": "sha512-PxoGdoBwZQ6SzGfFcERTk7mDxrmesNt2cfqKgtLsFpjYNpV6ZYlKw9Ku8C0ZIjdhy0tBbysj+Fsi3sYua6o6Eg==", + "requires": { + "cron": "2.3.1", + "uuid": "9.0.0" + }, + "dependencies": { + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + } + } + }, + "@nestjs/schematics": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-9.2.0.tgz", + "integrity": "sha512-wHpNJDPzM6XtZUOB3gW0J6mkFCSJilzCM3XrHI1o0C8vZmFE1snbmkIXNyoi1eV0Nxh1BMymcgz5vIMJgQtTqw==", + "dev": true, + "requires": { + "@angular-devkit/core": "16.0.1", + "@angular-devkit/schematics": "16.0.1", + "jsonc-parser": "3.2.0", + "pluralize": "8.0.0" + } + }, + "@nestjs/swagger": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-6.3.0.tgz", + "integrity": "sha512-Gnig189oa1tD+h0BYIfUwhp/wvvmTn6iO3csR2E4rQrDTgCxSxZDlNdfZo3AC+Rmf8u0KX4ZAX1RZN1qXTtC7A==", + "requires": { + "@nestjs/mapped-types": "1.2.2", + "js-yaml": "4.1.0", + "lodash": "4.17.21", + "path-to-regexp": "3.2.0", + "swagger-ui-dist": "4.18.2" + } + }, + "@nestjs/testing": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-9.4.3.tgz", + "integrity": "sha512-LDT8Ai2eKnTzvnPaJwWOK03qTaFap5uHHsJCv6dL0uKWk6hyF9jms8DjyVaGsaujCaXDG8izl1mDEER0OmxaZA==", + "dev": true, + "requires": { + "tslib": "2.5.3" + } + }, + "@nestjs/typeorm": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-9.0.1.tgz", + "integrity": "sha512-A2BgLIPsMtmMI0bPKEf4bmzgFPsnvHqNBx3KkvaJ7hJrBQy0OqYOb+Rr06ifblKWDWS2tUPNrAFQbZjtk3PI+g==", + "requires": { + "uuid": "8.3.2" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@nuxtjs/opencollective": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", + "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==", + "requires": { + "chalk": "^4.1.0", + "consola": "^2.15.0", + "node-fetch": "^2.6.1" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0" + } + }, + "@sqltools/formatter": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", + "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "devOptional": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "devOptional": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "devOptional": true + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "devOptional": true + }, + "@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "requires": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7" + } + }, + "@types/bcryptjs": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz", + "integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==", + "dev": true + }, + "@types/bluebird": { + "version": "3.5.42", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.42.tgz", + "integrity": "sha512-Jhy+MWRlro6UjVi578V/4ZGNfeCOcNCp0YaFNIUGFKlImowqwb1O/22wDVk3FDGMLqxdpOV3qQHD5fPEH4hK6A==", + "dev": true + }, + "@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/cache-manager": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/cache-manager/-/cache-manager-4.0.6.tgz", + "integrity": "sha512-8qL93MF05/xrzFm/LSPtzNEOE1eQF3VwGHAcQEylgp5hDSTe41jtFwbSYAPfyYcVa28y1vYSjIt0c1fLLUiC/Q==", + "dev": true + }, + "@types/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-KoooCrD56qlLskXPLGUiJxOMnv5l/8m7cQD2OxJ73NPMhuSz9PmvwRD6EpjDyKBVrdJDdQ4bQK7JFNHnNmax0w==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true + }, + "@types/cron": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@types/cron/-/cron-1.7.3.tgz", + "integrity": "sha512-iPmUXyIJG1Js+ldPYhOQcYU3kCAQ2FWrSkm1FJPoii2eYSn6wEW6onPukNTT0bfiflexNSRPl6KWmAIqS+36YA==", + "dev": true, + "requires": { + "@types/node": "*", + "moment": ">=2.14.0" + } + }, + "@types/crypto-js": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.1.tgz", + "integrity": "sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw==", + "dev": true + }, + "@types/eslint": { + "version": "8.44.8", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.8.tgz", + "integrity": "sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.41", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", + "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "@types/geojson": { + "version": "7946.0.13", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz", + "integrity": "sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ==", + "dev": true + }, + "@types/google-protobuf": { + "version": "3.15.12", + "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.12.tgz", + "integrity": "sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ==" + }, + "@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "@types/jsonwebtoken": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.8.tgz", + "integrity": "sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A==", + "requires": { + "@types/node": "*" + } + }, + "@types/kafkajs": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@types/kafkajs/-/kafkajs-1.9.0.tgz", + "integrity": "sha512-R9VDNbiw+vNfxWjjFHUrLMF/Dfc7asGXzKtYUwI4FaT24Chf5ZNkfvce54p4dkLMxPcsrEsVazAK0Jp2ib4Zxw==", + "dev": true, + "requires": { + "kafkajs": "*" + } + }, + "@types/lodash": { + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "dev": true + }, + "@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, + "@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==" + }, + "@types/nodemailer": { + "version": "6.4.14", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.14.tgz", + "integrity": "sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "@types/passport": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.16.tgz", + "integrity": "sha512-FD0qD5hbPWQzaM0wHUnJ/T0BBCJBxCeemtnCwc/ThhTg3x9jfrAcRUmj5Dopza+MfFS9acTe3wk7rcVnRIp/0A==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/passport-jwt": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-3.0.13.tgz", + "integrity": "sha512-fjHaC6Bv8EpMMqzTnHP32SXlZGaNfBPC/Po5dmRGYi2Ky7ljXPbGnOy+SxZqa6iZvFgVhoJ1915Re3m93zmcfA==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/jsonwebtoken": "*", + "@types/passport-strategy": "*" + } + }, + "@types/passport-local": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.38.tgz", + "integrity": "sha512-nsrW4A963lYE7lNTv9cr5WmiUD1ibYJvWrpE13oxApFsRt77b0RdtZvKbCdNIY4v/QZ6TRQWaDDEwV1kCTmcXg==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/passport": "*", + "@types/passport-strategy": "*" + } + }, + "@types/passport-saml": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@types/passport-saml/-/passport-saml-1.1.7.tgz", + "integrity": "sha512-pMKJvWlS06ZGXtWVbfULSYDYv9XlvDBhCmzkbuYOqfeVqfpgr2SJKRKvAZ3RK0TzNE2vO67WRSnMbPPz68TyEg==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/passport": "*" + } + }, + "@types/passport-strategy": { + "version": "0.2.38", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz", + "integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/passport": "*" + } + }, + "@types/pem": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/@types/pem/-/pem-1.14.4.tgz", + "integrity": "sha512-Xt6qY6kX1RD4UmYNhWCCf3OSJrRcwbQIaJ/mQSjjAHxIjXMHx/vHNPOgEU3HdVKS1k/U5CZ6ClQlRo8egkl8xg==", + "requires": { + "@types/node": "*" + } + }, + "@types/qs": { + "version": "6.9.10", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", + "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, + "@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "requires": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "@types/superagent": { + "version": "4.1.24", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.24.tgz", + "integrity": "sha512-mEafCgyKiMFin24SDzWN7yAADt4gt6YawFiNMp0QS5ZPboORfyxFt0s3VzJKhTaKg9py/4FUmrHLTNfJKt9Rbw==", + "dev": true, + "requires": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "@types/supertest": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.16.tgz", + "integrity": "sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg==", + "dev": true, + "requires": { + "@types/superagent": "*" + } + }, + "@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, + "@types/validator": { + "version": "13.11.7", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz", + "integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==" + }, + "@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/xml2js": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz", + "integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.14.0.tgz", + "integrity": "sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/type-utils": "6.14.0", + "@typescript-eslint/utils": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/parser": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.14.0.tgz", + "integrity": "sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/typescript-estree": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.14.0.tgz", + "integrity": "sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.14.0.tgz", + "integrity": "sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "6.14.0", + "@typescript-eslint/utils": "6.14.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/types": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.14.0.tgz", + "integrity": "sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.14.0.tgz", + "integrity": "sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/visitor-keys": "6.14.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/utils": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.14.0.tgz", + "integrity": "sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.14.0", + "@typescript-eslint/types": "6.14.0", + "@typescript-eslint/typescript-estree": "6.14.0", + "semver": "^7.5.4" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.14.0.tgz", + "integrity": "sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.14.0", + "eslint-visitor-keys": "^3.4.1" + } + }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@xmldom/xmldom": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz", + "integrity": "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==" + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "devOptional": true + }, + "acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "requires": {} + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "devOptional": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "^4.3.4" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==" + }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "devOptional": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "axios-cache-adapter": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/axios-cache-adapter/-/axios-cache-adapter-2.7.3.tgz", + "integrity": "sha512-A+ZKJ9lhpjthOEp4Z3QR/a9xC4du1ALaAsejgRGrH9ef6kSDxdFrhRpulqsh9khsEnwXxGfgpUuDp1YXMNMEiQ==", + "requires": { + "cache-control-esm": "1.0.0", + "md5": "^2.2.1" + } + }, + "babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "requires": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "dependencies": { + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@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-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@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-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "^4.3.4", + "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.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "requires": { + "streamsearch": "^1.1.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "cache-control-esm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cache-control-esm/-/cache-control-esm-1.0.0.tgz", + "integrity": "sha512-Fa3UV4+eIk4EOih8FTV6EEsVKO0W5XWtNs6FC3InTfVz+EjurjPfDXY5wZDo/lxjDxg5RjNcurLyxEJBcEUx9g==" + }, + "cache-manager": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-4.1.0.tgz", + "integrity": "sha512-ZGM6dLxrP65bfOZmcviWMadUOCICqpLs92+P/S5tj8onz+k+tB7Gr+SAgOUHCQtfm2gYEQDHiKeul4+tYPOJ8A==", + "requires": { + "async": "3.2.3", + "lodash.clonedeep": "^4.5.0", + "lru-cache": "^7.10.1" + } + }, + "call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "requires": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001568", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001568.tgz", + "integrity": "sha512-vSUkH84HontZJ88MiNrOau1EBrCqEQYgkC5gIySiDlpsm8sGVrhU7Kx4V6h0tnqaHzIHZv08HlJIwPbL4XL9+A==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==" + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, + "class-validator": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz", + "integrity": "sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==", + "requires": { + "@types/validator": "^13.7.10", + "libphonenumber-js": "^1.10.14", + "validator": "^13.7.0" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "requires": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "dependencies": { + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "6.0.0-alpha.0", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + } + } + }, + "cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true + }, + "cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "commist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz", + "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", + "requires": { + "leven": "^2.1.0", + "minimist": "^1.1.0" + }, + "dependencies": { + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==" + } + } + }, + "component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "^4.3.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "requires": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + } + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "requires": { + "@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" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "devOptional": true + }, + "cron": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/cron/-/cron-2.3.1.tgz", + "integrity": "sha512-1eRRlIT0UfIqauwbG9pkg3J6CX9A6My2ytJWqAXoK0T9oJnUZTzGBNPxao0zjodIbPgf8UQWjE62BMb9eVllSQ==", + "requires": { + "luxon": "^3.2.1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==" + }, + "crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, + "date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "requires": { + "@babel/runtime": "^7.21.0" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + } + }, + "dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "requires": {} + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "requires": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==" + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "devOptional": true + }, + "diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dotenv": { + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.1.4.tgz", + "integrity": "sha512-m55RtE8AsPeJBpOIFKihEmqUcoVncQIwo7x9U8ZwLEZw9ZpXboz2c+rvog+jUaJvVrZ5kBOeYQBX5+8Aa/OZQw==" + }, + "dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==" + }, + "duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "electron-to-chromium": { + "version": "1.4.610", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.610.tgz", + "integrity": "sha512-mqi2oL1mfeHYtOdCxbPQYV/PL7YrQlxbvFEZ0Ee8GbDdShimqt2/S6z2RWqysuvlwdOrQdqvE0KZrBTipAeJzg==", + "dev": true + }, + "emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, + "es6-promisify": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-7.0.0.tgz", + "integrity": "sha512-ginqzK3J90Rd4/Yz7qRrqUeIpe3TwSXTPPZtPne7tGBPeAaQiU8qt4fpKApnxHcq1AwtUdHVg5P77x/yrggG8Q==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", + "@humanwhocodes/config-array": "^0.11.13", + "@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.4", + "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" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + } + } + }, + "eslint-config-prettier": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", + "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", + "dev": true, + "requires": {} + }, + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, + "expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "requires": { + "@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": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "^4.3.4", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "^4.3.4", + "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", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "requires": { + "@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" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + } + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "^4.3.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" + }, + "fork-ts-checker-webpack-plugin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz", + "integrity": "sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "dev": true, + "requires": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "google-protobuf": { + "version": "3.21.2", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", + "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "requires": { + "get-intrinsic": "^1.2.2" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "help-me": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-3.0.0.tgz", + "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==", + "requires": { + "glob": "^7.1.6", + "readable-stream": "^3.6.0" + } + }, + "hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true + }, + "highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "requires": { + "agent-base": "6", + "debug": "^4.3.4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "isolated-vm": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-4.6.0.tgz", + "integrity": "sha512-MEnfC/54q5PED3VJ9UJYJPOlU6mYFHS3ivR9E8yeNNBEFRFUNBnY0xO4Rj3D/SOtFKPNmsQp9NWUYSKZqAoZiA==", + "requires": { + "prebuild-install": "^7.1.1" + } + }, + "istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", + "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + } + }, + "istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "requires": { + "semver": "^7.5.3" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==" + }, + "jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "requires": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + } + }, + "jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "requires": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + } + }, + "jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "requires": { + "@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": "^1.0.0", + "is-generator-fn": "^2.0.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.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "requires": { + "@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", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + } + }, + "jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@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.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.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + } + }, + "jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + } + }, + "jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + } + }, + "jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "requires": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + } + }, + "jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true + }, + "jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "requires": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + } + }, + "jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + } + }, + "jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@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.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true + }, + "jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "requires": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + } + }, + "jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "requires": { + "@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.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" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "requires": { + "@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.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": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "requires": { + "@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/types": "^7.3.3", + "@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.7.0", + "graceful-fs": "^4.2.9", + "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.7.0", + "semver": "^7.5.3" + } + }, + "jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "requires": { + "@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": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "requires": { + "@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.7.0", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "requires": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "kafkajs": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/kafkajs/-/kafkajs-2.2.4.tgz", + "integrity": "sha512-j/YeapB1vfPT2iOIUn/vxdyKEuhuY2PxMBvf5JWux6iSaukAccrMtXEY/Lb7OvavDhOWME589bpLrEdnVHjfjA==" + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "libphonenumber-js": { + "version": "1.10.51", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.51.tgz", + "integrity": "sha512-vY2I+rQwrDQzoPds0JeTEpeWzbUJgqoV0O4v31PauHBb/e+1KCXKylHcDnBMgJZ9fH9mErsEbROJY3Z3JtqEmg==" + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + }, + "luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==" + }, + "macos-release": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", + "integrity": "sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==", + "dev": true + }, + "magic-string": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", + "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "devOptional": true + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.4" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==" + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "dev": true + }, + "mqtt": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.8.tgz", + "integrity": "sha512-2xT75uYa0kiPEF/PE0VPdavmEkoBzMT/UL9moid0rAvlCtV48qBwxD62m7Ld/4j8tSkIO1E/iqRl/S72SEOhOw==", + "requires": { + "commist": "^1.0.0", + "concat-stream": "^2.0.0", + "debug": "^4.3.4", + "duplexify": "^4.1.1", + "help-me": "^3.0.0", + "inherits": "^2.0.3", + "lru-cache": "^6.0.0", + "minimist": "^1.2.5", + "mqtt-packet": "^6.8.0", + "number-allocator": "^1.0.9", + "pump": "^3.0.0", + "readable-stream": "^3.6.0", + "reinterval": "^1.1.0", + "rfdc": "^1.3.0", + "split2": "^3.1.0", + "ws": "^7.5.5", + "xtend": "^4.0.2" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mqtt-packet": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.10.0.tgz", + "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", + "requires": { + "bl": "^4.0.2", + "debug": "^4.3.4", + "process-nextick-args": "^2.0.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multer": { + "version": "1.4.4-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", + "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "njwt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/njwt/-/njwt-1.2.0.tgz", + "integrity": "sha512-i+cdqwxo7EUimJCHPSAEpQEWrz4ilsVefL+FRhWrjMqq8HHiQ8dwi9GUWUfj3Vt6XMY2PXSjMn9JeVB3/Jp6pg==", + "requires": { + "@types/node": "^15.0.1", + "ecdsa-sig-formatter": "^1.0.5", + "uuid": "^8.3.2" + }, + "dependencies": { + "@types/node": { + "version": "15.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.9.tgz", + "integrity": "sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==" + } + } + }, + "node-abi": { + "version": "3.52.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.52.0.tgz", + "integrity": "sha512-JJ98b02z16ILv7859irtXn4oUaFWADtvkzy2c0IAatNVX2Mc9Yoh8z6hZInn3QwvMEYhHuQloYi+TTQy67SIdQ==", + "requires": { + "semver": "^7.3.5" + } + }, + "node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true + }, + "node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } + }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "nodemailer": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.7.tgz", + "integrity": "sha512-rUtR77ksqex/eZRLmQ21LKVH5nAAsVicAtAYudK7JgwenEDZ0UIQ1adUGqErz7sMkWYxWTTU1aeP2Jga6WQyJw==" + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "number-allocator": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz", + "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==", + "requires": { + "debug": "^4.3.4", + "js-sdsl": "4.3.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + } + }, + "os-name": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-4.0.1.tgz", + "integrity": "sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw==", + "dev": true, + "requires": { + "macos-release": "^2.5.0", + "windows-release": "^4.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "requires": { + "parse5": "^6.0.1" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + } + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "passport": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", + "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + } + }, + "passport-headerapikey": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/passport-headerapikey/-/passport-headerapikey-1.2.2.tgz", + "integrity": "sha512-4BvVJRrWsNJPrd3UoZfcnnl4zvUWYKEtfYkoDsaOKBsrWHYmzTApCjs7qUbncOLexE9ul0IRiYBFfBG0y9IVQA==", + "requires": { + "lodash": "^4.17.15", + "passport-strategy": "^1.0.0" + } + }, + "passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "requires": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==", + "requires": { + "passport-strategy": "1.x.x" + } + }, + "passport-saml": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/passport-saml/-/passport-saml-3.2.4.tgz", + "integrity": "sha512-JSgkFXeaexLNQh1RrOvJAgjLnZzH/S3HbX/mWAk+i7aulnjqUe7WKnPl1NPnJWqP7Dqsv0I2Xm6KIFHkftk0HA==", + "requires": { + "@xmldom/xmldom": "^0.7.6", + "debug": "^4.3.4", + "passport-strategy": "^1.0.0", + "xml-crypto": "^2.1.3", + "xml-encryption": "^2.0.0", + "xml2js": "^0.6.2", + "xmlbuilder": "^15.1.1" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "requires": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "dev": true + } + } + }, + "path-to-regexp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", + "integrity": "sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "pem": { + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/pem/-/pem-1.14.8.tgz", + "integrity": "sha512-ZpbOf4dj9/fQg5tQzTqv4jSKJQsK7tPl0pm4/pvPcZVjZcJg7TMfr3PBk6gJH97lnpJDu4e4v8UUqEz5daipCg==", + "requires": { + "es6-promisify": "^7.0.0", + "md5": "^2.3.0", + "os-tmpdir": "^1.0.2", + "which": "^2.0.2" + } + }, + "pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-cloudflare": "^1.1.1", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "pg-connection-string": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "requires": {} + }, + "pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "requires": { + "split2": "^4.1.0" + }, + "dependencies": { + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + } + } + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + } + } + }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true + }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true + }, + "pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "dependencies": { + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + } + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" + }, + "pure-rand": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", + "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + } + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "reflect-metadata": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", + "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" + }, + "regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + }, + "reinterval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", + "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "^4.3.4", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "requires": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "requires": { + "readable-stream": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "superagent": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", + "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", + "dev": true, + "requires": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "dependencies": { + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + } + } + }, + "supertest": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", + "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", + "dev": true, + "requires": { + "methods": "^1.1.2", + "superagent": "^8.0.5" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "swagger-ui-dist": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.18.2.tgz", + "integrity": "sha512-oVBoBl9Dg+VJw8uRWDxlyUyHoNEDC0c1ysT6+Boy6CTgr2rUcLcfPon4RvxgS2/taNW6O0+US+Z/dlAsWFjOAQ==" + }, + "swagger-ui-express": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.3.tgz", + "integrity": "sha512-CDje4PndhTD2HkgyKH3pab+LKspDeB/NhPN2OF1j+piYIamQqBYwAXWESOT1Yju2xFg51bRW9sUng2WxDjzArw==", + "requires": { + "swagger-ui-dist": ">=4.11.0" + } + }, + "symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + }, + "dependencies": { + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + } + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "terser": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", + "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "dependencies": { + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "requires": {} + }, + "ts-jest": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + } + }, + "ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "devOptional": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "requires": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + } + } + }, + "tsconfig-paths-webpack-plugin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.0.1.tgz", + "integrity": "sha512-m5//KzLoKmqu2MVix+dgLKq70MnFi8YL8sdzQZ6DblmCdfuq/y3OqvJd5vMndg2KEVCOeNz8Es4WVZhYInteLw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tsconfig-paths": "^4.1.2" + } + }, + "tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "typeorm": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.17.tgz", + "integrity": "sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig==", + "requires": { + "@sqltools/formatter": "^1.2.5", + "app-root-path": "^3.1.0", + "buffer": "^6.0.3", + "chalk": "^4.1.2", + "cli-highlight": "^2.1.11", + "date-fns": "^2.29.3", + "debug": "^4.3.4", + "dotenv": "^16.0.3", + "glob": "^8.1.0", + "mkdirp": "^2.1.3", + "reflect-metadata": "^0.1.13", + "sha.js": "^2.4.11", + "tslib": "^2.5.0", + "uuid": "^9.0.0", + "yargs": "^17.6.2" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "mkdirp": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==" + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" + } + } + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "devOptional": true + }, + "uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "requires": { + "@lukeed/csprng": "^1.0.0" + } + }, + "universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "devOptional": true + }, + "v8-to-istanbul": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + } + }, + "validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "wait-for-expect": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/wait-for-expect/-/wait-for-expect-3.0.2.tgz", + "integrity": "sha512-cfS1+DZxuav1aBYbaO/kE06EOS8yRw7qOFoD3XtjTkYvCvh3zUvNST8DXK/nPaeqIzIv3P3kL3lRJn8iwOiSag==" + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "webpack-node-externals": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz", + "integrity": "sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==", + "dev": true + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "windows-release": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", + "integrity": "sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==", + "dev": true, + "requires": { + "execa": "^4.0.2" + }, + "dependencies": { + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + } + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "requires": {} + }, + "xml-crypto": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-2.1.5.tgz", + "integrity": "sha512-xOSJmGFm+BTXmaPYk8pPV3duKo6hJuZ5niN4uMzoNcTlwYs0jAu/N3qY+ud9MhE4N7eMRuC1ayC7Yhmb7MmAWg==", + "requires": { + "@xmldom/xmldom": "^0.7.9", + "xpath": "0.0.32" + } + }, + "xml-encryption": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xml-encryption/-/xml-encryption-2.0.0.tgz", + "integrity": "sha512-4Av83DdvAgUQQMfi/w8G01aJshbEZP9ewjmZMpS9t3H+OCZBDvyK4GJPnHGfWiXlArnPbYvR58JB9qF2x9Ds+Q==", + "requires": { + "@xmldom/xmldom": "^0.7.0", + "escape-html": "^1.0.3", + "xpath": "0.0.32" + } + }, + "xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "dependencies": { + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + } + } + }, + "xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==" + }, + "xpath": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz", + "integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "6.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-6.0.0-alpha.0.tgz", + "integrity": "sha512-J9CO+Qo98a30YwPMgXt1IetZS4823Y+KzBEWHPQYaO2sWcwtvVascTF0eNdUgU0Me3Efl36PnCygmVPdzqQmJg==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "6.0.0-alpha.0", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "devOptional": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } } } diff --git a/src/services/chirpstack/chirpstack-device.service.ts b/src/services/chirpstack/chirpstack-device.service.ts index 36916e81..9ae09ac1 100644 --- a/src/services/chirpstack/chirpstack-device.service.ts +++ b/src/services/chirpstack/chirpstack-device.service.ts @@ -32,7 +32,7 @@ import { ConfigService } from "@nestjs/config"; import { DeviceServiceClient } from "@chirpstack/chirpstack-api/api/device_grpc_pb"; import { DeviceProfileService } from "@services/chirpstack/device-profile.service"; -import { ServiceError, credentials } from "@grpc/grpc-js"; +import { ServiceError } from "@grpc/grpc-js"; import { Application, CreateApplicationRequest, diff --git a/src/services/chirpstack/chirpstack-gateway.service.ts b/src/services/chirpstack/chirpstack-gateway.service.ts index 07b53d5e..18479cc2 100644 --- a/src/services/chirpstack/chirpstack-gateway.service.ts +++ b/src/services/chirpstack/chirpstack-gateway.service.ts @@ -33,7 +33,6 @@ import { GetGatewayResponse, UpdateGatewayRequest, } from "@chirpstack/chirpstack-api/api/gateway_pb"; -import { credentials } from "@grpc/grpc-js"; import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; import { Aggregation, Location } from "@chirpstack/chirpstack-api/common/common_pb"; import { dateToTimestamp, timestampToDate } from "@helpers/date.helper"; diff --git a/src/services/chirpstack/device-profile.service.ts b/src/services/chirpstack/device-profile.service.ts index 1e05dc18..0c9b052e 100644 --- a/src/services/chirpstack/device-profile.service.ts +++ b/src/services/chirpstack/device-profile.service.ts @@ -16,8 +16,7 @@ import { DeviceProfileDto } from "@dto/chirpstack/device-profile.dto"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; import { ErrorCodes } from "@enum/error-codes.enum"; import { checkIfUserHasAccessToOrganization, OrganizationAccessScope } from "@helpers/security-helper"; -import { DeviceProfileServiceClient } from "@chirpstack/chirpstack-api/api/device_profile_grpc_pb"; -import { credentials, ServiceError } from "@grpc/grpc-js"; +import { ServiceError } from "@grpc/grpc-js"; import { CreateDeviceProfileRequest, DeleteDeviceProfileRequest, diff --git a/src/services/chirpstack/multicast.service.ts b/src/services/chirpstack/multicast.service.ts index 09ccc354..9cf4df27 100644 --- a/src/services/chirpstack/multicast.service.ts +++ b/src/services/chirpstack/multicast.service.ts @@ -50,7 +50,7 @@ import { UpdateMulticastGroupRequest, } from "@chirpstack/chirpstack-api/api/multicast_group_pb"; import { MulticastGroupServiceClient } from "@chirpstack/chirpstack-api/api/multicast_group_grpc_pb"; -import { credentials, ServiceError } from "@grpc/grpc-js"; +import { ServiceError } from "@grpc/grpc-js"; import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; import { multicastGroup } from "@enum/multicast-type.enum"; @Injectable() From 25c83f5b5bdf3747c3452ef7cbd4f1d8a924f9c0 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Tue, 12 Dec 2023 14:28:46 +0100 Subject: [PATCH 13/24] formatting and bumped chirpstack-api --- package-lock.json | 16 +-- package.json | 5 +- .../chirpstack-gateway.controller.ts | 15 +-- .../chirpstack/device-profile.controller.ts | 24 +---- .../admin-controller/iot-device.controller.ts | 95 ++++-------------- .../admin-controller/multicast.controller.ts | 87 +++-------------- .../chirpstack/device-profile.service.ts | 4 +- .../chirpstack/gateway-boostrapper.service.ts | 38 +++----- src/services/chirpstack/multicast.service.ts | 97 ++++--------------- .../chirpstack-mqtt-listener.service.ts | 20 +--- .../iot-device-downlink.service.ts | 39 ++------ 11 files changed, 103 insertions(+), 337 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1025789b..a4e8ebe3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "license": "Mozilla Public License Version 2.0", "dependencies": { - "@chirpstack/chirpstack-api": "4.5.1", + "@chirpstack/chirpstack-api": "4.6.0", "@grpc/grpc-js": "1.9.12", "@nestjs/axios": "^3.0.0", "@nestjs/common": "^9.1.2", @@ -911,9 +911,9 @@ "dev": true }, "node_modules/@chirpstack/chirpstack-api": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@chirpstack/chirpstack-api/-/chirpstack-api-4.5.1.tgz", - "integrity": "sha512-GAKb2/EAodgruOs4TF7la3EpZwXrlNJq8uQASvmRRTqFA4XUXsyna1BB+2QZmXxRt/VOA1POM/BsYUY47b2KIQ==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@chirpstack/chirpstack-api/-/chirpstack-api-4.6.0.tgz", + "integrity": "sha512-bGXKbWisX3tMWa9GxazVP87za2EzkoJuUIwgJGmwbHtSTz/bZqCLYhOG+77yt881qLFxUmzAsnVNTQFLE1whHQ==", "dependencies": { "@grpc/grpc-js": "^1.9.0", "@mapbox/node-pre-gyp": "^1.0.11", @@ -10772,11 +10772,11 @@ "dev": true }, "@chirpstack/chirpstack-api": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@chirpstack/chirpstack-api/-/chirpstack-api-4.5.1.tgz", - "integrity": "sha512-GAKb2/EAodgruOs4TF7la3EpZwXrlNJq8uQASvmRRTqFA4XUXsyna1BB+2QZmXxRt/VOA1POM/BsYUY47b2KIQ==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@chirpstack/chirpstack-api/-/chirpstack-api-4.6.0.tgz", + "integrity": "sha512-bGXKbWisX3tMWa9GxazVP87za2EzkoJuUIwgJGmwbHtSTz/bZqCLYhOG+77yt881qLFxUmzAsnVNTQFLE1whHQ==", "requires": { - "@grpc/grpc-js": "^1.9.0", + "@grpc/grpc-js": "1.9.12", "@mapbox/node-pre-gyp": "^1.0.11", "@types/google-protobuf": "^3.15.6", "google-protobuf": "^3.21.2" diff --git a/package.json b/package.json index 17a9450e..5b7b69b3 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ }, "dependencies": { "@nestjs/axios": "^3.0.0", - "@chirpstack/chirpstack-api": "4.5.1", + "@chirpstack/chirpstack-api": "4.6.0", "@grpc/grpc-js": "1.9.12", "@nestjs/common": "^9.1.2", "@nestjs/config": "^2.2.0", @@ -125,6 +125,7 @@ "xml2js": "^0.6.2", "jsonwebtoken": "^9.0.0", "debug": "^4.3.4", - "y18n": "6.0.0-alpha.0" + "y18n": "6.0.0-alpha.0", + "@grpc/grpc-js": "1.9.12" } } diff --git a/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts b/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts index 336c17c8..3202caf9 100644 --- a/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts +++ b/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts @@ -23,10 +23,7 @@ import { SingleGatewayResponseDto } from "@dto/chirpstack/single-gateway-respons import { UpdateGatewayDto } from "@dto/chirpstack/update-gateway.dto"; import { ErrorCodes } from "@enum/error-codes.enum"; import { ChirpstackGatewayService } from "@services/chirpstack/chirpstack-gateway.service"; -import { - checkIfUserHasAccessToOrganization, - OrganizationAccessScope, -} from "@helpers/security-helper"; +import { checkIfUserHasAccessToOrganization, OrganizationAccessScope } from "@helpers/security-helper"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; import { AuditLog } from "@services/audit-log.service"; import { ActionType } from "@entities/audit-log-entry"; @@ -46,11 +43,7 @@ export class ChirpstackGatewayController { @ApiBadRequestResponse() @GatewayAdmin() async create(@Req() req: AuthenticatedRequest, @Body() dto: CreateGatewayDto): Promise { - checkIfUserHasAccessToOrganization( - req, - dto.organizationId, - OrganizationAccessScope.GatewayWrite - ); + checkIfUserHasAccessToOrganization(req, dto.organizationId, OrganizationAccessScope.GatewayWrite); try { const gateway = await this.chirpstackGatewayService.createNewGateway(dto, req.user.userId); AuditLog.success( @@ -81,9 +74,7 @@ export class ChirpstackGatewayController { @ApiProduces("application/json") @ApiOperation({ summary: "List all Chirpstack gateways" }) @Read() - async getAll( - @Query() query?: ChirpstackGetAll - ): Promise { + async getAll(@Query() query?: ChirpstackGetAll): Promise { return await this.chirpstackGatewayService.getAll(query.organizationId); } diff --git a/src/controllers/admin-controller/chirpstack/device-profile.controller.ts b/src/controllers/admin-controller/chirpstack/device-profile.controller.ts index f7811dfc..9ce47408 100644 --- a/src/controllers/admin-controller/chirpstack/device-profile.controller.ts +++ b/src/controllers/admin-controller/chirpstack/device-profile.controller.ts @@ -33,10 +33,7 @@ import { DeleteResponseDto } from "@dto/delete-application-response.dto"; import { ErrorCodes } from "@enum/error-codes.enum"; import { DeviceProfileService } from "@services/chirpstack/device-profile.service"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; -import { - checkIfUserHasAccessToOrganization, - OrganizationAccessScope, -} from "@helpers/security-helper"; +import { checkIfUserHasAccessToOrganization, OrganizationAccessScope } from "@helpers/security-helper"; import { AuditLog } from "@services/audit-log.service"; import { ActionType } from "@entities/audit-log-entry"; import { ComposeAuthGuard } from "@auth/compose-auth.guard"; @@ -70,10 +67,7 @@ export class DeviceProfileController { ); try { - const result = await this.deviceProfileService.createDeviceProfile( - createDto, - req.user.userId - ); + const result = await this.deviceProfileService.createDeviceProfile(createDto, req.user.userId); AuditLog.success( ActionType.CREATE, @@ -176,14 +170,9 @@ export class DeviceProfileController { let result = undefined; try { this.logger.debug(`Limit: '${limit}' Offset:'${offset}'`); - result = await this.deviceProfileService.findAllDeviceProfiles( - limit || 50, - offset || 0 - ); + result = await this.deviceProfileService.findAllDeviceProfiles(limit || 50, offset || 0); } catch (err) { - this.logger.error( - `Error occured during Find all: '${JSON.stringify(err?.response?.data)}'` - ); + this.logger.error(`Error occured during Find all: '${JSON.stringify(err?.response?.data)}'`); } return result; } @@ -192,10 +181,7 @@ export class DeviceProfileController { @ApiOperation({ summary: "Delete one DeviceProfile by id" }) @ApiNotFoundResponse() @ApplicationAdmin() - async deleteOne( - @Req() req: AuthenticatedRequest, - @Param("id") id: string - ): Promise { + async deleteOne(@Req() req: AuthenticatedRequest, @Param("id") id: string): Promise { try { await this.deviceProfileService.deleteDeviceProfile(id, req); AuditLog.success(ActionType.DELETE, "ChirpstackDeviceProfile", req.user.userId, id); diff --git a/src/controllers/admin-controller/iot-device.controller.ts b/src/controllers/admin-controller/iot-device.controller.ts index 7922877f..901c3a72 100644 --- a/src/controllers/admin-controller/iot-device.controller.ts +++ b/src/controllers/admin-controller/iot-device.controller.ts @@ -35,15 +35,11 @@ import { LoRaWANDeviceWithChirpstackDataDto } from "@dto/lorawan-device-with-chi import { UpdateIoTDeviceDto } from "@dto/update-iot-device.dto"; import { IoTDevice } from "@entities/iot-device.entity"; import { ErrorCodes } from "@enum/error-codes.enum"; -import { - ApplicationAccessScope, - checkIfUserHasAccessToApplication, -} from "@helpers/security-helper"; +import { ApplicationAccessScope, checkIfUserHasAccessToApplication } from "@helpers/security-helper"; import { IoTDeviceService } from "@services/device-management/iot-device.service"; import { SigFoxDeviceWithBackendDataDto } from "@dto/sigfox-device-with-backend-data.dto"; import { CreateIoTDeviceDownlinkDto } from "@dto/create-iot-device-downlink.dto"; import { IoTDeviceDownlinkService } from "@services/device-management/iot-device-downlink.service"; -import { CreateChirpstackDeviceQueueItemResponse } from "@dto/chirpstack/create-chirpstack-device-queue-item.dto"; import { ChirpstackDeviceService } from "@services/chirpstack/chirpstack-device.service"; import { DeviceDownlinkQueueResponseDto } from "@dto/chirpstack/chirpstack-device-downlink-queue-response.dto"; import { IoTDeviceType } from "@enum/device-type.enum"; @@ -127,9 +123,7 @@ export class IoTDeviceController { } checkIfUserHasAccessToApplication(req, device.application.id, ApplicationAccessScope.Read); if (device.type === IoTDeviceType.LoRaWAN) { - return this.chirpstackDeviceService.getDownlinkQueue( - (device as LoRaWANDevice).deviceEUI - ); + return this.chirpstackDeviceService.getDownlinkQueue((device as LoRaWANDevice).deviceEUI); } else if (device.type === IoTDeviceType.SigFox) { return this.iotDeviceService.getDownlinkForSigfox(device as SigFoxDevice); } else { @@ -155,30 +149,15 @@ export class IoTDeviceController { @Header("Cache-Control", "none") @ApiOperation({ summary: "Create a new IoTDevice" }) @ApiBadRequestResponse() - async create( - @Req() req: AuthenticatedRequest, - @Body() createDto: CreateIoTDeviceDto - ): Promise { + async create(@Req() req: AuthenticatedRequest, @Body() createDto: CreateIoTDeviceDto): Promise { try { - checkIfUserHasAccessToApplication( - req, - createDto.applicationId, - ApplicationAccessScope.Write - ); + checkIfUserHasAccessToApplication(req, createDto.applicationId, ApplicationAccessScope.Write); const device = await this.iotDeviceService.create(createDto, req.user.userId); - AuditLog.success( - ActionType.CREATE, - IoTDevice.name, - req.user.userId, - device.id, - device.name - ); + AuditLog.success(ActionType.CREATE, IoTDevice.name, req.user.userId, device.id, device.name); return device; } catch (err) { AuditLog.fail(ActionType.CREATE, IoTDevice.name, req.user.userId); - this.logger.error( - `Failed to create IoTDevice from dto: ${JSON.stringify(createDto)}. Error: ${err}` - ); + this.logger.error(`Failed to create IoTDevice from dto: ${JSON.stringify(createDto)}. Error: ${err}`); throw err; } } @@ -197,11 +176,7 @@ export class IoTDeviceController { if (!device) { throw new NotFoundException(); } - checkIfUserHasAccessToApplication( - req, - device?.application?.id, - ApplicationAccessScope.Write - ); + checkIfUserHasAccessToApplication(req, device?.application?.id, ApplicationAccessScope.Write); const result = await this.downlinkService.createDownlink(dto, device); AuditLog.success(ActionType.CREATE, "Downlink", req.user.userId); return result; @@ -221,23 +196,12 @@ export class IoTDeviceController { @Body() updateDto: UpdateIoTDeviceDto ): Promise { // Old application - const oldIotDevice = await this.iotDeviceService.findOneWithApplicationAndMetadata( - id, - false - ); + const oldIotDevice = await this.iotDeviceService.findOneWithApplicationAndMetadata(id, false); try { - checkIfUserHasAccessToApplication( - req, - oldIotDevice.application.id, - ApplicationAccessScope.Write - ); + checkIfUserHasAccessToApplication(req, oldIotDevice.application.id, ApplicationAccessScope.Write); if (updateDto.applicationId !== oldIotDevice.application.id) { // New application - checkIfUserHasAccessToApplication( - req, - updateDto.applicationId, - ApplicationAccessScope.Write - ); + checkIfUserHasAccessToApplication(req, updateDto.applicationId, ApplicationAccessScope.Write); } } catch (err) { AuditLog.fail(ActionType.UPDATE, IoTDevice.name, req.user.userId, id); @@ -245,13 +209,7 @@ export class IoTDeviceController { } const iotDevice = await this.iotDeviceService.update(id, updateDto, req.user.userId); - AuditLog.success( - ActionType.UPDATE, - IoTDevice.name, - req.user.userId, - iotDevice.id, - iotDevice.name - ); + AuditLog.success(ActionType.UPDATE, IoTDevice.name, req.user.userId, iotDevice.id, iotDevice.name); return iotDevice; } @@ -265,11 +223,7 @@ export class IoTDeviceController { ): Promise { try { createDto.data.forEach(createDto => - checkIfUserHasAccessToApplication( - req, - createDto.applicationId, - ApplicationAccessScope.Write - ) + checkIfUserHasAccessToApplication(req, createDto.applicationId, ApplicationAccessScope.Write) ); const devices = await this.iotDeviceService.createMany(createDto.data, req.user.userId); @@ -291,9 +245,7 @@ export class IoTDeviceController { return devices; } catch (err) { AuditLog.fail(ActionType.CREATE, IoTDevice.name, req.user.userId); - this.logger.error( - `Failed to create IoTDevice from dto: ${JSON.stringify(createDto)}. Error: ${err}` - ); + this.logger.error(`Failed to create IoTDevice from dto: ${JSON.stringify(createDto)}. Error: ${err}`); throw err; } } @@ -351,15 +303,8 @@ export class IoTDeviceController { @Param("id", new ParseIntPipe()) id: number ): Promise { try { - const oldIotDevice = await this.iotDeviceService.findOneWithApplicationAndMetadata( - id, - false - ); - checkIfUserHasAccessToApplication( - req, - oldIotDevice?.application?.id, - ApplicationAccessScope.Write - ); + const oldIotDevice = await this.iotDeviceService.findOneWithApplicationAndMetadata(id, false); + checkIfUserHasAccessToApplication(req, oldIotDevice?.application?.id, ApplicationAccessScope.Write); const result = await this.iotDeviceService.delete(oldIotDevice); AuditLog.success(ActionType.DELETE, IoTDevice.name, req.user.userId, id); return new DeleteResponseDto(result.affected); @@ -378,19 +323,13 @@ export class IoTDeviceController { ): Promise> { try { const oldIotDevice = await this.iotDeviceService.findOne(id); - checkIfUserHasAccessToApplication( - req, - oldIotDevice?.application?.id, - ApplicationAccessScope.Write - ); + checkIfUserHasAccessToApplication(req, oldIotDevice?.application?.id, ApplicationAccessScope.Write); if (oldIotDevice.type !== IoTDeviceType.GenericHttp) { throw new BadRequestException("The requested device is not a generic HTTP device"); } - const result = await this.iotDeviceService.resetHttpDeviceApiKey( - oldIotDevice as GenericHTTPDevice - ); + const result = await this.iotDeviceService.resetHttpDeviceApiKey(oldIotDevice as GenericHTTPDevice); AuditLog.success(ActionType.UPDATE, IoTDevice.name, req.user.userId, id); return { apiKey: result.apiKey, diff --git a/src/controllers/admin-controller/multicast.controller.ts b/src/controllers/admin-controller/multicast.controller.ts index b8eda2bb..e6bf7d19 100644 --- a/src/controllers/admin-controller/multicast.controller.ts +++ b/src/controllers/admin-controller/multicast.controller.ts @@ -27,13 +27,10 @@ import { } from "@nestjs/swagger"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; import { Multicast } from "@entities/multicast.entity"; -import { - checkIfUserHasAccessToApplication, - ApplicationAccessScope, -} from "@helpers/security-helper"; +import { checkIfUserHasAccessToApplication, ApplicationAccessScope } from "@helpers/security-helper"; import { AuditLog } from "@services/audit-log.service"; import { ActionType } from "@entities/audit-log-entry"; -import { ComposeAuthGuard } from '@auth/compose-auth.guard'; +import { ComposeAuthGuard } from "@auth/compose-auth.guard"; import { RolesGuard } from "@auth/roles.guard"; import { Read, ApplicationAdmin } from "@auth/roles.decorator"; import { ListAllMulticastsDto } from "@dto/list-all-multicasts.dto"; @@ -59,27 +56,11 @@ export class MulticastController { @Post() @ApiOperation({ summary: "Create a new multicast" }) @ApiBadRequestResponse() - async create( - @Req() req: AuthenticatedRequest, - @Body() createMulticastDto: CreateMulticastDto - ): Promise { + async create(@Req() req: AuthenticatedRequest, @Body() createMulticastDto: CreateMulticastDto): Promise { try { - checkIfUserHasAccessToApplication( - req, - createMulticastDto.applicationID, - ApplicationAccessScope.Write - ); - const multicast = await this.multicastService.create( - createMulticastDto, - req.user.userId - ); - AuditLog.success( - ActionType.CREATE, - Multicast.name, - req.user.userId, - multicast.id, - multicast.groupName - ); + checkIfUserHasAccessToApplication(req, createMulticastDto.applicationID, ApplicationAccessScope.Write); + const multicast = await this.multicastService.create(createMulticastDto, req.user.userId); + AuditLog.success(ActionType.CREATE, Multicast.name, req.user.userId, multicast.id, multicast.groupName); return multicast; } catch (err) { AuditLog.fail(ActionType.CREATE, Multicast.name, req.user.userId); @@ -106,26 +87,16 @@ export class MulticastController { throw new UnauthorizedException(); } - return await this.multicastService.findAndCountAllWithPagination( - query, - allowed - ); + return await this.multicastService.findAndCountAllWithPagination(query, allowed); } } @Get(":id") @ApiOperation({ summary: "Find Multicast by id" }) - async findOne( - @Req() req: AuthenticatedRequest, - @Param("id", new ParseIntPipe()) id: number - ): Promise { + async findOne(@Req() req: AuthenticatedRequest, @Param("id", new ParseIntPipe()) id: number): Promise { try { const multicast = await this.multicastService.findOne(id); - checkIfUserHasAccessToApplication( - req, - multicast.application.id, - ApplicationAccessScope.Read - ); + checkIfUserHasAccessToApplication(req, multicast.application.id, ApplicationAccessScope.Read); return multicast; } catch (err) { throw new NotFoundException(ErrorCodes.IdDoesNotExists); @@ -148,15 +119,9 @@ export class MulticastController { if (!multicast) { throw new NotFoundException(ErrorCodes.IdDoesNotExists); } - checkIfUserHasAccessToApplication( - req, - multicast.application.id, - ApplicationAccessScope.Read - ); + checkIfUserHasAccessToApplication(req, multicast.application.id, ApplicationAccessScope.Read); - return this.multicastService.getDownlinkQueue( - multicast.lorawanMulticastDefinition.chirpstackGroupId - ); + return this.multicastService.getDownlinkQueue(multicast.lorawanMulticastDefinition.chirpstackGroupId); } @Post(":id/downlink-multicast") @@ -173,11 +138,7 @@ export class MulticastController { if (!multicast) { throw new NotFoundException(); } - checkIfUserHasAccessToApplication( - req, - multicast.application.id, - ApplicationAccessScope.Write - ); + checkIfUserHasAccessToApplication(req, multicast.application.id, ApplicationAccessScope.Write); const result = await this.multicastService.createDownlink(dto, multicast); AuditLog.success(ActionType.CREATE, "Downlink", req.user.userId); return result; @@ -198,17 +159,9 @@ export class MulticastController { ): Promise { const oldMulticast = await this.multicastService.findOne(id); try { - checkIfUserHasAccessToApplication( - req, - oldMulticast.application.id, - ApplicationAccessScope.Write - ); + checkIfUserHasAccessToApplication(req, oldMulticast.application.id, ApplicationAccessScope.Write); if (oldMulticast.application.id !== updateDto.applicationID) { - checkIfUserHasAccessToApplication( - req, - updateDto.applicationID, - ApplicationAccessScope.Write - ); + checkIfUserHasAccessToApplication(req, updateDto.applicationID, ApplicationAccessScope.Write); } } catch (err) { AuditLog.fail( @@ -221,11 +174,7 @@ export class MulticastController { throw err; } - const multicast = await this.multicastService.update( - oldMulticast, - updateDto, - req.user.userId - ); + const multicast = await this.multicastService.update(oldMulticast, updateDto, req.user.userId); AuditLog.success( ActionType.UPDATE, Multicast.name, @@ -246,11 +195,7 @@ export class MulticastController { ): Promise { try { const multicast = await this.multicastService.findOne(id); - checkIfUserHasAccessToApplication( - req, - multicast.application.id, - ApplicationAccessScope.Write - ); + checkIfUserHasAccessToApplication(req, multicast.application.id, ApplicationAccessScope.Write); const result = await this.multicastService.multicastDelete(id, multicast); if (result.affected === 0) { diff --git a/src/services/chirpstack/device-profile.service.ts b/src/services/chirpstack/device-profile.service.ts index 0c9b052e..14ba1610 100644 --- a/src/services/chirpstack/device-profile.service.ts +++ b/src/services/chirpstack/device-profile.service.ts @@ -35,6 +35,7 @@ import { AdrAlgorithmDto } from "@dto/chirpstack/adr-algorithm.dto"; import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; import { DeviceListItem, ListDevicesRequest, ListDevicesResponse } from "@chirpstack/chirpstack-api/api/device_pb"; import { ListApplicationsRequest, ListApplicationsResponse } from "@chirpstack/chirpstack-api/api/application_pb"; +import * as google_protobuf_empty_pb from "google-protobuf/google/protobuf/empty_pb"; @Injectable() export class DeviceProfileService extends GenericChirpstackConfigurationService { @@ -351,8 +352,9 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService async getAdrAlgorithms(): Promise { const metaData = this.makeMetadataHeader(); + const test: google_protobuf_empty_pb.Empty = new Empty() const getPromise = new Promise((resolve, reject) => { - this.deviceProfileClient.listAdrAlgorithms(new Empty(), metaData, (err: ServiceError, resp: any) => { + this.deviceProfileClient.listAdrAlgorithms(test, metaData, (err: ServiceError, resp: any) => { if (err) { reject(err); } else { diff --git a/src/services/chirpstack/gateway-boostrapper.service.ts b/src/services/chirpstack/gateway-boostrapper.service.ts index 8d26ddcc..c5097b54 100644 --- a/src/services/chirpstack/gateway-boostrapper.service.ts +++ b/src/services/chirpstack/gateway-boostrapper.service.ts @@ -28,41 +28,35 @@ export class GatewayBootstrapperService implements OnApplicationBootstrap { } } - /** + /** * Populate the gateway status table with an entry for each new gateway. * @param gateways All chirpstack gateways * @param statusHistories Existing status histories to check against */ - private async seedGatewayStatus( - gateways: ListAllGatewaysResponseGrpcDto, - statusHistories: GatewayStatusHistory[] - ) { + private async seedGatewayStatus(gateways: ListAllGatewaysResponseGrpcDto, statusHistories: GatewayStatusHistory[]) { const now = new Date(); const errorTime = new Date(); errorTime.setSeconds(errorTime.getSeconds() - 150); // Don't overwrite ones which already have a status history - const newHistoriesForMissingGateways = gateways.resultList.reduce( - (res: GatewayStatusHistory[], gateway) => { - if (!statusHistories.some(history => history.mac === gateway.gatewayId)) { - // Best fit is to imitate the status logic from Chirpstack. - if (gateway.lastSeenAt) { - const lastSeenDate = timestampToDate(gateway.lastSeenAt); + const newHistoriesForMissingGateways = gateways.resultList.reduce((res: GatewayStatusHistory[], gateway) => { + if (!statusHistories.some(history => history.mac === gateway.gatewayId)) { + // Best fit is to imitate the status logic from Chirpstack. + if (gateway.lastSeenAt) { + const lastSeenDate = timestampToDate(gateway.lastSeenAt); - const wasOnline = errorTime.getTime() < lastSeenDate.getTime(); + const wasOnline = errorTime.getTime() < lastSeenDate.getTime(); - res.push({ - mac: gateway.gatewayId, - timestamp: now, - wasOnline, - } as GatewayStatusHistory); - } + res.push({ + mac: gateway.gatewayId, + timestamp: now, + wasOnline, + } as GatewayStatusHistory); } + } - return res; - }, - [] - ); + return res; + }, []); if (newHistoriesForMissingGateways.length) { await this.statusHistoryService.createMany(newHistoriesForMissingGateways); diff --git a/src/services/chirpstack/multicast.service.ts b/src/services/chirpstack/multicast.service.ts index 9cf4df27..12cb50ac 100644 --- a/src/services/chirpstack/multicast.service.ts +++ b/src/services/chirpstack/multicast.service.ts @@ -3,14 +3,7 @@ import { ListAllMulticastsResponseDto } from "@dto/list-all-multicasts-response. import { ListAllMulticastsDto } from "@dto/list-all-multicasts.dto"; import { Multicast } from "@entities/multicast.entity"; import { ErrorCodes } from "@enum/error-codes.enum"; -import { - BadRequestException, - forwardRef, - Inject, - Injectable, - Logger, - NotFoundException, -} from "@nestjs/common"; +import { BadRequestException, forwardRef, Inject, Injectable, Logger, NotFoundException } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; import { DeleteResult, Repository, SelectQueryBuilder } from "typeorm"; @@ -134,10 +127,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { const dbMulticast = new Multicast(); dbMulticast.lorawanMulticastDefinition = new LorawanMulticastDefinition(); - const mappedDbMulticast = await this.mapMulticastDtoToDbMulticast( - createMulticastDto, - dbMulticast - ); + const mappedDbMulticast = await this.mapMulticastDtoToDbMulticast(createMulticastDto, dbMulticast); mappedDbMulticast.createdBy = userId; mappedDbMulticast.updatedBy = userId; mappedDbMulticast.lorawanMulticastDefinition.createdBy = userId; @@ -148,11 +138,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { if (lorawanDevices.length > 0) { if (await this.checkForDifferentAppID(lorawanDevices)) { // If they all have same serviceID / appID then proceed. - await this.createMulticastInChirpstack( - createMulticastDto, - lorawanDevices, - mappedDbMulticast - ); + await this.createMulticastInChirpstack(createMulticastDto, lorawanDevices, mappedDbMulticast); } else { throw new BadRequestException(ErrorCodes.InvalidPost); } @@ -172,11 +158,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { ); const req = new CreateMulticastGroupRequest(); req.setMulticastGroup(mappedChirpStackMulticast); - const result: PostReturnInterface = await this.post( - this.multicastGroupUrl, - this.multicastServiceClient, - req - ); // This creates the multicast in chirpstack. Chirpstack returns an id as a string + const result: PostReturnInterface = await this.post(this.multicastGroupUrl, this.multicastServiceClient, req); // This creates the multicast in chirpstack. Chirpstack returns an id as a string await this.addDevices(createMulticastDto, result); // iotDevices are added to multicast in a seperate endpoint. @@ -193,27 +175,15 @@ export class MulticastService extends GenericChirpstackConfigurationService { userId: number ): Promise { const oldMulticast: Multicast = { ...existingMulticast }; - const mappedMulticast = await this.mapMulticastDtoToDbMulticast( - updateMulticastDto, - existingMulticast - ); + const mappedMulticast = await this.mapMulticastDtoToDbMulticast(updateMulticastDto, existingMulticast); const lorawanDevices = this.checkForLorawan(updateMulticastDto); const oldLorawanDevices = this.checkForLorawan(oldMulticast); if (lorawanDevices.length > 0 || oldLorawanDevices.length > 0) { // check if new lorawan devices is included. If so, either create or update in chirpstack. Otherwise, just update db if (!existingMulticast.lorawanMulticastDefinition.chirpstackGroupId) { - await this.createIfNotInChirpstack( - lorawanDevices, - updateMulticastDto, - mappedMulticast - ); + await this.createIfNotInChirpstack(lorawanDevices, updateMulticastDto, mappedMulticast); } else { - await this.updateLogic( - existingMulticast, - lorawanDevices, - updateMulticastDto, - oldMulticast - ); + await this.updateLogic(existingMulticast, lorawanDevices, updateMulticastDto, oldMulticast); } } mappedMulticast.updatedBy = userId; @@ -250,12 +220,8 @@ export class MulticastService extends GenericChirpstackConfigurationService { } } - checkForLorawan( - multicastDto: CreateMulticastDto | Multicast | UpdateMulticastDto - ): LoRaWANDevice[] { - const lorawanDevices = multicastDto.iotDevices.filter( - x => x.type === IoTDeviceType.LoRaWAN - ) as LoRaWANDevice[]; + checkForLorawan(multicastDto: CreateMulticastDto | Multicast | UpdateMulticastDto): LoRaWANDevice[] { + const lorawanDevices = multicastDto.iotDevices.filter(x => x.type === IoTDeviceType.LoRaWAN) as LoRaWANDevice[]; return lorawanDevices; } @@ -266,9 +232,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { const devices: ChirpstackDeviceContentsDto[] = []; for (let index = 0; index < lorawanDevices.length; index++) { - const lora = await this.chirpStackDeviceService.getChirpstackDevice( - lorawanDevices[index].deviceEUI - ); + const lora = await this.chirpStackDeviceService.getChirpstackDevice(lorawanDevices[index].deviceEUI); devices.push(lora); } @@ -286,9 +250,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { const devices: ChirpstackDeviceContentsDto[] = []; for (let index = 0; index < lorawanDevices.length; index++) { - const lora = await this.chirpStackDeviceService.getChirpstackDevice( - lorawanDevices[index].deviceEUI - ); + const lora = await this.chirpStackDeviceService.getChirpstackDevice(lorawanDevices[index].deviceEUI); devices.push(lora); } if (devices.length > 0) { @@ -336,9 +298,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { async multicastDelete(id: number, existingMulticast: Multicast): Promise { const loraDevices = this.checkForLorawan(existingMulticast); if (loraDevices.length > 0) { - await this.deleteMulticastChirpstack( - existingMulticast.lorawanMulticastDefinition.chirpstackGroupId - ); + await this.deleteMulticastChirpstack(existingMulticast.lorawanMulticastDefinition.chirpstackGroupId); } return this.multicastRepository.delete(id); } @@ -373,9 +333,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { multicastDto.applicationID ); } catch (err) { - this.logger.error( - `Could not find application with id: ${multicastDto.applicationID}` - ); + this.logger.error(`Could not find application with id: ${multicastDto.applicationID}`); throw new BadRequestException(ErrorCodes.IdDoesNotExists); } @@ -424,11 +382,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { } } - private async updateDevices( - removed: IoTDevice[], - added: IoTDevice[], - chirpstackMulticastID: string - ) { + private async updateDevices(removed: IoTDevice[], added: IoTDevice[], chirpstackMulticastID: string) { removed.forEach(async device => { // if the removed devices is a lorawan, then delete from chirpstack if (device.type === IoTDeviceType.LoRaWAN) { @@ -448,10 +402,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { addDevice.devEUI = lorawanDevice.deviceEUI; addDevice.multicastGroupID = chirpstackMulticastID; - await this.post( - this.multicastGroupUrl + "/" + chirpstackMulticastID + "/" + "devices", - addDevice - ); + await this.post(this.multicastGroupUrl + "/" + chirpstackMulticastID + "/" + "devices", addDevice); } }); } @@ -516,9 +467,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { newMulticast.iotDevices.forEach(frontendDevice => { // if a device in the new multicast is not in the old one, then add - if ( - oldMulticast.iotDevices.findIndex(device => device.id === frontendDevice.id) === -1 - ) { + if (oldMulticast.iotDevices.findIndex(device => device.id === frontendDevice.id) === -1) { added.push(frontendDevice); } }); @@ -578,8 +527,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { const res = await this.postDownlink(this.multicastServiceClient, req); return res; } catch (err) { - const fcntError = - "enqueue downlink payload error: get next downlink fcnt for deveui error"; + const fcntError = "enqueue downlink payload error: get next downlink fcnt for deveui error"; if (err?.response?.data?.error?.startsWith(fcntError)) { throw new BadRequestException(ErrorCodes.DeviceIsNotActivatedInChirpstack); } @@ -603,11 +551,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { mappedMulticast: Multicast ): Promise { if (await this.checkForDifferentAppID(lorawanDevices)) { - await this.createMulticastInChirpstack( - updateMulticastDto, - lorawanDevices, - mappedMulticast - ); + await this.createMulticastInChirpstack(updateMulticastDto, lorawanDevices, mappedMulticast); } else { throw new BadRequestException(ErrorCodes.InvalidPost); } @@ -666,10 +610,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { } } - async deleteQueue( - client: MulticastGroupServiceClient, - request: FlushMulticastGroupQueueRequest - ): Promise { + async deleteQueue(client: MulticastGroupServiceClient, request: FlushMulticastGroupQueueRequest): Promise { const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.flushQueue(request, metaData, (err: ServiceError, resp: any) => { diff --git a/src/services/data-management/chirpstack-mqtt-listener.service.ts b/src/services/data-management/chirpstack-mqtt-listener.service.ts index ef454199..15fb57c1 100644 --- a/src/services/data-management/chirpstack-mqtt-listener.service.ts +++ b/src/services/data-management/chirpstack-mqtt-listener.service.ts @@ -16,10 +16,7 @@ import * as Protobuf from "protobufjs"; @Injectable() export class ChirpstackMQTTListenerService implements OnApplicationBootstrap { - constructor( - private receiveDataService: ReceiveDataService, - private iotDeviceService: IoTDeviceService - ) { + constructor(private receiveDataService: ReceiveDataService, private iotDeviceService: IoTDeviceService) { const connStateFullTemplate = Protobuf.loadSync(ChirpstackStateTemplatePath); this.connStateType = connStateFullTemplate.lookupType("ConnState"); } @@ -27,17 +24,14 @@ export class ChirpstackMQTTListenerService implements OnApplicationBootstrap { private readonly logger = new Logger(ChirpstackMQTTListenerService.name); private readonly connStateType: Protobuf.Type; - MQTT_URL = `mqtt://${process.env.CS_MQTT_HOSTNAME || "localhost"}:${ - process.env.CS_MQTT_PORT || "1883" - }`; + MQTT_URL = `mqtt://${process.env.CS_MQTT_HOSTNAME || "localhost"}:${process.env.CS_MQTT_PORT || "1883"}`; client: Client; private readonly CHIRPSTACK_MQTT_DEVICE_DATA_PREFIX = "application/"; private readonly CHIRPSTACK_MQTT_DEVICE_DATA_TOPIC = this.CHIRPSTACK_MQTT_DEVICE_DATA_PREFIX + "+/device/+/event/up"; private readonly CHIRPSTACK_MQTT_GATEWAY_PREFIX = "gateway/"; - private readonly CHIRPSTACK_MQTT_GATEWAY_TOPIC = - this.CHIRPSTACK_MQTT_GATEWAY_PREFIX + "+/state/conn"; + private readonly CHIRPSTACK_MQTT_GATEWAY_TOPIC = this.CHIRPSTACK_MQTT_GATEWAY_PREFIX + "+/state/conn"; public async onApplicationBootstrap(): Promise { this.logger.debug("Pre-init"); @@ -60,9 +54,7 @@ export class ChirpstackMQTTListenerService implements OnApplicationBootstrap { const decoded = this.connStateType.decode(message); await this.receiveMqttGatewayStatusMessage(decoded.toJSON()); } catch (error) { - this.logger.error( - `Gateway status data could not be processed. Error: ${error}` - ); + this.logger.error(`Gateway status data could not be processed. Error: ${error}`); } } else { this.logger.warn("Unrecognized MQTT topic " + topic); @@ -74,9 +66,7 @@ export class ChirpstackMQTTListenerService implements OnApplicationBootstrap { async receiveMqttMessage(message: string): Promise { const dto: ChirpstackMQTTMessageDto = JSON.parse(message); - const iotDevice = await this.iotDeviceService.findLoRaWANDeviceByDeviceEUI( - dto.deviceInfo.devEui - ); + const iotDevice = await this.iotDeviceService.findLoRaWANDeviceByDeviceEUI(dto.deviceInfo.devEui); if (!iotDevice) { this.logger.warn( diff --git a/src/services/device-management/iot-device-downlink.service.ts b/src/services/device-management/iot-device-downlink.service.ts index 62d5b758..3dc230f3 100644 --- a/src/services/device-management/iot-device-downlink.service.ts +++ b/src/services/device-management/iot-device-downlink.service.ts @@ -4,12 +4,7 @@ import { LoRaWANDevice } from "@entities/lorawan-device.entity"; import { SigFoxDevice } from "@entities/sigfox-device.entity"; import { IoTDeviceType } from "@enum/device-type.enum"; import { ErrorCodes } from "@enum/error-codes.enum"; -import { - BadRequestException, - Injectable, - InternalServerErrorException, - Logger, -} from "@nestjs/common"; +import { BadRequestException, Injectable, InternalServerErrorException, Logger } from "@nestjs/common"; import { SigFoxApiDeviceTypeService } from "@services/sigfox/sigfox-api-device-type.service"; import { SigFoxGroupService } from "@services/sigfox/sigfox-group.service"; import { IoTDeviceService } from "@services/device-management/iot-device.service"; @@ -31,10 +26,7 @@ export class IoTDeviceDownlinkService { private readonly logger = new Logger(IoTDeviceDownlinkService.name); private readonly SIGFOX_DOWNLINK_LENGTH_EXACT = 16; - async createDownlink( - dto: CreateIoTDeviceDownlinkDto, - device: IoTDevice - ): Promise { + async createDownlink(dto: CreateIoTDeviceDownlinkDto, device: IoTDevice): Promise { if (device.type === IoTDeviceType.LoRaWAN) { const cast = device; return await this.createLoraDownlink(dto, cast); @@ -46,14 +38,9 @@ export class IoTDeviceDownlinkService { } } - private async createSigfoxDownlink( - dto: CreateIoTDeviceDownlinkDto, - cast: SigFoxDevice - ): Promise { + private async createSigfoxDownlink(dto: CreateIoTDeviceDownlinkDto, cast: SigFoxDevice): Promise { this.validateSigfoxPayload(dto); - this.logger.debug( - `Creating downlink for device(${cast.id}) sigfoxId(${cast.deviceId})` - ); + this.logger.debug(`Creating downlink for device(${cast.id}) sigfoxId(${cast.deviceId})`); cast.downlinkPayload = dto.data; await this.iotDeviceService.save(cast); await this.updateSigFoxDeviceTypeDownlink(cast); @@ -61,10 +48,7 @@ export class IoTDeviceDownlinkService { private async updateSigFoxDeviceTypeDownlink(cast: SigFoxDevice) { const sigfoxGroup = await this.sigfoxGroupService.findOneByGroupId(cast.groupId); - await this.sigfoxApiDeviceTypeService.addOrUpdateCallback( - sigfoxGroup, - cast.deviceTypeId - ); + await this.sigfoxApiDeviceTypeService.addOrUpdateCallback(sigfoxGroup, cast.deviceTypeId); } private validateSigfoxPayload(dto: CreateIoTDeviceDownlinkDto) { @@ -93,23 +77,16 @@ export class IoTDeviceDownlinkService { } } - private handleErrorsFromChirpstack( - csDto: CreateChirpstackDeviceQueueItemDto, - err: any - ) { + private handleErrorsFromChirpstack(csDto: CreateChirpstackDeviceQueueItemDto, err: any) { this.logger.error( `Error while trying to create downlink i chirpstack. DTO: '${JSON.stringify( csDto )}'. Error: '${JSON.stringify(err?.data)}'` ); if (err.status == 400) { - throw new BadRequestException( - "Error 400 from Chirpstack" + JSON.stringify(err?.data) - ); + throw new BadRequestException("Error 400 from Chirpstack" + JSON.stringify(err?.data)); } - throw new InternalServerErrorException( - "Could not send to chirpstack, try again later." - ); + throw new InternalServerErrorException("Could not send to chirpstack, try again later."); } private hexBytesToBase64(hexBytes: string): string { From 0415c785a60f26666101cb4cbd991a57a7fbb109 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Tue, 12 Dec 2023 14:39:32 +0100 Subject: [PATCH 14/24] Packagelock fix --- package-lock.json | 4 ++-- package.json | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a4e8ebe3..5d2d25b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "Mozilla Public License Version 2.0", "dependencies": { "@chirpstack/chirpstack-api": "4.6.0", - "@grpc/grpc-js": "1.9.12", + "@grpc/grpc-js": "^1.9.12", "@nestjs/axios": "^3.0.0", "@nestjs/common": "^9.1.2", "@nestjs/config": "^2.2.0", @@ -10776,7 +10776,7 @@ "resolved": "https://registry.npmjs.org/@chirpstack/chirpstack-api/-/chirpstack-api-4.6.0.tgz", "integrity": "sha512-bGXKbWisX3tMWa9GxazVP87za2EzkoJuUIwgJGmwbHtSTz/bZqCLYhOG+77yt881qLFxUmzAsnVNTQFLE1whHQ==", "requires": { - "@grpc/grpc-js": "1.9.12", + "@grpc/grpc-js": "^1.9.0", "@mapbox/node-pre-gyp": "^1.0.11", "@types/google-protobuf": "^3.15.6", "google-protobuf": "^3.21.2" diff --git a/package.json b/package.json index 5b7b69b3..600d295c 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "dependencies": { "@nestjs/axios": "^3.0.0", "@chirpstack/chirpstack-api": "4.6.0", - "@grpc/grpc-js": "1.9.12", + "@grpc/grpc-js": "^1.9.12", "@nestjs/common": "^9.1.2", "@nestjs/config": "^2.2.0", "@nestjs/core": "^9.1.2", @@ -125,7 +125,6 @@ "xml2js": "^0.6.2", "jsonwebtoken": "^9.0.0", "debug": "^4.3.4", - "y18n": "6.0.0-alpha.0", - "@grpc/grpc-js": "1.9.12" + "y18n": "6.0.0-alpha.0" } } From 193ae005c15baa3ebc9d600e999d68c1af53715f Mon Sep 17 00:00:00 2001 From: August Andersen Date: Thu, 14 Dec 2023 13:45:27 +0100 Subject: [PATCH 15/24] PR changes --- src/config/configuration.ts | 20 +- .../chirpstack-gateway.controller.ts | 8 +- .../chirpstack/device-profile.controller.ts | 7 +- .../admin-controller/iot-device.controller.ts | 4 +- src/entities/application.entity.ts | 1 + src/entities/base.entity.ts | 8 +- .../chirpstack/chirpstack-application.dto.ts | 1 - .../chirpstack-device-contents.dto.ts | 1 + .../chirpstack-many-device-response.ts | 4 +- .../chirpstack-multicast-contents.dto.ts | 10 +- .../chirpstack/create-device-profile.dto.ts | 4 +- .../dto/chirpstack/device-profile.dto.ts | 20 +- .../dto/chirpstack/gateway-contents.dto.ts | 3 - .../dto/chirpstack/gateway-response.dto.ts | 20 +- .../list-all-applications-response.dto.ts | 2 +- .../dto/chirpstack/list-all-gateways.dto.ts | 11 +- .../chirpstack/single-gateway-response.dto.ts | 5 +- .../dto/chirpstack/update-gateway.dto.ts | 2 + src/entities/dto/create-application.dto.ts | 12 +- .../enum/device-profile-enums.enum.ts | 17 - src/entities/enum/error-codes.enum.ts | 2 +- .../chirpstack-id-response.interface.ts | 3 + .../chirpstack-post-return.interface.ts | 3 - .../chirpstack-administration.module.ts | 7 +- .../lorawan-gateway.module.ts | 6 +- .../chirpstack-application.service.ts | 82 ++- .../chirpstack/chirpstack-device.service.ts | 504 +++++++----------- .../chirpstack/chirpstack-gateway.service.ts | 152 +++--- .../chirpstack/device-profile.service.ts | 47 +- .../chirpstack/gateway-boostrapper.service.ts | 13 +- .../gateway-status-history.service.ts | 8 +- ...eneric-chirpstack-configuration.service.ts | 11 +- src/services/chirpstack/multicast.service.ts | 10 +- .../gateway-persistence.service.ts | 32 +- .../data-management/search.service.ts | 7 +- .../device-management/application.service.ts | 9 +- .../iot-device-downlink.service.ts | 9 +- .../device-management/iot-device.service.ts | 12 +- .../lorawan-device-database-enrich-job.ts | 49 +- 39 files changed, 497 insertions(+), 629 deletions(-) delete mode 100644 src/entities/enum/device-profile-enums.enum.ts create mode 100644 src/entities/interfaces/chirpstack-id-response.interface.ts delete mode 100644 src/entities/interfaces/chirpstack-post-return.interface.ts diff --git a/src/config/configuration.ts b/src/config/configuration.ts index 2dda5353..24f8fc38 100644 --- a/src/config/configuration.ts +++ b/src/config/configuration.ts @@ -15,10 +15,8 @@ export default (): any => { expiresIn: process.env.JWT_EXPIRESIN || "9h", }, backend: { - baseurl: - process.env.BACKEND_BASEURL || "https://localhost:3000", - deviceStatsIntervalInDays: - parseInt(process.env.DEVICE_STATS_INTERVAL_IN_DAYS, 10) || 29, + baseurl: process.env.BACKEND_BASEURL || "https://localhost:3000", + deviceStatsIntervalInDays: parseInt(process.env.DEVICE_STATS_INTERVAL_IN_DAYS, 10) || 29, }, kombit: { entryPoint: @@ -26,17 +24,13 @@ export default (): any => { "https://adgangsstyring.eksterntest-stoettesystemerne.dk/runtime/saml2/issue.idp", certificatePublicKey: process.env.KOMBIT_CERTIFICATEPUBLICKEY || "INSERT_KOMBIT_CERT", // Public certificate from Kombit Test server certificatePrivateKey: process.env.KOMBIT_CERTIFICATEPRIVATEKEY || null, - roleUri: - process.env.KOMBIT_ROLE_NAME || - "http://os2iot.dk/roles/usersystemrole/adgang/", + roleUri: process.env.KOMBIT_ROLE_NAME || "http://os2iot.dk/roles/usersystemrole/adgang/", }, chirpstack: { jwtsecret: process.env.CHIRPSTACK_JWTSECRET || "verysecret", - apikey: process.env.CHIRPSTACK_API_KEY || "apikey" + apikey: process.env.CHIRPSTACK_API_KEY || "apikey", }, - logLevels: process.env.LOG_LEVEL - ? GetLogLevels(process.env.LOG_LEVEL) - : GetLogLevels("debug"), + logLevels: process.env.LOG_LEVEL ? GetLogLevels(process.env.LOG_LEVEL) : GetLogLevels("debug"), email: { host: process.env.EMAIL_HOST || "smtp.ethereal.email", port: process.env.EMAIL_PORT || 587, @@ -46,9 +40,7 @@ export default (): any => { * Can be formatted to show a user-friendly name before the e-mail. * E.g. "OS2iot " */ - from: process.env.EMAIL_FROM - ? formatEmail(process.env.EMAIL_FROM) - : "OS2iot tremayne38@ethereal.email", + from: process.env.EMAIL_FROM ? formatEmail(process.env.EMAIL_FROM) : "OS2iot tremayne38@ethereal.email", }, frontend: { baseurl: process.env.FRONTEND_BASEURL || "http://localhost:8081", diff --git a/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts b/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts index 3202caf9..b29f5066 100644 --- a/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts +++ b/src/controllers/admin-controller/chirpstack/chirpstack-gateway.controller.ts @@ -18,7 +18,7 @@ import { Read, GatewayAdmin } from "@auth/roles.decorator"; import { RolesGuard } from "@auth/roles.guard"; import { ChirpstackResponseStatus } from "@dto/chirpstack/chirpstack-response.dto"; import { CreateGatewayDto } from "@dto/chirpstack/create-gateway.dto"; -import { ListAllGatewaysResponseGrpcDto } from "@dto/chirpstack/list-all-gateways.dto"; +import { ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways.dto"; import { SingleGatewayResponseDto } from "@dto/chirpstack/single-gateway-response.dto"; import { UpdateGatewayDto } from "@dto/chirpstack/update-gateway.dto"; import { ErrorCodes } from "@enum/error-codes.enum"; @@ -74,7 +74,7 @@ export class ChirpstackGatewayController { @ApiProduces("application/json") @ApiOperation({ summary: "List all Chirpstack gateways" }) @Read() - async getAll(@Query() query?: ChirpstackGetAll): Promise { + async getAll(@Query() query?: ChirpstackGetAll): Promise { return await this.chirpstackGatewayService.getAll(query.organizationId); } @@ -125,10 +125,10 @@ export class ChirpstackGatewayController { ): Promise { try { const gw = await this.chirpstackGatewayService.getOne(gatewayId); - if (gw.gateway.internalOrganizationId != null) { + if (gw.gateway.organizationId != null) { checkIfUserHasAccessToOrganization( req, - +gw.gateway.internalOrganizationId, + +gw.gateway.organizationId, OrganizationAccessScope.GatewayWrite ); } diff --git a/src/controllers/admin-controller/chirpstack/device-profile.controller.ts b/src/controllers/admin-controller/chirpstack/device-profile.controller.ts index 9ce47408..777c9701 100644 --- a/src/controllers/admin-controller/chirpstack/device-profile.controller.ts +++ b/src/controllers/admin-controller/chirpstack/device-profile.controller.ts @@ -38,7 +38,7 @@ import { AuditLog } from "@services/audit-log.service"; import { ActionType } from "@entities/audit-log-entry"; import { ComposeAuthGuard } from "@auth/compose-auth.guard"; import { ListAllAdrAlgorithmsResponseDto } from "@dto/chirpstack/list-all-adr-algorithms-response.dto"; -import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; @ApiTags("Chirpstack") @Controller("chirpstack/device-profiles") @@ -56,10 +56,7 @@ export class DeviceProfileController { @ApiOperation({ summary: "Create a new DeviceProfile" }) @ApiBadRequestResponse() @ApplicationAdmin() - async create( - @Req() req: AuthenticatedRequest, - @Body() createDto: CreateDeviceProfileDto - ): Promise { + async create(@Req() req: AuthenticatedRequest, @Body() createDto: CreateDeviceProfileDto): Promise { checkIfUserHasAccessToOrganization( req, createDto.internalOrganizationId, diff --git a/src/controllers/admin-controller/iot-device.controller.ts b/src/controllers/admin-controller/iot-device.controller.ts index 901c3a72..a81fe8d8 100644 --- a/src/controllers/admin-controller/iot-device.controller.ts +++ b/src/controllers/admin-controller/iot-device.controller.ts @@ -58,7 +58,7 @@ import { DeviceStatsResponseDto } from "@dto/chirpstack/device/device-stats.resp import { GenericHTTPDevice } from "@entities/generic-http-device.entity"; import { MQTTInternalBrokerDeviceDTO } from "@dto/mqtt-internal-broker-device.dto"; import { MQTTExternalBrokerDeviceDTO } from "@dto/mqtt-external-broker-device.dto"; -import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; @ApiTags("IoT Device") @Controller("iot-device") @@ -170,7 +170,7 @@ export class IoTDeviceController { @Req() req: AuthenticatedRequest, @Param("id", new ParseIntPipe()) id: number, @Body() dto: CreateIoTDeviceDownlinkDto - ): Promise { + ): Promise { try { const device = await this.iotDeviceService.findOneWithApplicationAndMetadata(id); if (!device) { diff --git a/src/entities/application.entity.ts b/src/entities/application.entity.ts index 97f77d13..3a3862e7 100644 --- a/src/entities/application.entity.ts +++ b/src/entities/application.entity.ts @@ -113,6 +113,7 @@ export class Application extends DbBaseEntity { cascade: true, }) deviceTypes?: ApplicationDeviceType[]; + @Column({ nullable: true }) chirpstackId?: string; } diff --git a/src/entities/base.entity.ts b/src/entities/base.entity.ts index 2e896822..da07bc9d 100644 --- a/src/entities/base.entity.ts +++ b/src/entities/base.entity.ts @@ -1,10 +1,4 @@ -import { - CreateDateColumn, - JoinColumn, - ManyToOne, - PrimaryGeneratedColumn, - UpdateDateColumn, -} from "typeorm"; +import { CreateDateColumn, JoinColumn, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm"; /** * This class contains all the values which are stored by default on all entities. diff --git a/src/entities/dto/chirpstack/chirpstack-application.dto.ts b/src/entities/dto/chirpstack/chirpstack-application.dto.ts index ddde7e39..06365798 100644 --- a/src/entities/dto/chirpstack/chirpstack-application.dto.ts +++ b/src/entities/dto/chirpstack/chirpstack-application.dto.ts @@ -1,5 +1,4 @@ export class ChirpstackApplicationDto { name: string; description: string; - tenantId: string; } diff --git a/src/entities/dto/chirpstack/chirpstack-device-contents.dto.ts b/src/entities/dto/chirpstack/chirpstack-device-contents.dto.ts index 57f93294..8ef466b8 100644 --- a/src/entities/dto/chirpstack/chirpstack-device-contents.dto.ts +++ b/src/entities/dto/chirpstack/chirpstack-device-contents.dto.ts @@ -37,6 +37,7 @@ export class ChirpstackDeviceContentsDto { @ApiHideProperty() deviceStatusBattery?: number; + @ApiHideProperty() deviceStatusMargin?: number; } diff --git a/src/entities/dto/chirpstack/chirpstack-many-device-response.ts b/src/entities/dto/chirpstack/chirpstack-many-device-response.ts index 9c0f1de2..cc7633c7 100644 --- a/src/entities/dto/chirpstack/chirpstack-many-device-response.ts +++ b/src/entities/dto/chirpstack/chirpstack-many-device-response.ts @@ -1,4 +1,4 @@ -export interface ChirpstackManyDeviceResponseContents { +export interface ChirpstackDeviceResponseContents { devEUI: string; name: string; description: string; @@ -12,5 +12,5 @@ export interface ChirpstackManyDeviceResponseContents { export interface ChirpstackManyDeviceResponseDto { totalCount: string; - result: ChirpstackManyDeviceResponseContents[]; + result: ChirpstackDeviceResponseContents[]; } diff --git a/src/entities/dto/chirpstack/chirpstack-multicast-contents.dto.ts b/src/entities/dto/chirpstack/chirpstack-multicast-contents.dto.ts index d34d258e..9228164e 100644 --- a/src/entities/dto/chirpstack/chirpstack-multicast-contents.dto.ts +++ b/src/entities/dto/chirpstack/chirpstack-multicast-contents.dto.ts @@ -4,23 +4,31 @@ import { ApiProperty } from "@nestjs/swagger"; export class ChirpstackMulticastContentsDto { @ApiProperty({ required: true }) applicationID: string; + @ApiProperty({ required: true }) dr: number; + @ApiProperty({ required: true }) fCnt: number; + @ApiProperty({ required: true }) frequency: number; + @ApiProperty({ required: true }) groupType: multicastGroup; + @ApiProperty({ required: true }) mcAddr: string; + @ApiProperty({ required: true }) mcAppSKey: string; + @ApiProperty({ required: true }) mcNwkSKey: string; + @ApiProperty({ required: true }) name: string; + @ApiProperty({ required: true }) id: string; - } diff --git a/src/entities/dto/chirpstack/create-device-profile.dto.ts b/src/entities/dto/chirpstack/create-device-profile.dto.ts index 47a5d9b7..f4efcc37 100644 --- a/src/entities/dto/chirpstack/create-device-profile.dto.ts +++ b/src/entities/dto/chirpstack/create-device-profile.dto.ts @@ -13,9 +13,9 @@ export class CreateDeviceProfileDto { @ApiProperty({ required: true }) internalOrganizationId: number; - @ApiHideProperty() + @ApiProperty({ required: false }) createdAt: Date; - @ApiHideProperty() + @ApiProperty({ required: false }) updatedAt: Date; } diff --git a/src/entities/dto/chirpstack/device-profile.dto.ts b/src/entities/dto/chirpstack/device-profile.dto.ts index c0fc251a..f849dcc5 100644 --- a/src/entities/dto/chirpstack/device-profile.dto.ts +++ b/src/entities/dto/chirpstack/device-profile.dto.ts @@ -1,7 +1,4 @@ -import { - MacVersionMap, - RegParamsRevisionMap, -} from "@chirpstack/chirpstack-api/common/common_pb"; +import { MacVersionMap, RegParamsRevisionMap } from "@chirpstack/chirpstack-api/common/common_pb"; import { ApiHideProperty, ApiProperty } from "@nestjs/swagger"; import { IsInt, IsNotEmpty, IsOptional, IsString, Length, Min, ValidateIf } from "class-validator"; @@ -17,7 +14,6 @@ export class DeviceProfileDto { @ApiProperty({ required: true }) @IsNotEmpty() - regParamsRevision: RegParamsRevisionMap[keyof RegParamsRevisionMap]; @ApiProperty({ required: false }) @@ -38,9 +34,6 @@ export class DeviceProfileDto { @ApiProperty({ required: false }) id?: string; - @ApiHideProperty() - organizationID?: string; - @ApiProperty({ required: false }) @ValidateIf((o: DeviceProfileDto) => o.supportsClassB) @Min(0) @@ -58,7 +51,7 @@ export class DeviceProfileDto { pingSlotPeriod?: number; @ApiProperty({ required: false }) - rfRegion?: string + rfRegion?: string; @ApiProperty({ required: false }) @ValidateIf((o: DeviceProfileDto) => o.supportsJoin == false) @@ -93,8 +86,12 @@ export class DeviceProfileDto { @ApiProperty({ required: false }) supportsJoin?: boolean; + @ApiProperty({ required: false }) + devStatusReqFreq?: number; + @ApiHideProperty() tags?: { [id: string]: string }; + @ApiHideProperty() tagsMap?: Array<[string, string]>; @@ -106,6 +103,7 @@ export class DeviceProfileDto { @ApiHideProperty() createdBy?: number; - @ApiProperty({ required: false }) - devStatusReqFreq?: number; + + @ApiHideProperty() + organizationID?: string; } diff --git a/src/entities/dto/chirpstack/gateway-contents.dto.ts b/src/entities/dto/chirpstack/gateway-contents.dto.ts index 53e88aa5..57c435ef 100644 --- a/src/entities/dto/chirpstack/gateway-contents.dto.ts +++ b/src/entities/dto/chirpstack/gateway-contents.dto.ts @@ -57,9 +57,6 @@ export class GatewayContentsDto { @ApiHideProperty() tags?: { [id: string]: string }; - @ApiHideProperty() - gatewayProfileID?: string; - @ApiHideProperty() id: string; } diff --git a/src/entities/dto/chirpstack/gateway-response.dto.ts b/src/entities/dto/chirpstack/gateway-response.dto.ts index a6a45cd9..35382c69 100644 --- a/src/entities/dto/chirpstack/gateway-response.dto.ts +++ b/src/entities/dto/chirpstack/gateway-response.dto.ts @@ -1,7 +1,7 @@ import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; import { CommonLocationDto } from "./common-location.dto"; -export class GatewayResponseGrpcDto { +export class GatewayResponseChirpstackDto { id?: number; gatewayId: string; name: string; @@ -18,3 +18,21 @@ export class GatewayResponseGrpcDto { createdBy?: number; tags?: { [id: string]: string }; } + +export class GatewayResponseDto { + id: number; + gatewayId: string; + name: string; + description?: string; + rxPacketsReceived: number; + txPacketsEmitted: number; + organizationId: number; + organizationName: string; + location: CommonLocationDto; + tags: { [id: string]: string | number }; + createdAt?: Date; + updatedAt?: Date; + lastSeenAt?: Date; + updatedBy?: number; + createdBy?: number; +} diff --git a/src/entities/dto/chirpstack/list-all-applications-response.dto.ts b/src/entities/dto/chirpstack/list-all-applications-response.dto.ts index 1efabe5b..fa1fad16 100644 --- a/src/entities/dto/chirpstack/list-all-applications-response.dto.ts +++ b/src/entities/dto/chirpstack/list-all-applications-response.dto.ts @@ -1,6 +1,6 @@ import { ChirpstackApplicationResponseDto } from "./chirpstack-application-response.dto"; export class ListAllChirpstackApplicationsResponseDto { - result: ChirpstackApplicationResponseDto[]; + resultList: ChirpstackApplicationResponseDto[]; totalCount: number; } diff --git a/src/entities/dto/chirpstack/list-all-gateways.dto.ts b/src/entities/dto/chirpstack/list-all-gateways.dto.ts index 3b616a79..7e95f872 100644 --- a/src/entities/dto/chirpstack/list-all-gateways.dto.ts +++ b/src/entities/dto/chirpstack/list-all-gateways.dto.ts @@ -1,6 +1,11 @@ -import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; +import { GatewayResponseChirpstackDto, GatewayResponseDto } from "./gateway-response.dto"; -export class ListAllGatewaysResponseGrpcDto { +export class ListAllGatewaysResponseDto { totalCount: number; - resultList: GatewayResponseGrpcDto[]; + resultList: GatewayResponseDto[]; +} + +export class ListAllGatewaysResponseChirpstackDto { + totalCount: number; + resultList: GatewayResponseChirpstackDto[]; } diff --git a/src/entities/dto/chirpstack/single-gateway-response.dto.ts b/src/entities/dto/chirpstack/single-gateway-response.dto.ts index f3f99e9a..2580402c 100644 --- a/src/entities/dto/chirpstack/single-gateway-response.dto.ts +++ b/src/entities/dto/chirpstack/single-gateway-response.dto.ts @@ -1,8 +1,7 @@ import { GatewayStatsElementDto } from "@dto/chirpstack/gateway-stats.response.dto"; -import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; -import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; +import { GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto"; export class SingleGatewayResponseDto { - gateway: GatewayResponseGrpcDto; + gateway: GatewayResponseDto; stats?: GatewayStatsElementDto[]; } diff --git a/src/entities/dto/chirpstack/update-gateway.dto.ts b/src/entities/dto/chirpstack/update-gateway.dto.ts index 3b628b26..98c907cb 100644 --- a/src/entities/dto/chirpstack/update-gateway.dto.ts +++ b/src/entities/dto/chirpstack/update-gateway.dto.ts @@ -6,8 +6,10 @@ import { Type } from "class-transformer"; export class UpdateGatewayContentsDto extends OmitType(GatewayContentsDto, ["gatewayId"]) { @ApiHideProperty() gatewayId: string; + @ApiHideProperty() createdBy?: number; + @ApiHideProperty() updatedBy?: number; } diff --git a/src/entities/dto/create-application.dto.ts b/src/entities/dto/create-application.dto.ts index 30dab95c..632674be 100644 --- a/src/entities/dto/create-application.dto.ts +++ b/src/entities/dto/create-application.dto.ts @@ -6,16 +6,7 @@ import { IsSwaggerOptional } from "@helpers/optional-validator"; import { IsPhoneNumberString } from "@helpers/phone-number.validator"; import { nameof } from "@helpers/type-helper"; import { ApiProperty } from "@nestjs/swagger"; -import { - ArrayUnique, - IsArray, - IsBoolean, - IsEnum, - IsOptional, - IsString, - MaxLength, - MinLength, -} from "class-validator"; +import { ArrayUnique, IsArray, IsBoolean, IsEnum, IsOptional, IsString, MaxLength, MinLength } from "class-validator"; export class CreateApplicationDto { @ApiProperty({ required: true }) @@ -99,6 +90,7 @@ export class CreateApplicationDto { }, }) permissionIds?: number[]; + @ApiProperty({ required: false }) @IsOptional() @IsString() diff --git a/src/entities/enum/device-profile-enums.enum.ts b/src/entities/enum/device-profile-enums.enum.ts deleted file mode 100644 index ba21b70f..00000000 --- a/src/entities/enum/device-profile-enums.enum.ts +++ /dev/null @@ -1,17 +0,0 @@ -export enum MacVersions { - "1.0.0", - "1.0.1", - "1.0.2", - "1.0.3", - "1.0.4", - "1.1.0", -} - -export enum RegParamsRevisions { - "A", - "B", - "RP002-1.0.0", - "RP002-1.0.1", - "RP002-1.0.2", - "RP002-1.0.3", -} diff --git a/src/entities/enum/error-codes.enum.ts b/src/entities/enum/error-codes.enum.ts index 225cd1a8..d1cca2d1 100644 --- a/src/entities/enum/error-codes.enum.ts +++ b/src/entities/enum/error-codes.enum.ts @@ -48,5 +48,5 @@ export enum ErrorCodes { SendMailError = "MESSAGE.SEND-MAIL-ERROR", UserDoesNotExistInArray = "MESSAGE.USER-DOES-NOT-EXIST", UserAlreadyInPermission = "MESSAGE.USER-ALREADY-IN-PERMISSION", - CouldntGetApplications= "MESSAGE.COULDN'T-GET-CS-APPLICATIONS" + CouldntGetApplications= "MESSAGE.COULD-NOT-GET-CS-APPLICATIONS" } diff --git a/src/entities/interfaces/chirpstack-id-response.interface.ts b/src/entities/interfaces/chirpstack-id-response.interface.ts new file mode 100644 index 00000000..7f23bafb --- /dev/null +++ b/src/entities/interfaces/chirpstack-id-response.interface.ts @@ -0,0 +1,3 @@ +export interface IdResponse { + id: string; +} diff --git a/src/entities/interfaces/chirpstack-post-return.interface.ts b/src/entities/interfaces/chirpstack-post-return.interface.ts deleted file mode 100644 index bf92e0a5..00000000 --- a/src/entities/interfaces/chirpstack-post-return.interface.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface PostReturnInterface { - id: string; -} diff --git a/src/modules/device-integrations/chirpstack-administration.module.ts b/src/modules/device-integrations/chirpstack-administration.module.ts index a2a6e4cd..e006a566 100644 --- a/src/modules/device-integrations/chirpstack-administration.module.ts +++ b/src/modules/device-integrations/chirpstack-administration.module.ts @@ -13,17 +13,14 @@ import { GenericChirpstackConfigurationService } from "@services/chirpstack/gene import { OrganizationModule } from "@modules/user-management/organization.module"; @Module({ - controllers: [ - ChirpstackGatewayController, - DeviceProfileController, - ], + controllers: [ChirpstackGatewayController, DeviceProfileController], imports: [SharedModule, HttpModule, OrganizationModule, ConfigModule.forRoot({ load: [configuration] })], providers: [ GenericChirpstackConfigurationService, ChirpstackGatewayService, DeviceProfileService, ChirpstackDeviceService, - ApplicationChirpstackService + ApplicationChirpstackService, ], exports: [ChirpstackDeviceService, ChirpstackGatewayService, DeviceProfileService, ApplicationChirpstackService], }) diff --git a/src/modules/device-integrations/lorawan-gateway.module.ts b/src/modules/device-integrations/lorawan-gateway.module.ts index dfd9e4d3..fc919c86 100644 --- a/src/modules/device-integrations/lorawan-gateway.module.ts +++ b/src/modules/device-integrations/lorawan-gateway.module.ts @@ -10,11 +10,7 @@ import { OrganizationModule } from "@modules/user-management/organization.module @Module({ controllers: [LoRaWANGatewayController], imports: [SharedModule, HttpModule, OrganizationModule], - providers: [ - ChirpstackGatewayService, - GatewayStatusHistoryService, - GatewayBootstrapperService, - ], + providers: [ChirpstackGatewayService, GatewayStatusHistoryService, GatewayBootstrapperService], exports: [GatewayStatusHistoryService], }) export class LoRaWANGatewayModule {} diff --git a/src/services/chirpstack/chirpstack-application.service.ts b/src/services/chirpstack/chirpstack-application.service.ts index dc0c6415..7b25af02 100644 --- a/src/services/chirpstack/chirpstack-application.service.ts +++ b/src/services/chirpstack/chirpstack-application.service.ts @@ -1,37 +1,93 @@ -import { BadRequestException, Injectable } from "@nestjs/common"; +import { Injectable } from "@nestjs/common"; import { GenericChirpstackConfigurationService } from "./generic-chirpstack-configuration.service"; - import { Application, CreateApplicationRequest, DeleteApplicationRequest, + ListApplicationsRequest, UpdateApplicationRequest, } from "@chirpstack/chirpstack-api/api/application_pb"; import { CreateApplicationDto } from "@dto/create-application.dto"; -import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; import { Application as DbApplication } from "@entities/application.entity"; +import { ListAllChirpstackApplicationsResponseDto } from "@dto/chirpstack/list-all-applications-response.dto"; +import { LoRaWANDevice } from "@entities/lorawan-device.entity"; +import { CreateChirpstackApplicationDto } from "@dto/chirpstack/create-chirpstack-application.dto"; +import { InjectRepository } from "@nestjs/typeorm"; +import { Repository } from "typeorm"; @Injectable() export class ApplicationChirpstackService extends GenericChirpstackConfigurationService { + @InjectRepository(DbApplication) + private applicationRepository: Repository; constructor() { super(); } - defaultApplicationName = "os2iot"; + applicationNamePrefix = "os2iot-"; DEFAULT_DESCRIPTION = "Created by OS2IoT"; - public async createApplication(dto: CreateApplicationDto): Promise { + + public async findOrCreateDefaultApplication( + applications: ListAllChirpstackApplicationsResponseDto = null, + iotDevice: LoRaWANDevice + ): Promise { + const organizationID = await this.getDefaultOrganizationId(); + const req = new ListApplicationsRequest(); + req.setTenantId(organizationID); + // Fetch applications + applications = + applications ?? + (await this.getAllWithPagination( + `applications?limit=100&organizationID=${organizationID}`, + 100, + undefined, + this.applicationServiceClient + )); + + // if application exist use it + let applicationId = applications.resultList.find( + element => + element.id === iotDevice.chirpstackApplicationId || element.id === iotDevice.application.chirpstackId + )?.id; + + // otherwise create new application + if (!applicationId) { + applicationId = await this.createNewApplication( + applicationId, + iotDevice.application.name, + iotDevice.application.id + ); + } + + return applicationId; + } + + public async createNewApplication(applicationId: string, name: string, id: number) { + applicationId = await this.createChirpstackApplication({ + application: { + name: `${this.applicationNamePrefix}${name}`, + description: this.DEFAULT_DESCRIPTION, + }, + }); + const existingApplication = await this.applicationRepository.findOneOrFail({ + where: { id: id }, + }); + existingApplication.chirpstackId = applicationId; + await this.applicationRepository.save(existingApplication); + return applicationId; + } + + public async createChirpstackApplication(dto: CreateChirpstackApplicationDto): Promise { const req = new CreateApplicationRequest(); const application = new Application(); - application.setDescription(this.DEFAULT_DESCRIPTION); - application.setName(this.defaultApplicationName + "-" + dto.name); + application.setDescription(dto.application.description); + application.setName(dto.application.name); application.setTenantId(await this.getDefaultOrganizationId()); req.setApplication(application); - try { - return await this.post("applications", this.applicationServiceClient, req); - } catch (e) { - throw e; - } + const applicationIdObject: IdResponse = await this.post("applications", this.applicationServiceClient, req); + return applicationIdObject.id; } + public async deleteApplication(id: string): Promise { const req = new DeleteApplicationRequest(); req.setId(id); @@ -46,7 +102,7 @@ export class ApplicationChirpstackService extends GenericChirpstackConfiguration const application = new Application(); application.setId(dto.chirpstackId); application.setDescription(this.DEFAULT_DESCRIPTION); - application.setName(this.defaultApplicationName + "-" + dto.name); + application.setName(this.applicationNamePrefix + "-" + dto.name); application.setTenantId(await this.getDefaultOrganizationId()); req.setApplication(application); try { diff --git a/src/services/chirpstack/chirpstack-device.service.ts b/src/services/chirpstack/chirpstack-device.service.ts index 9ae09ac1..2baab699 100644 --- a/src/services/chirpstack/chirpstack-device.service.ts +++ b/src/services/chirpstack/chirpstack-device.service.ts @@ -1,13 +1,9 @@ -import { BadRequestException, Injectable, Logger, NotFoundException } from "@nestjs/common"; -import { Application as ApplicationDb } from "@entities/application.entity"; - +import { BadRequestException, Injectable, InternalServerErrorException, Logger } from "@nestjs/common"; import { ChirpstackDeviceActivationContentsDto } from "@dto/chirpstack/chirpstack-device-activation-response.dto"; import { ChirpstackDeviceContentsDto } from "@dto/chirpstack/chirpstack-device-contents.dto"; import { ChirpstackDeviceKeysContentDto } from "@dto/chirpstack/chirpstack-device-keys-response.dto"; import { ChirpstackSingleApplicationResponseDto } from "@dto/chirpstack/chirpstack-single-application-response.dto"; -import { CreateChirpstackApplicationDto } from "@dto/chirpstack/create-chirpstack-application.dto"; import { CreateChirpstackDeviceDto } from "@dto/chirpstack/create-chirpstack-device.dto"; -import { ListAllChirpstackApplicationsResponseDto } from "@dto/chirpstack/list-all-applications-response.dto"; import { ListAllDevicesResponseDto } from "@dto/chirpstack/list-all-devices-response.dto"; import { CreateLoRaWANSettingsDto } from "@dto/create-lorawan-settings.dto"; import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; @@ -18,7 +14,7 @@ import { } from "@dto/chirpstack/chirpstack-device-downlink-queue-response.dto"; import { ErrorCodes } from "@enum/error-codes.enum"; import { - ChirpstackManyDeviceResponseContents, + ChirpstackDeviceResponseContents, ChirpstackManyDeviceResponseDto, } from "@dto/chirpstack/chirpstack-many-device-response"; import { IoTDevice } from "@entities/iot-device.entity"; @@ -26,20 +22,12 @@ import { LoRaWANDeviceWithChirpstackDataDto } from "@dto/lorawan-device-with-chi import { ActivationType } from "@enum/lorawan-activation-type.enum"; import { ChirpstackDeviceId } from "@dto/chirpstack/chirpstack-device-id.dto"; import { ChirpstackApplicationResponseDto } from "@dto/chirpstack/chirpstack-application-response.dto"; -import { groupBy } from "lodash"; import { LoRaWANStatsElementDto, LoRaWANStatsResponseDto } from "@dto/chirpstack/device/lorawan-stats.response.dto"; import { ConfigService } from "@nestjs/config"; -import { DeviceServiceClient } from "@chirpstack/chirpstack-api/api/device_grpc_pb"; import { DeviceProfileService } from "@services/chirpstack/device-profile.service"; import { ServiceError } from "@grpc/grpc-js"; -import { - Application, - CreateApplicationRequest, - GetApplicationRequest, - GetApplicationResponse, - ListApplicationsRequest, -} from "@chirpstack/chirpstack-api/api/application_pb"; +import { GetApplicationRequest, GetApplicationResponse } from "@chirpstack/chirpstack-api/api/application_pb"; import { ActivateDeviceRequest, CreateDeviceKeysRequest, @@ -66,7 +54,7 @@ import { UpdateDeviceKeysRequest, UpdateDeviceRequest, } from "@chirpstack/chirpstack-api/api/device_pb"; -import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; import { dateToTimestamp, timestampToDate } from "@helpers/date.helper"; import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; import { Aggregation } from "@chirpstack/chirpstack-api/common/common_pb"; @@ -89,65 +77,11 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi private readonly logger = new Logger(ChirpstackDeviceService.name); - defaultApplicationName = "os2iot"; - DEVICE_NAME_PREFIX = "OS2IOT-"; DEFAULT_DESCRIPTION = "Created by OS2IoT"; private readonly deviceStatsIntervalInDays: number; - async findOrCreateDefaultApplication( - applications: ListAllChirpstackApplicationsResponseDto = null, - iotDevice: LoRaWANDevice - ): Promise { - const organizationID = await this.getDefaultOrganizationId(); - const req = new ListApplicationsRequest(); - req.setTenantId(organizationID); - // Fetch applications - applications = - applications ?? - (await this.getAllWithPagination( - `applications?limit=100&organizationID=${organizationID}`, - 100, - undefined, - this.applicationServiceClient - )); - - // if application exist use it - let applicationId = applications.result.find( - element => - element.id === iotDevice.chirpstackApplicationId || element.id === iotDevice.application.chirpstackId - )?.id; - - // otherwise create new application - if (!applicationId) { - applicationId = await this.createNewApplication( - applicationId, - organizationID, - iotDevice.application.name, - iotDevice.application.id - ); - } - - return applicationId; - } - - private async createNewApplication(applicationId: string, organizationID: string, name: string, id: number) { - applicationId = await this.createApplication({ - application: { - name: `${this.defaultApplicationName}-${name}`, - description: this.DEFAULT_DESCRIPTION, - tenantId: organizationID, - }, - }); - const existingApplication = await this.applicationRepository.findOneOrFail({ - where: { id: id }, - }); - existingApplication.chirpstackId = applicationId; - await this.applicationRepository.save(existingApplication); - return applicationId; - } - - makeCreateChirpstackDeviceDto(dto: CreateLoRaWANSettingsDto, name: string): CreateChirpstackDeviceDto { + public makeCreateChirpstackDeviceDto(dto: CreateLoRaWANSettingsDto, name: string): CreateChirpstackDeviceDto { const csDto = new ChirpstackDeviceContentsDto(); csDto.name = `${this.DEVICE_NAME_PREFIX}${name}`.toLowerCase(); csDto.description = this.DEFAULT_DESCRIPTION; @@ -160,7 +94,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi return { device: csDto }; } - async overwriteDownlink(dto: CreateChirpstackDeviceQueueItemDto): Promise { + public async overwriteDownlink(dto: CreateChirpstackDeviceQueueItemDto): Promise { await this.deleteDownlinkQueue(dto.deviceQueueItem.devEUI); try { const req = new EnqueueDeviceQueueItemRequest(); @@ -171,7 +105,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi queueItem.setFPort(dto.deviceQueueItem.fPort); req.setQueueItem(queueItem); - const res = await this.postDownlink(this.deviceServiceClient, req); + const res = await this.postDownlink(req); return res; } catch (err) { const fcntError = "enqueue downlink payload error: get next downlink fcnt for deveui error"; @@ -183,7 +117,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi } } - async deleteDevice(deviceEUI: string): Promise { + public async deleteDevice(deviceEUI: string): Promise { try { const req = new DeleteDeviceRequest(); req.setDevEui(deviceEUI); @@ -193,43 +127,42 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi } } - async getDownlinkQueue(deviceEUI: string): Promise { + public async getDownlinkQueue(deviceEUI: string): Promise { const req = new GetDeviceQueueItemsRequest(); req.setDevEui(deviceEUI); - const res = await this.getQueue(this.deviceServiceClient, req); + const res = await this.getQueue(req); - const queueDto: DeviceQueueItem[] = []; - res.getResultList().forEach(queueItem => { - queueDto.push({ + const queueItems: DeviceQueueItem[] = res.getResultList().map(queueItem => { + return { confirmed: queueItem.getConfirmed(), devEUI: queueItem.getDevEui(), fCnt: queueItem.getFCntDown(), fPort: queueItem.getFPort(), data: queueItem.getData_asB64(), - }); + }; }); const responseDto: DeviceDownlinkQueueResponseDto = { totalCount: res.getTotalCount(), - deviceQueueItems: queueDto, + deviceQueueItems: queueItems, }; return responseDto; } - async deleteDownlinkQueue(deviceEUI: string): Promise { + private async deleteDownlinkQueue(deviceEUI: string): Promise { const req = new FlushDeviceQueueRequest(); req.setDevEui(deviceEUI); - await this.deleteQueue(this.deviceServiceClient, req); + await this.deleteQueue(req); } - async activateDeviceWithABP( + public async activateDeviceWithABP( devEUI: string, devAddr: string, fCntUp: number, nFCntDown: number, networkSessionKey: string, applicationSessionKey: string - ): Promise { + ): Promise { const res = await this.createOrUpdateABPActivation( devAddr, networkSessionKey, @@ -240,25 +173,29 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi ); if (!res) { this.logger.warn(`Could not ABP activate Chirpstack Device using DEVEUI: ${devEUI}}`); - return false; } - return true; } - async getAllDevicesStatus(app: ApplicationDb): Promise { + public async getAllDevicesStatus(application: DbApplication): Promise { const req = new ListDevicesRequest(); - if (!app.chirpstackId) { - const loraDev = app.iotDevices.find(d => d.type === IoTDeviceType.LoRaWAN); + if (!application.chirpstackId) { + const loraDev = application.iotDevices.find(d => d.type === IoTDeviceType.LoRaWAN); const cast = loraDev as LoRaWANDevice; + + const deviceRequest = new GetDeviceRequest(); + deviceRequest.setDevEui(cast.deviceEUI); + const getChirpstackDevice = await this.get( "device", this.deviceServiceClient, - new GetDeviceRequest().setDevEui(cast.deviceEUI) + deviceRequest ); - app.chirpstackId = getChirpstackDevice.getDevice().getApplicationId(); - await this.applicationRepository.save(app, {}); + + application.chirpstackId = getChirpstackDevice.getDevice().getApplicationId(); + await this.applicationRepository.save(application, {}); } - req.setApplicationId(app.chirpstackId); + + req.setApplicationId(application.chirpstackId); const devices = await this.getAllWithPagination( `devices`, 10000, @@ -266,10 +203,9 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi this.deviceServiceClient, req ); - const responseDto: ChirpstackManyDeviceResponseContents[] = []; - devices.resultList.map(e => { - const responseItem: ChirpstackManyDeviceResponseContents = { + const responseDevvice: ChirpstackDeviceResponseContents[] = devices.resultList.map(e => { + return { devEUI: e.devEui, name: e.name, description: e.description, @@ -280,11 +216,10 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi deviceProfileID: e.deviceProfileId, deviceProfileName: e.deviceProfileName, }; - responseDto.push(responseItem); }); return { totalCount: devices.totalCount.toString(), - result: responseDto, + result: responseDevvice, }; } @@ -307,14 +242,14 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi ); req.setDeviceActivation(deviceActivation); try { - await this.postActivation(this.deviceServiceClient, req); + await this.postActivation(req); } catch (e) { return false; } return true; } - mapActivationToChirpstack( + private mapActivationToChirpstack( devAddr: string, networkSessionKey: string, applicationSessionKey: string, @@ -334,19 +269,18 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi return deviceActivation; } - async activateDeviceWithOTAA(deviceEUI: string, nwkKey: string, isUpdate: boolean): Promise { + public async activateDeviceWithOTAA(deviceEUI: string, nwkKey: string, isUpdate: boolean): Promise { try { if (isUpdate) { const req = new UpdateDeviceKeysRequest(); const deviceKeys = this.mapDeviceKeysToChirpstack(deviceEUI, nwkKey); req.setDeviceKeys(deviceKeys); - await this.putKeys(this.deviceServiceClient, req); + await this.putKeys(req); } else { const req = new CreateDeviceKeysRequest(); const deviceKeys = this.mapDeviceKeysToChirpstack(deviceEUI, nwkKey); req.setDeviceKeys(deviceKeys); - - await this.postKeys(this.deviceServiceClient, req); + await this.postKeys(req); } } catch (e) { return false; @@ -355,14 +289,14 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi return true; } - mapDeviceKeysToChirpstack(deviceEUI: string, nwkKey: string) { + private mapDeviceKeysToChirpstack(deviceEUI: string, nwkKey: string) { const deviceKeys = new DeviceKeys(); deviceKeys.setDevEui(deviceEUI); deviceKeys.setNwkKey(nwkKey); return deviceKeys; } - async createOrUpdateDevice( + public async createOrUpdateDevice( dto: CreateChirpstackDeviceDto, lorawanDevices: ChirpstackDeviceId[] = null ): Promise { @@ -379,12 +313,13 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi await this.post(`devices`, this.deviceServiceClient, req); } } catch (e) { + this.logger.error(`Update or Post device got error: ${e}`); return false; } return true; } - mapDeviceToChirpstack(dto: CreateChirpstackDeviceDto): Device { + private mapDeviceToChirpstack(dto: CreateChirpstackDeviceDto): Device { const device = new Device(); device.setApplicationId(dto.device.applicationID); device.setDescription(dto.device.description); @@ -395,22 +330,22 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi device.setSkipFcntCheck(dto.device.skipFCntCheck); return device; } - async getChirpstackApplication(id: string): Promise { + private async getChirpstackApplication(id: string): Promise { const req = new GetApplicationRequest(); req.setId(id); try { - const csApplication = await this.get( + const chirpstackApplicationResponse = await this.get( `applications/${id}`, this.applicationServiceClient, req ); - + const chirpstackApplication = chirpstackApplicationResponse.getApplication(); const applicationDto = new ChirpstackApplicationResponseDto(); - applicationDto.name = csApplication.getApplication().getName(); - applicationDto.description = csApplication.getApplication().getDescription(); - applicationDto.id = csApplication.getApplication().getId(); - applicationDto.tenantId = csApplication.getApplication().getTenantId(); + applicationDto.name = chirpstackApplication.getName(); + applicationDto.description = chirpstackApplication.getDescription(); + applicationDto.id = chirpstackApplication.getId(); + applicationDto.tenantId = chirpstackApplication.getTenantId(); const returnDto = new ChirpstackSingleApplicationResponseDto(); returnDto.application = applicationDto; @@ -421,25 +356,26 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi } } - async getChirpstackDevice(id: string): Promise { + public async getChirpstackDevice(id: string): Promise { try { const req = new GetDeviceRequest(); req.setDevEui(id); const res = await this.get(`devices/${id}`, this.deviceServiceClient, req); + const device = res.getDevice(); const deviceDto: ChirpstackDeviceContentsDto = { deviceStatusBattery: res.getDeviceStatus()?.getBatteryLevel(), deviceStatusMargin: res.getDeviceStatus()?.getMargin(), - devEUI: res.getDevice().getDevEui(), - deviceProfileID: res.getDevice().getDeviceProfileId(), - applicationID: res.getDevice().getApplicationId(), - description: res.getDevice().getDescription(), - isDisabled: res.getDevice().getIsDisabled(), - name: res.getDevice().getName(), - skipFCntCheck: res.getDevice().getSkipFcntCheck(), - tags: res.getDevice().getTagsMap().toObject(), - variables: res.getDevice().getVariablesMap().toObject(), + devEUI: device.getDevEui(), + deviceProfileID: device.getDeviceProfileId(), + applicationID: device.getApplicationId(), + description: device.getDescription(), + isDisabled: device.getIsDisabled(), + name: device.getName(), + skipFCntCheck: device.getSkipFcntCheck(), + tags: device.getTagsMap().toObject(), + variables: device.getVariablesMap().toObject(), }; return deviceDto; @@ -448,17 +384,17 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi } } - async getDeviceKeys(deviceId: string): Promise { + private async getDeviceKeys(deviceId: string): Promise { try { const req = new GetDeviceKeysRequest(); req.setDevEui(deviceId); - const res = await this.getKeys(this.deviceServiceClient, req); + const res = (await this.getKeys(req)).getDeviceKeys(); const keysDto: ChirpstackDeviceKeysContentDto = { - appKey: res.getDeviceKeys().getAppKey(), - devEUI: res.getDeviceKeys().getDevEui(), - nwkKey: res.getDeviceKeys().getNwkKey(), + appKey: res.getAppKey(), + devEUI: res.getDevEui(), + nwkKey: res.getNwkKey(), }; return keysDto; @@ -469,23 +405,23 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi } } - async getDeviceActivation(deviceId: string): Promise { + private async getDeviceActivation(deviceId: string): Promise { try { const req = new GetDeviceActivationRequest(); req.setDevEui(deviceId); - const res = await this.getActivation(this.deviceServiceClient, req); + const res = (await this.getActivation(req)).getDeviceActivation(); const activationDto: ChirpstackDeviceActivationContentsDto = { - aFCntDown: res.getDeviceActivation().getAFCntDown(), - devEUI: res.getDeviceActivation().getDevEui(), - appSKey: res.getDeviceActivation().getAppSKey(), - devAddr: res.getDeviceActivation().getDevAddr(), - fCntUp: res.getDeviceActivation().getFCntUp(), - fNwkSIntKey: res.getDeviceActivation().getFNwkSIntKey(), - nFCntDown: res.getDeviceActivation().getAFCntDown(), - nwkSEncKey: res.getDeviceActivation().getNwkSEncKey(), - sNwkSIntKey: res.getDeviceActivation().getSNwkSIntKey(), + aFCntDown: res.getAFCntDown(), + devEUI: res.getDevEui(), + appSKey: res.getAppSKey(), + devAddr: res.getDevAddr(), + fCntUp: res.getFCntUp(), + fNwkSIntKey: res.getFNwkSIntKey(), + nFCntDown: res.getAFCntDown(), + nwkSEncKey: res.getNwkSEncKey(), + sNwkSIntKey: res.getSNwkSIntKey(), }; return activationDto; } catch (err) { @@ -499,7 +435,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi * @param applications * @returns The mutated device */ - async enrichLoRaWANDevice(iotDevice: IoTDevice): Promise { + public async enrichLoRaWANDevice(iotDevice: IoTDevice): Promise { const loraDevice = iotDevice as LoRaWANDeviceWithChirpstackDataDto; loraDevice.lorawanSettings = new CreateLoRaWANSettingsDto(); await this.mapActivationAndKeys(loraDevice); @@ -540,13 +476,16 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi } } - async isDeviceAlreadyCreated(deviceEUI: string, chirpstackIds: ChirpstackDeviceId[] = null): Promise { + public async isDeviceAlreadyCreated( + deviceEUI: string, + chirpstackIds: ChirpstackDeviceId[] = null + ): Promise { const devices = !chirpstackIds ? await this.getAllChirpstackDevices() : chirpstackIds; const alreadyExists = devices.some(x => x.devEUI.toLowerCase() === deviceEUI.toLowerCase()); return alreadyExists; } - async getStats(deviceEUI: string): Promise { + public async getStats(deviceEUI: string): Promise { const now = new Date(); const to_time = dateToTimestamp(now); const from_time = new Date(new Date().setDate(now.getDate() - this.deviceStatsIntervalInDays)); @@ -577,7 +516,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi } private mapMetrics(metrics: GetDeviceLinkMetricsResponse): LoRaWANStatsResponseDto { const statsElementDto: LoRaWANStatsElementDto[] = []; - const packetCounts: DeviceMetricsDto = {}; + const deviceMetrics: DeviceMetricsDto = {}; const rssiTimestamp = metrics.getGwRssi().getTimestampsList(); const rssis = metrics @@ -586,7 +525,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi .find(e => e.getLabel() === "rssi") .getDataList(); - this.processPackets(rssiTimestamp, rssis, MetricProperties.rssi, packetCounts); + this.processPackets(rssiTimestamp, rssis, MetricProperties.rssi, deviceMetrics); const snrTimestamp = metrics.getGwSnr().getTimestampsList(); const snr = metrics @@ -595,7 +534,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi .find(e => e.getLabel() === "snr") .getDataList(); - this.processPackets(snrTimestamp, snr, MetricProperties.snr, packetCounts); + this.processPackets(snrTimestamp, snr, MetricProperties.snr, deviceMetrics); const drTimestamp = metrics.getRxPacketsPerDr().getTimestampsList(); const drDatasets = metrics.getRxPacketsPerDr().getDatasetsList(); @@ -603,11 +542,11 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi drDatasets.forEach(drDataset => { const drLabel = drDataset.getLabel(); const drData = drDataset.getDataList(); - this.processPackets(drTimestamp, drData, MetricProperties.dr, packetCounts, drLabel); + this.processPackets(drTimestamp, drData, MetricProperties.dr, deviceMetrics, drLabel); }); - Object.keys(packetCounts).forEach(timestamp => { - const packetCount = packetCounts[timestamp]; + Object.keys(deviceMetrics).forEach(timestamp => { + const packetCount = deviceMetrics[timestamp]; const dto: LoRaWANStatsElementDto = { timestamp, gwRssi: packetCount.rssi, @@ -641,207 +580,128 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi }); }; - /** - * Fetch LoRaWAN applications by the device application id. This **assumes** that - * the device chirpstack application id always reflects what's on Chirpstack. - * @param devices - * @returns - */ - public async getLoRaWANApplications( - devices: LoRaWANDeviceWithChirpstackDataDto[] - ): Promise { - const loraDevicesByAppId = groupBy(devices, device => device.chirpstackApplicationId); + //TODO:: FIX THIS! + private async getAllChirpstackDevices(): Promise { + const req = new ListDevicesRequest(); - const res: ChirpstackSingleApplicationResponseDto[] = []; + const devices = await this.getAllWithPagination( + `devices`, + 1000, + 0, + this.deviceServiceClient, + req + ); - // Avoid async .forEach and .map when querying the API. They execute whatever's inside in "parallel" which can result in timeouts. - for (const appId of Object.keys(loraDevicesByAppId)) { - res.push(await this.getChirpstackApplication(appId)); - } + const responseDevice: ChirpstackDeviceResponseContents[] = devices.resultList.map(e => { + return { + devEUI: e.devEui, + name: e.name, + description: e.description, + lastSeenAt: e.lastSeenAt ? timestampToDate(e.lastSeenAt) : undefined, + deviceStatusBattery: e.deviceStatus?.batteryLevel, + deviceStatusMargin: e.deviceStatus?.margin, + deviceStatusExternalPowerSource: e.deviceStatus?.externalPowerSource, + deviceProfileID: e.deviceProfileId, + deviceProfileName: e.deviceProfileName, + }; + }); - return res; + return responseDevice; } - private async getAllChirpstackDevices(limit = 1000): Promise { - return (await this.get(`devices?limit=${limit}`)).result; + private async getKeys(request: GetDeviceKeysRequest): Promise { + return await this.makeRequest( + request, + this.deviceServiceClient.getKeys, + "GET KEYS success", + "GET KEYS failed and got error: " + ); } - private async createApplication(dto: CreateChirpstackApplicationDto): Promise { - const req = new CreateApplicationRequest(); - const application = new Application(); - application.setDescription(dto.application.description); - application.setName(dto.application.name); - application.setTenantId(dto.application.tenantId); - - req.setApplication(application); - const applicationIdObject: PostReturnInterface = await this.post( - "applications", - this.applicationServiceClient, - req + private async postKeys(request: CreateDeviceKeysRequest): Promise { + await this.makeRequest( + request, + this.deviceServiceClient.createKeys, + "POST KEYS success", + "POST KEYS failed and got error: " ); - return applicationIdObject.id; } - async getKeys(client: DeviceServiceClient, request: GetDeviceKeysRequest): Promise { - const metaData = this.makeMetadataHeader(); - const getPromise = new Promise((resolve, reject) => { - client.getKeys(request, metaData, (err: ServiceError, resp: any) => { - if (err) { - reject(err); - } else { - this.logger.debug(`get from Keys success`); - resolve(resp); - } - }); - }); - try { - return await getPromise; - } catch (err) { - throw new NotFoundException(); - } - } - async postKeys(client: DeviceServiceClient, request: CreateDeviceKeysRequest): Promise { - const metaData = this.makeMetadataHeader(); - const createPromise = new Promise((resolve, reject) => { - client.createKeys(request, metaData, (err: ServiceError, resp: any) => { - if (err) { - reject(err); - } else { - this.logger.debug(`post KEYS success`); - resolve(resp); - } - }); - }); - try { - return await createPromise; - } catch (err) { - this.logger.error(`POST KEYS got error: ${err}`); - throw new BadRequestException(); - } + private async putKeys(request: UpdateDeviceKeysRequest): Promise { + await this.makeRequest( + request, + this.deviceServiceClient.updateKeys, + "UPDATE KEYS success", + "UPDATE KEYS failed and got error: " + ); } - async putKeys(client: DeviceServiceClient, request: UpdateDeviceKeysRequest): Promise { - const metaData = this.makeMetadataHeader(); - const updatePromise = new Promise((resolve, reject) => { - client.updateKeys(request, metaData, (err: ServiceError, resp: any) => { - if (err) { - reject(err); - } else { - this.logger.debug(`update KEYS success`); - resolve(resp); - } - }); - }); - try { - return await updatePromise; - } catch (err) { - this.logger.error(`UPDATE KEYS got error: ${err}`); - throw new BadRequestException(); - } + + private async getQueue(request: GetDeviceQueueItemsRequest): Promise { + return await this.makeRequest( + request, + this.deviceServiceClient.getQueue, + "GET QUEUE success", + "GET QUEUE failed and got error: " + ); } - async getQueue( - client: DeviceServiceClient, - request: GetDeviceQueueItemsRequest - ): Promise { - const metaData = this.makeMetadataHeader(); - const getPromise = new Promise((resolve, reject) => { - client.getQueue(request, metaData, (err: ServiceError, resp: any) => { - if (err) { - reject(err); - } else { - this.logger.debug(`get from Queue success`); - resolve(resp); - } - }); - }); - try { - return await getPromise; - } catch (err) { - throw new NotFoundException(); - } + private async deleteQueue(request: FlushDeviceQueueRequest): Promise { + await this.makeRequest( + request, + this.deviceServiceClient.flushQueue, + "DELETE QUEUE success", + "DELETE QUEUE failed and got error: " + ); } - async deleteQueue(client: DeviceServiceClient, request: FlushDeviceQueueRequest): Promise { - const metaData = this.makeMetadataHeader(); - const getPromise = new Promise((resolve, reject) => { - client.flushQueue(request, metaData, (err: ServiceError, resp: any) => { - if (err) { - reject(err); - } else { - this.logger.debug(`Delete queue success`); - resolve(resp); - } - }); - }); - try { - return await getPromise; - } catch (err) { - this.logger.error(`DELETE queue got error: ${err}`); - throw new BadRequestException(); - } + + private async postDownlink(request: EnqueueDeviceQueueItemRequest): Promise { + return await this.makeRequest( + request, + this.deviceServiceClient.enqueue, + "POST DOWNLINK success", + "POST DOWNLINK failed and got error :" + ); } - async postDownlink( - client: DeviceServiceClient, - request: EnqueueDeviceQueueItemRequest - ): Promise { - const metaData = this.makeMetadataHeader(); - const createPromise = new Promise((resolve, reject) => { - client.enqueue(request, metaData, (err: ServiceError, resp: any) => { - if (err) { - reject(err); - } else { - this.logger.debug(`post downlink success`); - resolve(resp.toObject()); - } - }); - }); - try { - return await createPromise; - } catch (err) { - this.logger.error(`POST downlink got error: ${err}`); - throw new BadRequestException(); - } + private async getActivation(request: GetDeviceActivationRequest): Promise { + return await this.makeRequest( + request, + this.deviceServiceClient.getActivation, + "GET ACTIVATION success", + "GET ACTIVATION failed and got error: " + ); } - async getActivation( - client: DeviceServiceClient, - request: GetDeviceActivationRequest - ): Promise { - const metaData = this.makeMetadataHeader(); - const getPromise = new Promise((resolve, reject) => { - client.getActivation(request, metaData, (err: ServiceError, resp: any) => { - if (err) { - reject(err); - } else { - this.logger.debug(`get from Activation success`); - resolve(resp); - } - }); - }); - try { - return await getPromise; - } catch (err) { - this.logger.error(`GET Activation got error: ${err}`); - throw new NotFoundException(); - } + private async postActivation(request?: ActivateDeviceRequest): Promise { + await this.makeRequest( + request, + this.deviceServiceClient.activate, + "post ACTIVATION success", + "GET activation failed and got error: " + ); } - async postActivation(client?: DeviceServiceClient, request?: ActivateDeviceRequest): Promise { + private async makeRequest( + request: any, + method: (request: any, metaData: any, callback: (err: ServiceError, resp: any) => void) => void, + successMessage: string, + errorMessage: string + ): Promise { const metaData = this.makeMetadataHeader(); - const createPromise = new Promise((resolve, reject) => { - client.activate(request, metaData, (err: ServiceError, resp: any) => { + const promise = new Promise((resolve, reject) => { + method.call(this.deviceServiceClient, request, metaData, (err: ServiceError, resp: any) => { if (err) { reject(err); } else { - this.logger.debug(`post ACTIVATION success`); + this.logger.debug(successMessage); resolve(resp); } }); }); try { - return await createPromise; + return await promise; } catch (err) { - this.logger.error(`POST ACTIVATION got error: ${err}`); - throw new BadRequestException(); + this.logger.error(errorMessage, +err); + throw new InternalServerErrorException(); } } } diff --git a/src/services/chirpstack/chirpstack-gateway.service.ts b/src/services/chirpstack/chirpstack-gateway.service.ts index 18479cc2..c5bc2e6e 100644 --- a/src/services/chirpstack/chirpstack-gateway.service.ts +++ b/src/services/chirpstack/chirpstack-gateway.service.ts @@ -8,8 +8,11 @@ import { import { ChirpstackErrorResponseDto } from "@dto/chirpstack/chirpstack-error-response.dto"; import { ChirpstackResponseStatus } from "@dto/chirpstack/chirpstack-response.dto"; import { CreateGatewayDto } from "@dto/chirpstack/create-gateway.dto"; -import { GatewayStatsElementDto, GatewayStatsResponseDto } from "@dto/chirpstack/gateway-stats.response.dto"; -import { ListAllGatewaysResponseGrpcDto } from "@dto/chirpstack/list-all-gateways.dto"; +import { GatewayStatsElementDto } from "@dto/chirpstack/gateway-stats.response.dto"; +import { + ListAllGatewaysResponseChirpstackDto, + ListAllGatewaysResponseDto, +} from "@dto/chirpstack/list-all-gateways.dto"; import { SingleGatewayResponseDto } from "@dto/chirpstack/single-gateway-response.dto"; import { UpdateGatewayContentsDto, UpdateGatewayDto } from "@dto/chirpstack/update-gateway.dto"; import { ErrorCodes } from "@enum/error-codes.enum"; @@ -18,29 +21,30 @@ import { GatewayContentsDto } from "@dto/chirpstack/gateway-contents.dto"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; import { checkIfUserHasAccessToOrganization, OrganizationAccessScope } from "@helpers/security-helper"; import { InjectRepository } from "@nestjs/typeorm"; -import { Gateway as GatewayDb } from "@entities/gateway.entity"; +import { Gateway as DbGateway } from "@entities/gateway.entity"; import { Repository } from "typeorm"; import { OrganizationService } from "@services/user-management/organization.service"; import { CommonLocationDto } from "@dto/chirpstack/common-location.dto"; -import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; -import { GatewayServiceClient } from "@chirpstack/chirpstack-api/api/gateway_grpc_pb"; import { CreateGatewayRequest, DeleteGatewayRequest, - Gateway as GatewayCs, + Gateway as ChirpstackGateway, GetGatewayMetricsRequest, GetGatewayMetricsResponse, GetGatewayResponse, + ListGatewaysRequest, UpdateGatewayRequest, + ListGatewaysResponse, } from "@chirpstack/chirpstack-api/api/gateway_pb"; import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; import { Aggregation, Location } from "@chirpstack/chirpstack-api/common/common_pb"; import { dateToTimestamp, timestampToDate } from "@helpers/date.helper"; +import { GatewayResponseChirpstackDto, GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto"; @Injectable() export class ChirpstackGatewayService extends GenericChirpstackConfigurationService { constructor( - @InjectRepository(GatewayDb) - private gatewayRepository: Repository, + @InjectRepository(DbGateway) + private gatewayRepository: Repository, private organizationService: OrganizationService ) { super(); @@ -49,9 +53,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ private readonly logger = new Logger(ChirpstackGatewayService.name, { timestamp: true, }); - private readonly ORG_ID_KEY = "internalOrganizationId"; - private readonly UPDATED_BY_KEY = "os2iot-updated-by"; - private readonly CREATED_BY_KEY = "os2iot-created-by"; + async createNewGateway(dto: CreateGatewayDto, userId: number): Promise { dto.gateway = await this.updateDtoContents(dto.gateway); @@ -67,19 +69,19 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ gateway.organization = await this.organizationService.findById(dto.organizationId); const req = new CreateGatewayRequest(); - const location = new Location(); - this.mapToLocationChirpstack(location, dto); + const chirpstackLocation = new Location(); + this.mapToChirpstackLocation(chirpstackLocation, dto); - const gatewayCs = new GatewayCs(); - await this.mapToGatewayChirpstack(gatewayCs, dto, location); + const gatewayCs = new ChirpstackGateway(); + await this.mapToChirpstackGateway(gatewayCs, dto, chirpstackLocation); Object.entries(dto.gateway.tags).forEach(([key, value]) => { gatewayCs.getTagsMap().set(key, value); }); req.setGateway(gatewayCs); try { - await this.gatewayRepository.save(gateway); await this.post("gateways", this.gatewayClient, req); + await this.gatewayRepository.save(gateway); return { success: true }; } catch (e) { this.logger.error(`Error from Chirpstack: '${JSON.stringify(dto)}', got response: ${JSON.stringify(e)}`); @@ -90,8 +92,8 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ } } - async mapToGatewayChirpstack( - gateway: GatewayCs, + async mapToChirpstackGateway( + gateway: ChirpstackGateway, dto: CreateGatewayDto | UpdateGatewayDto, location: Location, gatewayId?: string @@ -103,7 +105,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ gateway.setStatsInterval(30); gateway.setTenantId(dto.gateway.tenantId ? dto.gateway.tenantId : await this.getDefaultOrganizationId()); } - mapToLocationChirpstack(location: Location, dto: CreateGatewayDto | UpdateGatewayDto) { + mapToChirpstackLocation(location: Location, dto: CreateGatewayDto | UpdateGatewayDto) { location.setAccuracy(dto.gateway.location.accuracy); location.setAltitude(dto.gateway.location.altitude); location.setLatitude(dto.gateway.location.latitude); @@ -118,10 +120,9 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ return tags; } - updateTags(dto: UpdateGatewayDto, userId: number): { [id: string]: string } { + updateUpdatedByTag(dto: UpdateGatewayDto, userId: number): { [id: string]: string } { const tags = dto.gateway.tags; tags[this.UPDATED_BY_KEY] = `${userId}`; - tags[this.CREATED_BY_KEY] = `${dto.gateway.createdBy}`; return tags; } @@ -131,7 +132,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ return tags; } - async getAll(organizationId?: number): Promise { + async getAll(organizationId?: number): Promise { let query = this.gatewayRepository .createQueryBuilder("gateway") .innerJoinAndSelect("gateway.organization", "organization"); @@ -260,20 +261,19 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ ): Promise { dto.gateway = await this.updateDtoContents(dto.gateway); dto.gateway.tags = await this.ensureOrganizationIdIsSet(gatewayId, dto, req); - dto.gateway.tags = this.updateTags(dto, +req.user.userId); + dto.gateway.tags = this.updateUpdatedByTag(dto, +req.user.userId); const gateway = this.mapContentsDtoToGateway(dto.gateway); gateway.gatewayId = gatewayId; gateway.updatedBy = req.user.userId; - gateway.updatedAt = new Date(); const request = new UpdateGatewayRequest(); const location = new Location(); - this.mapToLocationChirpstack(location, dto); + this.mapToChirpstackLocation(location, dto); - const gatewayCs = new GatewayCs(); + const gatewayCs = new ChirpstackGateway(); - await this.mapToGatewayChirpstack(gatewayCs, dto, location, gatewayId); + await this.mapToChirpstackGateway(gatewayCs, dto, location, gatewayId); Object.entries(dto.gateway.tags).forEach(([key, value]) => { gatewayCs.getTagsMap().set(key, value); @@ -281,8 +281,8 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ request.setGateway(gatewayCs); try { - await this.gatewayRepository.update({ gatewayId }, gateway); await this.put("gateways", this.gatewayClient, request); + await this.gatewayRepository.update({ gatewayId }, gateway); return { success: true }; } catch (e) { this.logger.error(`Error from Chirpstack: '${JSON.stringify(dto)}', got response: ${JSON.stringify(e)}`); @@ -309,7 +309,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ ): Promise<{ [id: string]: string }> { const existing = await this.getOne(gatewayId); const tags = dto.gateway.tags; - tags[this.ORG_ID_KEY] = `${existing.gateway.internalOrganizationId}`; + tags[this.ORG_ID_KEY] = `${existing.gateway.organizationId}`; // TODO: Interpolated string will never be null? if (tags[this.ORG_ID_KEY] != null) { checkIfUserHasAccessToOrganization(req, +tags[this.ORG_ID_KEY], OrganizationAccessScope.GatewayWrite); @@ -321,8 +321,8 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ const req = new DeleteGatewayRequest(); req.setGatewayId(gatewayId); try { - await this.gatewayRepository.delete({ gatewayId }); await this.delete("gateways", this.gatewayClient, req); + await this.gatewayRepository.delete({ gatewayId }); return { success: true, }; @@ -338,20 +338,17 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ private async updateDtoContents( contentsDto: GatewayContentsDto | UpdateGatewayContentsDto ): Promise { - // Chirpstack requires 'gatewayProfileID' to be set (with value or null) - if (!contentsDto?.gatewayProfileID) { - contentsDto.gatewayProfileID = null; - } - if (contentsDto?.tagsString) { contentsDto.tags = JSON.parse(contentsDto.tagsString); } + contentsDto.id = contentsDto.gatewayId; + return contentsDto; } public mapContentsDtoToGateway(dto: GatewayContentsDto) { - const gateway = new GatewayDb(); + const gateway = new DbGateway(); gateway.name = dto.name; gateway.gatewayId = dto.gatewayId; gateway.description = dto.description; @@ -369,17 +366,21 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ return gateway; } - public mapCsGwToGateway(gw: GatewayCs, gwResponse: GetGatewayResponse) { - const gateway = new GatewayDb(); - gateway.name = gw.getName(); - gateway.gatewayId = gw.getGatewayId(); - gateway.description = gw.getDescription(); - gateway.altitude = gw.getLocation().getAltitude(); + //TODO:: Check that it works + public mapChirpstackGatewayToDatabaseGateway(chirpstackGateway: ChirpstackGateway, gwResponse: GetGatewayResponse) { + const gateway = new DbGateway(); + gateway.name = chirpstackGateway.getName(); + gateway.gatewayId = chirpstackGateway.getGatewayId(); + gateway.description = chirpstackGateway.getDescription(); + gateway.altitude = chirpstackGateway.getLocation().getAltitude(); gateway.location = { type: "Point", - coordinates: [gw.getLocation().getLongitude(), gw.getLocation().getLatitude()], + coordinates: [ + chirpstackGateway.getLocation().getLongitude(), + chirpstackGateway.getLocation().getLatitude(), + ], }; - const jsonRepresentation: Record = gw + const jsonRepresentation: Record = chirpstackGateway .getTagsMap() .toArray() .reduce((obj: Record, [key, value]) => { @@ -390,32 +391,32 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ jsonRepresentation["os2iot-updated-by"] = undefined; jsonRepresentation["os2iot-created-by"] = undefined; gateway.tags = JSON.stringify(jsonRepresentation); - (gateway.lastSeenAt = gwResponse.getLastSeenAt() + gateway.lastSeenAt = gwResponse.getLastSeenAt() ? timestampToDate(gwResponse.getLastSeenAt().toObject()) - : undefined), - (gateway.createdAt = gwResponse.getCreatedAt() - ? timestampToDate(gwResponse.getCreatedAt().toObject()) - : undefined); - (gateway.updatedAt = gwResponse.getUpdatedAt() + : undefined; + gateway.createdAt = gwResponse.getCreatedAt() + ? timestampToDate(gwResponse.getCreatedAt().toObject()) + : undefined; + gateway.updatedAt = gwResponse.getUpdatedAt() ? timestampToDate(gwResponse.getUpdatedAt().toObject()) - : undefined), - (gateway.rxPacketsReceived = 0); + : undefined; + gateway.rxPacketsReceived = 0; gateway.txPacketsEmitted = 0; gateway.createdBy = - gw.getTagsMap().get("os2iot-created-by") !== undefined - ? Number(gw.getTagsMap().get("os2iot-created-by")) + chirpstackGateway.getTagsMap().get("os2iot-created-by") !== undefined + ? Number(chirpstackGateway.getTagsMap().get("os2iot-created-by")) : undefined; gateway.updatedBy = - gw.getTagsMap().get("os2iot-updated-by") !== undefined - ? Number(gw.getTagsMap().get("os2iot-updated-by")) + chirpstackGateway.getTagsMap().get("os2iot-updated-by") !== undefined + ? Number(chirpstackGateway.getTagsMap().get("os2iot-updated-by")) : undefined; return gateway; } - private mapGatewayToResponseDto(gateway: GatewayDb): GatewayResponseGrpcDto { - const responseDto = gateway as unknown as GatewayResponseGrpcDto; - responseDto.internalOrganizationId = gateway.organization.id; - responseDto.internalOrganizationName = gateway.organization.name; + private mapGatewayToResponseDto(gateway: DbGateway): GatewayResponseDto { + const responseDto = gateway as unknown as GatewayResponseDto; + responseDto.organizationId = gateway.organization.id; + responseDto.organizationName = gateway.organization.name; const commonLocation = new CommonLocationDto(); commonLocation.latitude = gateway.location.coordinates[1]; @@ -426,4 +427,35 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ return responseDto; } + async getAllGatewaysFromChirpstack(): Promise { + const limit = 1000; + const listReq = new ListGatewaysRequest(); + // Get all chirpstack gateways + const chirpStackGateways = await this.getAllWithPagination( + "gateways", + limit, + 0, + this.gatewayClient, + listReq + ); + + const responseItem: GatewayResponseChirpstackDto[] = []; + chirpStackGateways.resultList.map(e => { + const resultItem: GatewayResponseChirpstackDto = { + gatewayId: e.gatewayId, + name: e.name, + location: e.location, + description: e.description, + createdAt: e.createdAt ?? undefined, + updatedAt: e.updatedAt ?? undefined, + lastSeenAt: e.lastSeenAt ?? undefined, + }; + responseItem.push(resultItem); + }); + const responseList: ListAllGatewaysResponseChirpstackDto = { + totalCount: chirpStackGateways.totalCount, + resultList: responseItem, + }; + return responseList; + } } diff --git a/src/services/chirpstack/device-profile.service.ts b/src/services/chirpstack/device-profile.service.ts index 14ba1610..08d008af 100644 --- a/src/services/chirpstack/device-profile.service.ts +++ b/src/services/chirpstack/device-profile.service.ts @@ -32,18 +32,14 @@ import { timestampToDate } from "@helpers/date.helper"; import { ListAllAdrAlgorithmsResponseDto } from "@dto/chirpstack/list-all-adr-algorithms-response.dto"; import { Empty } from "google-protobuf/google/protobuf/empty_pb"; import { AdrAlgorithmDto } from "@dto/chirpstack/adr-algorithm.dto"; -import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; import { DeviceListItem, ListDevicesRequest, ListDevicesResponse } from "@chirpstack/chirpstack-api/api/device_pb"; import { ListApplicationsRequest, ListApplicationsResponse } from "@chirpstack/chirpstack-api/api/application_pb"; import * as google_protobuf_empty_pb from "google-protobuf/google/protobuf/empty_pb"; @Injectable() export class DeviceProfileService extends GenericChirpstackConfigurationService { - private readonly ORG_ID_KEY = "internalOrganizationId"; - private readonly UPDATED_BY_KEY = "os2iot-updated-by"; - private readonly CREATED_BY_KEY = "os2iot-created-by"; - - public async createDeviceProfile(dto: CreateDeviceProfileDto, userId: number): Promise { + public async createDeviceProfile(dto: CreateDeviceProfileDto, userId: number): Promise { if (await this.isNameInUse(dto.deviceProfile.name)) { throw new BadRequestException(ErrorCodes.NameInvalidOrAlreadyInUse); } @@ -51,17 +47,16 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService dto.deviceProfile.tags = this.addOrganizationToTags(dto); dto.deviceProfile.tags = this.addUserIdToTags(dto, userId); - const deviceProfile = new DeviceProfile(); const req = new CreateDeviceProfileRequest(); + const deviceProfile = this.mapToChirpstackDto(dto, true); + Object.entries(dto.deviceProfile.tags).forEach(([key, value]) => { deviceProfile.getTagsMap().set(key, value); }); - this.mapToChirpstackDto(deviceProfile, dto, true); - req.setDeviceProfile(deviceProfile); - const result: PostReturnInterface = await this.post("device-profiles", this.deviceProfileClient, req); + const result: IdResponse = await this.post("device-profiles", this.deviceProfileClient, req); return result; } @@ -86,15 +81,12 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService if (await this.isNameInUse(data.deviceProfile.name, id)) { throw new BadRequestException(ErrorCodes.NameInvalidOrAlreadyInUse); } - const deviceProfile = new DeviceProfile(); + const deviceProfile = this.mapToChirpstackDto(data); const request = new UpdateDeviceProfileRequest(); - this.mapToChirpstackDto(deviceProfile, data); data.deviceProfile.tags = await this.updateTags(id, req); data.deviceProfile = await this.updateDto(data.deviceProfile); - Object.entries(data.deviceProfile.tags).forEach(([key, value]) => { - deviceProfile.getTagsMap().set(key, value); - }); + request.setDeviceProfile(deviceProfile); return await this.put("device-profiles", this.deviceProfileClient, request); } @@ -171,7 +163,6 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService } if (result.getDeviceProfile().getTagsMap().get(this.ORG_ID_KEY) != null) { - [] = []; checkIfUserHasAccessToOrganization( req, +result.getDeviceProfile().getTagsMap().get(this.ORG_ID_KEY), @@ -194,15 +185,14 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService this.deviceProfileClient, req ); - const deviceResultListDto: DeviceProfileListDto[] = []; - result.resultList.map(e => { - const resultItem: DeviceProfileListDto = { + + const deviceResultListDto: DeviceProfileListDto[] = result.resultList.map(e => { + return { name: e.name, createdAt: timestampToDate(e.createdAt), updatedAt: timestampToDate(e.updatedAt), id: e.id, }; - deviceResultListDto.push(resultItem); }); const deviceProfileList: ListAllDeviceProfilesResponseDto = { totalCount: result.totalCount.toString(), @@ -302,11 +292,8 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService return deviceProfileMapped; } - mapToChirpstackDto( - deviceProfile: DeviceProfile, - data: CreateDeviceProfileDto | UpdateDeviceProfileDto, - isCreate?: boolean - ) { + mapToChirpstackDto(data: CreateDeviceProfileDto | UpdateDeviceProfileDto, isCreate?: boolean) { + const deviceProfile = new DeviceProfile(); deviceProfile.setName(data.deviceProfile.name); deviceProfile.setMacVersion(data.deviceProfile.macVersion); deviceProfile.setRegParamsRevision(data.deviceProfile.regParamsRevision); @@ -331,18 +318,18 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService ); isCreate ? deviceProfile.setTenantId(data.deviceProfile.organizationID) : {}; + + return deviceProfile; } public async getAdrAlgorithmsForChirpstack(): Promise { const result = await this.getAdrAlgorithms(); - const adrAlgoritmList: AdrAlgorithmDto[] = []; - result.getResultList().map(e => { - const resultItem: AdrAlgorithmDto = { + const adrAlgoritmList: AdrAlgorithmDto[] = result.getResultList().map(e => { + return { id: e.getId(), name: e.getName(), }; - adrAlgoritmList.push(resultItem); }); return { @@ -352,7 +339,7 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService async getAdrAlgorithms(): Promise { const metaData = this.makeMetadataHeader(); - const test: google_protobuf_empty_pb.Empty = new Empty() + const test: google_protobuf_empty_pb.Empty = new Empty(); const getPromise = new Promise((resolve, reject) => { this.deviceProfileClient.listAdrAlgorithms(test, metaData, (err: ServiceError, resp: any) => { if (err) { diff --git a/src/services/chirpstack/gateway-boostrapper.service.ts b/src/services/chirpstack/gateway-boostrapper.service.ts index c5097b54..7a0cb734 100644 --- a/src/services/chirpstack/gateway-boostrapper.service.ts +++ b/src/services/chirpstack/gateway-boostrapper.service.ts @@ -1,9 +1,8 @@ -import { ListAllGatewaysResponseGrpcDto } from "@dto/chirpstack/list-all-gateways.dto"; +import { ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways.dto"; import { GatewayStatusHistory } from "@entities/gateway-status-history.entity"; -import { Inject, OnApplicationBootstrap } from "@nestjs/common"; +import { Inject, InternalServerErrorException, Logger, OnApplicationBootstrap } from "@nestjs/common"; import { ChirpstackGatewayService } from "./chirpstack-gateway.service"; import { GatewayStatusHistoryService } from "./gateway-status-history.service"; -import { timestampToDate } from "@helpers/date.helper"; /** * Verify if any gateways exist on chirpstack and haven't been loaded into the database. @@ -16,6 +15,7 @@ export class GatewayBootstrapperService implements OnApplicationBootstrap { @Inject(ChirpstackGatewayService) private chirpstackGatewayService: ChirpstackGatewayService ) {} + private readonly logger = new Logger(GatewayBootstrapperService.name); async onApplicationBootstrap(): Promise { try { @@ -24,7 +24,8 @@ export class GatewayBootstrapperService implements OnApplicationBootstrap { const gateways = await chirpstackGatewaysPromise; await this.seedGatewayStatus(gateways, latestStatusHistories); } catch (e) { - throw e; + this.logger.error("Error in applicationBootstrap"); + throw new InternalServerErrorException(e); } } @@ -33,7 +34,7 @@ export class GatewayBootstrapperService implements OnApplicationBootstrap { * @param gateways All chirpstack gateways * @param statusHistories Existing status histories to check against */ - private async seedGatewayStatus(gateways: ListAllGatewaysResponseGrpcDto, statusHistories: GatewayStatusHistory[]) { + private async seedGatewayStatus(gateways: ListAllGatewaysResponseDto, statusHistories: GatewayStatusHistory[]) { const now = new Date(); const errorTime = new Date(); errorTime.setSeconds(errorTime.getSeconds() - 150); @@ -43,7 +44,7 @@ export class GatewayBootstrapperService implements OnApplicationBootstrap { if (!statusHistories.some(history => history.mac === gateway.gatewayId)) { // Best fit is to imitate the status logic from Chirpstack. if (gateway.lastSeenAt) { - const lastSeenDate = timestampToDate(gateway.lastSeenAt); + const lastSeenDate = gateway.lastSeenAt; const wasOnline = errorTime.getTime() < lastSeenDate.getTime(); diff --git a/src/services/chirpstack/gateway-status-history.service.ts b/src/services/chirpstack/gateway-status-history.service.ts index 448505dd..5638b016 100644 --- a/src/services/chirpstack/gateway-status-history.service.ts +++ b/src/services/chirpstack/gateway-status-history.service.ts @@ -10,7 +10,7 @@ import { InjectRepository } from "@nestjs/typeorm"; import { In, MoreThanOrEqual, Repository } from "typeorm"; import { ChirpstackGatewayService } from "./chirpstack-gateway.service"; import { nameof } from "@helpers/type-helper"; -import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; +import { GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto"; @Injectable() export class GatewayStatusHistoryService { @@ -56,7 +56,7 @@ export class GatewayStatusHistoryService { }; } - public async findOne(gateway: GatewayResponseGrpcDto, timeInterval: GatewayStatusInterval): Promise { + public async findOne(gateway: GatewayResponseDto, timeInterval: GatewayStatusInterval): Promise { const fromDate = gatewayStatusIntervalToDate(timeInterval); const statusHistoriesInPeriod = await this.gatewayStatusHistoryRepository.find({ @@ -125,7 +125,7 @@ export class GatewayStatusHistoryService { } private mapStatusHistoryToGateways( - gateways: GatewayResponseGrpcDto[], + gateways: GatewayResponseDto[], statusHistories: GatewayStatusHistory[] ): GatewayStatus[] { return gateways.map(gateway => { @@ -133,7 +133,7 @@ export class GatewayStatusHistoryService { }); } - private mapStatusHistoryToGateway(gateway: GatewayResponseGrpcDto, statusHistories: GatewayStatusHistory[]) { + private mapStatusHistoryToGateway(gateway: GatewayResponseDto, statusHistories: GatewayStatusHistory[]) { const statusTimestamps = statusHistories.reduce((res: GatewayStatus["statusTimestamps"], history) => { if (history.mac === gateway.gatewayId) { res.push({ diff --git a/src/services/chirpstack/generic-chirpstack-configuration.service.ts b/src/services/chirpstack/generic-chirpstack-configuration.service.ts index f553325e..f156f032 100644 --- a/src/services/chirpstack/generic-chirpstack-configuration.service.ts +++ b/src/services/chirpstack/generic-chirpstack-configuration.service.ts @@ -13,7 +13,7 @@ import { ListTenantsRequest, ListTenantsResponse } from "@chirpstack/chirpstack- import { ApplicationServiceClient } from "@chirpstack/chirpstack-api/api/application_grpc_pb"; import { ListApplicationsRequest, ListApplicationsResponse } from "@chirpstack/chirpstack-api/api/application_pb"; import { ChirpstackApplicationResponseDto } from "@dto/chirpstack/chirpstack-application-response.dto"; -import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; import { DeviceServiceClient } from "@chirpstack/chirpstack-api/api/device_grpc_pb"; import { GatewayServiceClient } from "@chirpstack/chirpstack-api/api/gateway_grpc_pb"; import { DeviceProfileServiceClient } from "@chirpstack/chirpstack-api/api/device_profile_grpc_pb"; @@ -29,6 +29,9 @@ export class GenericChirpstackConfigurationService { protected gatewayClient = new GatewayServiceClient(this.baseUrlGRPC, credentials.createInsecure()); protected deviceProfileClient = new DeviceProfileServiceClient(this.baseUrlGRPC, credentials.createInsecure()); protected multicastServiceClient = new MulticastGroupServiceClient(this.baseUrlGRPC, credentials.createInsecure()); + protected readonly ORG_ID_KEY = "internalOrganizationId"; + protected readonly UPDATED_BY_KEY = "os2iot-updated-by"; + protected readonly CREATED_BY_KEY = "os2iot-created-by"; makeMetadataHeader(): Metadata { const metadata = new Metadata(); @@ -36,9 +39,9 @@ export class GenericChirpstackConfigurationService { return metadata; } - async post(endpoint: string, client?: any, request?: any): Promise { + async post(endpoint: string, client?: any, request?: any): Promise { const metaData = this.makeMetadataHeader(); - const createPromise = new Promise((resolve, reject) => { + const createPromise = new Promise((resolve, reject) => { client.create(request, metaData, (err: ServiceError, resp: any) => { if (err) { reject(err); @@ -164,7 +167,7 @@ export class GenericChirpstackConfigurationService { }); return { totalCount: result.totalCount, - result: chirpstackApplicationResponseDto, + resultList: chirpstackApplicationResponseDto, }; } diff --git a/src/services/chirpstack/multicast.service.ts b/src/services/chirpstack/multicast.service.ts index 12cb50ac..c8a6def6 100644 --- a/src/services/chirpstack/multicast.service.ts +++ b/src/services/chirpstack/multicast.service.ts @@ -44,7 +44,7 @@ import { } from "@chirpstack/chirpstack-api/api/multicast_group_pb"; import { MulticastGroupServiceClient } from "@chirpstack/chirpstack-api/api/multicast_group_grpc_pb"; import { ServiceError } from "@grpc/grpc-js"; -import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; import { multicastGroup } from "@enum/multicast-type.enum"; @Injectable() export class MulticastService extends GenericChirpstackConfigurationService { @@ -158,7 +158,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { ); const req = new CreateMulticastGroupRequest(); req.setMulticastGroup(mappedChirpStackMulticast); - const result: PostReturnInterface = await this.post(this.multicastGroupUrl, this.multicastServiceClient, req); // This creates the multicast in chirpstack. Chirpstack returns an id as a string + const result: IdResponse = await this.post(this.multicastGroupUrl, this.multicastServiceClient, req); // This creates the multicast in chirpstack. Chirpstack returns an id as a string await this.addDevices(createMulticastDto, result); // iotDevices are added to multicast in a seperate endpoint. @@ -370,7 +370,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { } private handlePossibleError( - result: PostReturnInterface, + result: IdResponse, dto: CreateMulticastDto | UpdateMulticastDto | CreateChirpstackMulticastQueueItemDto ): void { if (!result.id) { @@ -409,7 +409,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { private async addDevices( multicastDto: CreateMulticastDto | UpdateMulticastDto, - chirpstackMulticastID: PostReturnInterface // the id returned from chirpstack when the multicast is created in chirpstack. + chirpstackMulticastID: IdResponse // the id returned from chirpstack when the multicast is created in chirpstack. ) { multicastDto.iotDevices.forEach(async device => { if (device.type === IoTDeviceType.LoRaWAN) { @@ -434,7 +434,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { request?: AddDeviceToMulticastGroupRequest ): Promise { const metaData = this.makeMetadataHeader(); - const createPromise = new Promise((resolve, reject) => { + const createPromise = new Promise((resolve, reject) => { client.addDevice(request, metaData, (err: ServiceError, resp: any) => { if (err) { reject(err); diff --git a/src/services/data-management/gateway-persistence.service.ts b/src/services/data-management/gateway-persistence.service.ts index 1cff17a6..d862db5e 100644 --- a/src/services/data-management/gateway-persistence.service.ts +++ b/src/services/data-management/gateway-persistence.service.ts @@ -36,29 +36,20 @@ export class GatewayPersistenceService extends AbstractKafkaConsumer { async rawRequestListener(payload: KafkaPayload): Promise { this.logger.debug(`RAW_GATEWAY_STATE: '${JSON.stringify(payload)}'`); const dto = payload.body as RawGatewayStateDto; - const messageState = (dto.rawPayload as unknown) as ChirpstackMQTTConnectionStateMessageDto; + const messageState = dto.rawPayload as unknown as ChirpstackMQTTConnectionStateMessageDto; const statusHistory = this.mapDtoToEntity(dto, messageState); await this.gatewayStatusHistoryRepository.save(statusHistory); - // Clean up old statuses - await this.deleteStatusHistoriesSinceLastHour( - statusHistory.timestamp, - dto.gatewayId - ); + // Clean up old statuses + await this.deleteStatusHistoriesSinceLastHour(statusHistory.timestamp, dto.gatewayId); await this.deleteOldStatusHistories(dto.gatewayId); } - private mapDtoToEntity( - dto: RawGatewayStateDto, - messageState: ChirpstackMQTTConnectionStateMessageDto - ) { + private mapDtoToEntity(dto: RawGatewayStateDto, messageState: ChirpstackMQTTConnectionStateMessageDto) { const statusHistory = new GatewayStatusHistory(); - dto.gatewayId statusHistory.mac = dto.gatewayId; - statusHistory.timestamp = dto.unixTimestamp - ? new Date(dto.unixTimestamp) - : new Date(); + statusHistory.timestamp = dto.unixTimestamp ? new Date(dto.unixTimestamp) : new Date(); statusHistory.wasOnline = !!messageState?.isOnline; return statusHistory; } @@ -69,10 +60,7 @@ export class GatewayPersistenceService extends AbstractKafkaConsumer { * @param latestMessageTime * @param gatewayId */ - private async deleteStatusHistoriesSinceLastHour( - latestMessageTime: Date, - gatewayId: string - ): Promise { + private async deleteStatusHistoriesSinceLastHour(latestMessageTime: Date, gatewayId: string): Promise { const lastHour = subtractHours(latestMessageTime); // Find the oldest items since the last hour const oldestToDelete = await this.gatewayStatusHistoryRepository.find({ @@ -90,9 +78,7 @@ export class GatewayPersistenceService extends AbstractKafkaConsumer { return; } - const result = await this.gatewayStatusHistoryRepository.delete( - oldestToDelete.map(old => old.id) - ); + const result = await this.gatewayStatusHistoryRepository.delete(oldestToDelete.map(old => old.id)); this.logger.debug(`Deleted: ${result.affected} rows from gateway_status_history`); } @@ -116,9 +102,7 @@ export class GatewayPersistenceService extends AbstractKafkaConsumer { return; } - const result = await this.gatewayStatusHistoryRepository.delete( - oldestToDelete.map(old => old.id) - ); + const result = await this.gatewayStatusHistoryRepository.delete(oldestToDelete.map(old => old.id)); this.logger.debug(`Deleted: ${result.affected} rows from gateway_status_history`); } diff --git a/src/services/data-management/search.service.ts b/src/services/data-management/search.service.ts index fa097e75..b1d894f9 100644 --- a/src/services/data-management/search.service.ts +++ b/src/services/data-management/search.service.ts @@ -1,6 +1,6 @@ import { GatewayServiceClient } from "@chirpstack/chirpstack-api/api/gateway_grpc_pb"; import { ListGatewaysRequest } from "@chirpstack/chirpstack-api/api/gateway_pb"; -import { ListAllGatewaysResponseGrpcDto } from "@dto/chirpstack/list-all-gateways.dto"; +import { ListAllGatewaysResponseChirpstackDto, ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways.dto"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; import { ListAllSearchResultsResponseDto } from "@dto/list-all-search-results-response.dto"; import { SearchResultDto, SearchResultType } from "@dto/search-result.dto"; @@ -97,7 +97,8 @@ export class SearchService { const req = new ListGatewaysRequest(); req.setSearch(escapedQuery); - const gateways = await this.gatewayService.getAllWithPagination( + //TODO:: The return type might be changed. + const gateways = await this.gatewayService.getAllWithPagination( `gateways?search=${escapedQuery}`, 1000, 0, @@ -114,7 +115,7 @@ export class SearchService { const detailedInfo = await this.gatewayService.getOne(x.gatewayId); - resultDto.organizationId = detailedInfo.gateway.internalOrganizationId; + resultDto.organizationId = detailedInfo.gateway.organizationId; return resultDto; }) ); diff --git a/src/services/device-management/application.service.ts b/src/services/device-management/application.service.ts index dd7a0b5b..acf6b45c 100644 --- a/src/services/device-management/application.service.ts +++ b/src/services/device-management/application.service.ts @@ -204,11 +204,11 @@ export class ApplicationService { } private async matchWithChirpstackStatusData(app: Application) { - const allFromChirpstack = await this.chirpstackDeviceService.getAllDevicesStatus(app); + const chirpstackDevices = await this.chirpstackDeviceService.getAllDevicesStatus(app); app.iotDevices.forEach(x => { if (x.type === IoTDeviceType.LoRaWAN) { const loraDevice = x as LoRaWANDeviceWithChirpstackDataDto; - const matchingDevice = allFromChirpstack.result.find(cs => cs.devEUI === loraDevice.deviceEUI); + const matchingDevice = chirpstackDevices.result.find(cs => cs.devEUI === loraDevice.deviceEUI); if (matchingDevice) { loraDevice.lorawanSettings = new CreateLoRaWANSettingsDto(); loraDevice.lorawanSettings.deviceStatusBattery = matchingDevice.deviceStatusBattery; @@ -236,8 +236,9 @@ export class ApplicationService { mappedApplication.updatedBy = userId; try { - const chirpId = await this.chirpstackApplicationService.createApplication(createApplicationDto); - mappedApplication.chirpstackId = chirpId.id; + mappedApplication.chirpstackId = await this.chirpstackApplicationService.createChirpstackApplication( + { application: { description: createApplicationDto.description, name: createApplicationDto.name } } + ); const app = await this.applicationRepository.save(mappedApplication); await this.permissionService.autoAddPermissionsToApplication(app); diff --git a/src/services/device-management/iot-device-downlink.service.ts b/src/services/device-management/iot-device-downlink.service.ts index 3dc230f3..355062ab 100644 --- a/src/services/device-management/iot-device-downlink.service.ts +++ b/src/services/device-management/iot-device-downlink.service.ts @@ -13,7 +13,7 @@ import { CreateChirpstackDeviceQueueItemResponse, } from "@dto/chirpstack/create-chirpstack-device-queue-item.dto"; import { ChirpstackDeviceService } from "@services/chirpstack/chirpstack-device.service"; -import { PostReturnInterface } from "@interfaces/chirpstack-post-return.interface"; +import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; @Injectable() export class IoTDeviceDownlinkService { @@ -26,7 +26,7 @@ export class IoTDeviceDownlinkService { private readonly logger = new Logger(IoTDeviceDownlinkService.name); private readonly SIGFOX_DOWNLINK_LENGTH_EXACT = 16; - async createDownlink(dto: CreateIoTDeviceDownlinkDto, device: IoTDevice): Promise { + async createDownlink(dto: CreateIoTDeviceDownlinkDto, device: IoTDevice): Promise { if (device.type === IoTDeviceType.LoRaWAN) { const cast = device; return await this.createLoraDownlink(dto, cast); @@ -57,10 +57,7 @@ export class IoTDeviceDownlinkService { } } - private async createLoraDownlink( - dto: CreateIoTDeviceDownlinkDto, - cast: LoRaWANDevice - ): Promise { + private async createLoraDownlink(dto: CreateIoTDeviceDownlinkDto, cast: LoRaWANDevice): Promise { const csDto: CreateChirpstackDeviceQueueItemDto = { deviceQueueItem: { fPort: dto.port, diff --git a/src/services/device-management/iot-device.service.ts b/src/services/device-management/iot-device.service.ts index 0af3eb45..1e3c273a 100644 --- a/src/services/device-management/iot-device.service.ts +++ b/src/services/device-management/iot-device.service.ts @@ -70,6 +70,7 @@ import { CsvGeneratorService } from "@services/csv-generator.service"; import * as fs from "fs"; import { caCertPath } from "@resources/resource-paths"; import { DeviceProfileService } from "@services/chirpstack/device-profile.service"; +import { ApplicationChirpstackService } from "@services/chirpstack/chirpstack-application.service"; type IoTDeviceOrSpecialized = | IoTDevice @@ -95,6 +96,7 @@ export class IoTDeviceService { private entityManager: EntityManager, private applicationService: ApplicationService, private chirpstackDeviceService: ChirpstackDeviceService, + private applicationChirpstackService: ApplicationChirpstackService, private sigfoxApiDeviceService: SigFoxApiDeviceService, private sigfoxApiDeviceTypeService: SigFoxApiDeviceTypeService, private sigfoxGroupService: SigFoxGroupService, @@ -937,18 +939,18 @@ export class IoTDeviceService { dto.name ); - const applicationId = await this.chirpstackDeviceService.findOrCreateDefaultApplication( + const applicationId = await this.applicationChirpstackService.findOrCreateDefaultApplication( loraApplications, lorawanDevice ); lorawanDevice.chirpstackApplicationId = applicationId; chirpstackDeviceDto.device.applicationID = applicationId; // Create or update the LoRa device against Chirpstack API - const response = await this.chirpstackDeviceService.createOrUpdateDevice( + const success = await this.chirpstackDeviceService.createOrUpdateDevice( chirpstackDeviceDto, lorawanDeviceEuis ); - if (response) { + if (success) { lorawanDeviceEuis.push(chirpstackDeviceDto.device); await this.doActivation(dto, isUpdate); lorawanDevice.OTAAapplicationKey = dto.lorawanSettings.OTAAapplicationKey; @@ -976,7 +978,7 @@ export class IoTDeviceService { // OTAA Activate if key is provided await this.doActivationByOTAA(dto, isUpdate); } else if (dto.lorawanSettings.activationType === ActivationType.ABP) { - await this.doActivationByABP(dto, isUpdate); + await this.doActivationByABP(dto); } } @@ -992,7 +994,7 @@ export class IoTDeviceService { } } - private async doActivationByABP(dto: CreateIoTDeviceDto, isUpdate: boolean) { + private async doActivationByABP(dto: CreateIoTDeviceDto) { if ( dto.lorawanSettings.devAddr && dto.lorawanSettings.fCntUp != null && diff --git a/src/services/device-management/lorawan-device-database-enrich-job.ts b/src/services/device-management/lorawan-device-database-enrich-job.ts index 0e2e14c1..4e012d46 100644 --- a/src/services/device-management/lorawan-device-database-enrich-job.ts +++ b/src/services/device-management/lorawan-device-database-enrich-job.ts @@ -4,19 +4,15 @@ import { ChirpstackDeviceService } from "@services/chirpstack/chirpstack-device. import { IoTDeviceService } from "@services/device-management/iot-device.service"; import { ChirpstackGatewayService } from "@services/chirpstack/chirpstack-gateway.service"; import * as BluebirdPromise from "bluebird"; -import { ListAllGatewaysResponseGrpcDto } from "@dto/chirpstack/list-all-gateways.dto"; import { OrganizationService } from "@services/user-management/organization.service"; import { InjectRepository } from "@nestjs/typeorm"; import { Gateway } from "@entities/gateway.entity"; import { Repository } from "typeorm"; import { timestampToDate } from "@helpers/date.helper"; import { - ListGatewaysResponse, - ListGatewaysRequest, GetGatewayRequest, GetGatewayResponse, } from "@chirpstack/chirpstack-api/api/gateway_pb"; -import { GatewayResponseGrpcDto } from "@dto/chirpstack/gateway-response.dto"; import { GatewayServiceClient } from "@chirpstack/chirpstack-api/api/gateway_grpc_pb"; import { credentials } from "@grpc/grpc-js"; @@ -39,7 +35,7 @@ export class LorawanDeviceDatabaseEnrichJob { async fetchStatusForGateway() { // Select all gateways from our database and chirpstack (Cheaper than individual calls) const gateways = await this.gatewayService.getAll(); - const responseList = await this.getAllGateways(); + const chirpstackDevices = await this.gatewayService.getAllGatewaysFromChirpstack(); // Setup batched fetching of status (Only for today) await BluebirdPromise.all( @@ -59,7 +55,7 @@ export class LorawanDeviceDatabaseEnrichJob { ); // Save that to our database const stats = statsToday[0]; - const chirpstackGateway = responseList.resultList.find(g => g.gatewayId === gateway.gatewayId); + const chirpstackGateway = chirpstackDevices.resultList.find(g => g.gatewayId === gateway.gatewayId); await this.gatewayService.updateGatewayStats( gateway.gatewayId, @@ -105,10 +101,10 @@ export class LorawanDeviceDatabaseEnrichJob { // This is run once on startup and will create any gateways that exist in chirpstack but not our database @Timeout(10000) async importChirpstackGateways() { - const responseList = await this.getAllGateways(); + const chirpstackDevices = await this.gatewayService.getAllGatewaysFromChirpstack(); const dbGateways = await this.gatewayService.getAll(); // Filter for gateways not existing in our database - const unknownGateways = responseList.resultList.filter( + const unknownGateways = chirpstackDevices.resultList.filter( g => dbGateways.resultList.findIndex(dbGateway => dbGateway.gatewayId === g.gatewayId) === -1 ); await BluebirdPromise.all( @@ -124,9 +120,9 @@ export class LorawanDeviceDatabaseEnrichJob { this.gatewayClient, req ); - const csGw = gwResponse.getGateway(); - const organizationId = +csGw.getTagsMap().get("internalOrganizationId"); - const gateway = this.gatewayService.mapCsGwToGateway(csGw, gwResponse); + const chirpstackGateway = gwResponse.getGateway(); + const organizationId = +chirpstackGateway.getTagsMap().get("internalOrganizationId"); + const gateway = this.gatewayService.mapChirpstackGatewayToDatabaseGateway(chirpstackGateway, gwResponse); gateway.organization = await this.organizationService.findById(organizationId); await this.gatewayRepository.save(gateway); } catch (err) { @@ -139,35 +135,4 @@ export class LorawanDeviceDatabaseEnrichJob { ) ); } - async getAllGateways(): Promise { - const limit = 1000; - const listReq = new ListGatewaysRequest(); - // Get all chirpstack gateways - const chirpStackGateways = await this.gatewayService.getAllWithPagination( - "gateways", - limit, - 0, - this.gatewayClient, - listReq - ); - - const responseItem: GatewayResponseGrpcDto[] = []; - chirpStackGateways.resultList.map(e => { - const resultItem: GatewayResponseGrpcDto = { - gatewayId: e.gatewayId, - name: e.name, - location: e.location, - description: e.description, - createdAt: e.createdAt ?? undefined, - updatedAt: e.updatedAt ?? undefined, - lastSeenAt: e.lastSeenAt ?? undefined, - }; - responseItem.push(resultItem); - }); - const responseList: ListAllGatewaysResponseGrpcDto = { - totalCount: chirpStackGateways.totalCount, - resultList: responseItem, - }; - return responseList; - } } From d2cecdb88f807b72a9ae36463fb8c9db497bd540 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Thu, 14 Dec 2023 14:50:05 +0100 Subject: [PATCH 16/24] cleanup --- .../chirpstack-application-response.dto.ts | 2 +- .../chirpstack-application.service.ts | 5 ++-- .../chirpstack/chirpstack-device.service.ts | 25 ------------------- .../chirpstack/chirpstack-gateway.service.ts | 1 - 4 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/entities/dto/chirpstack/chirpstack-application-response.dto.ts b/src/entities/dto/chirpstack/chirpstack-application-response.dto.ts index cfb77375..e80434c5 100644 --- a/src/entities/dto/chirpstack/chirpstack-application-response.dto.ts +++ b/src/entities/dto/chirpstack/chirpstack-application-response.dto.ts @@ -2,5 +2,5 @@ export class ChirpstackApplicationResponseDto { id: string; name: string; description: string; - tenantId: string; + tenantId?: string; } diff --git a/src/services/chirpstack/chirpstack-application.service.ts b/src/services/chirpstack/chirpstack-application.service.ts index 7b25af02..4365a189 100644 --- a/src/services/chirpstack/chirpstack-application.service.ts +++ b/src/services/chirpstack/chirpstack-application.service.ts @@ -40,7 +40,8 @@ export class ApplicationChirpstackService extends GenericChirpstackConfiguration `applications?limit=100&organizationID=${organizationID}`, 100, undefined, - this.applicationServiceClient + this.applicationServiceClient, + req )); // if application exist use it @@ -79,7 +80,7 @@ export class ApplicationChirpstackService extends GenericChirpstackConfiguration public async createChirpstackApplication(dto: CreateChirpstackApplicationDto): Promise { const req = new CreateApplicationRequest(); const application = new Application(); - application.setDescription(dto.application.description); + application.setDescription(dto.application.description ? dto.application.description: this.DEFAULT_DESCRIPTION); application.setName(dto.application.name); application.setTenantId(await this.getDefaultOrganizationId()); diff --git a/src/services/chirpstack/chirpstack-device.service.ts b/src/services/chirpstack/chirpstack-device.service.ts index 2baab699..67478f00 100644 --- a/src/services/chirpstack/chirpstack-device.service.ts +++ b/src/services/chirpstack/chirpstack-device.service.ts @@ -330,31 +330,6 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi device.setSkipFcntCheck(dto.device.skipFCntCheck); return device; } - private async getChirpstackApplication(id: string): Promise { - const req = new GetApplicationRequest(); - req.setId(id); - try { - const chirpstackApplicationResponse = await this.get( - `applications/${id}`, - this.applicationServiceClient, - req - ); - const chirpstackApplication = chirpstackApplicationResponse.getApplication(); - const applicationDto = new ChirpstackApplicationResponseDto(); - - applicationDto.name = chirpstackApplication.getName(); - applicationDto.description = chirpstackApplication.getDescription(); - applicationDto.id = chirpstackApplication.getId(); - applicationDto.tenantId = chirpstackApplication.getTenantId(); - - const returnDto = new ChirpstackSingleApplicationResponseDto(); - returnDto.application = applicationDto; - - return returnDto; - } catch (err) { - throw new BadRequestException(ErrorCodes.CouldntGetApplications); - } - } public async getChirpstackDevice(id: string): Promise { try { diff --git a/src/services/chirpstack/chirpstack-gateway.service.ts b/src/services/chirpstack/chirpstack-gateway.service.ts index c5bc2e6e..aa21fb9f 100644 --- a/src/services/chirpstack/chirpstack-gateway.service.ts +++ b/src/services/chirpstack/chirpstack-gateway.service.ts @@ -366,7 +366,6 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ return gateway; } - //TODO:: Check that it works public mapChirpstackGatewayToDatabaseGateway(chirpstackGateway: ChirpstackGateway, gwResponse: GetGatewayResponse) { const gateway = new DbGateway(); gateway.name = chirpstackGateway.getName(); From b2f62c41ef22968015199edbbb9b331e056fc68c Mon Sep 17 00:00:00 2001 From: August Andersen Date: Thu, 14 Dec 2023 15:21:49 +0100 Subject: [PATCH 17/24] added bluebird --- package-lock.json | 18 +++++++++--------- .../chirpstack/device-profile.service.ts | 19 ++++++++++++------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5d2d25b2..400446ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10343,10 +10343,10 @@ "@babel/helpers": "^7.23.6", "@babel/parser": "^7.23.6", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", + "@babel/traverse": "^7.23.6", "@babel/types": "^7.23.6", "convert-source-map": "^2.0.0", - "debug": "^4.3.4", + "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" @@ -10504,7 +10504,7 @@ "dev": true, "requires": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", + "@babel/traverse": "^7.23.6", "@babel/types": "^7.23.6" } }, @@ -10742,7 +10742,7 @@ "@babel/helper-split-export-declaration": "^7.22.6", "@babel/parser": "^7.23.6", "@babel/types": "^7.23.6", - "debug": "^4.3.4", + "debug": "^4.3.1", "globals": "^11.1.0" }, "dependencies": { @@ -10832,7 +10832,7 @@ "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.3.4", + "debug": "^4.3.2", "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", @@ -10896,7 +10896,7 @@ "dev": true, "requires": { "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.3.4", + "debug": "^4.1.1", "minimatch": "^3.0.5" } }, @@ -12401,7 +12401,7 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "requires": { - "debug": "^4.3.4" + "debug": "4" } }, "ajv": { @@ -12979,7 +12979,7 @@ "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", - "y18n": "6.0.0-alpha.0", + "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, @@ -14510,7 +14510,7 @@ "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "requires": { - "debug": "^4.3.4", + "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" }, diff --git a/src/services/chirpstack/device-profile.service.ts b/src/services/chirpstack/device-profile.service.ts index 08d008af..c9c53dba 100644 --- a/src/services/chirpstack/device-profile.service.ts +++ b/src/services/chirpstack/device-profile.service.ts @@ -36,6 +36,7 @@ import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; import { DeviceListItem, ListDevicesRequest, ListDevicesResponse } from "@chirpstack/chirpstack-api/api/device_pb"; import { ListApplicationsRequest, ListApplicationsResponse } from "@chirpstack/chirpstack-api/api/application_pb"; import * as google_protobuf_empty_pb from "google-protobuf/google/protobuf/empty_pb"; +import * as BluebirdPromise from "bluebird"; @Injectable() export class DeviceProfileService extends GenericChirpstackConfigurationService { @@ -199,13 +200,17 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService result: deviceResultListDto, }; - await Promise.all( - deviceProfileList.result.map(async x => { - const dp = await this.findOneDeviceProfileById(x.id); - x.internalOrganizationId = +dp.deviceProfile.internalOrganizationId; - x.createdBy = +dp.deviceProfile.createdBy; - x.updatedBy = +dp.deviceProfile.updatedBy; - }) + await BluebirdPromise.all( + BluebirdPromise.map( + deviceProfileList.result, + async x => { + const dp = await this.findOneDeviceProfileById(x.id); + x.internalOrganizationId = +dp.deviceProfile.internalOrganizationId; + x.createdBy = +dp.deviceProfile.createdBy; + x.updatedBy = +dp.deviceProfile.updatedBy; + }, + { concurrency: 20 } + ) ); return deviceProfileList; From 183dbb13005c1159e6687ac77fe0044f3555c0de Mon Sep 17 00:00:00 2001 From: August Andersen Date: Thu, 14 Dec 2023 22:44:13 +0100 Subject: [PATCH 18/24] PR updates. --- .../admin-controller/multicast.controller.ts | 2 +- src/entities/enum/error-codes.enum.ts | 3 +- .../chirpstack-application.service.ts | 4 +- .../chirpstack/chirpstack-device.service.ts | 46 +------ .../chirpstack/chirpstack-gateway.service.ts | 7 +- .../chirpstack/device-profile.service.ts | 55 +++----- ...eneric-chirpstack-configuration.service.ts | 52 ++++---- src/services/chirpstack/multicast.service.ts | 121 ++++-------------- .../data-management/search.service.ts | 24 ++-- .../device-management/iot-device.service.ts | 4 +- 10 files changed, 99 insertions(+), 219 deletions(-) diff --git a/src/controllers/admin-controller/multicast.controller.ts b/src/controllers/admin-controller/multicast.controller.ts index e6bf7d19..dd46fe7c 100644 --- a/src/controllers/admin-controller/multicast.controller.ts +++ b/src/controllers/admin-controller/multicast.controller.ts @@ -196,7 +196,7 @@ export class MulticastController { try { const multicast = await this.multicastService.findOne(id); checkIfUserHasAccessToApplication(req, multicast.application.id, ApplicationAccessScope.Write); - const result = await this.multicastService.multicastDelete(id, multicast); + const result = await this.multicastService.deleteMulticast(id, multicast); if (result.affected === 0) { throw new NotFoundException(ErrorCodes.IdDoesNotExists); diff --git a/src/entities/enum/error-codes.enum.ts b/src/entities/enum/error-codes.enum.ts index d1cca2d1..1d47ee19 100644 --- a/src/entities/enum/error-codes.enum.ts +++ b/src/entities/enum/error-codes.enum.ts @@ -48,5 +48,6 @@ export enum ErrorCodes { SendMailError = "MESSAGE.SEND-MAIL-ERROR", UserDoesNotExistInArray = "MESSAGE.USER-DOES-NOT-EXIST", UserAlreadyInPermission = "MESSAGE.USER-ALREADY-IN-PERMISSION", - CouldntGetApplications= "MESSAGE.COULD-NOT-GET-CS-APPLICATIONS" + CouldntGetApplications = "MESSAGE.COULD-NOT-GET-CS-APPLICATIONS", + DifferentServiceProfile = "MESSAGE.DIFFERENT-SERVICE-PROFILE", } diff --git a/src/services/chirpstack/chirpstack-application.service.ts b/src/services/chirpstack/chirpstack-application.service.ts index 4365a189..dfd0c40b 100644 --- a/src/services/chirpstack/chirpstack-application.service.ts +++ b/src/services/chirpstack/chirpstack-application.service.ts @@ -38,10 +38,10 @@ export class ApplicationChirpstackService extends GenericChirpstackConfiguration applications ?? (await this.getAllWithPagination( `applications?limit=100&organizationID=${organizationID}`, + this.applicationServiceClient, + req, 100, undefined, - this.applicationServiceClient, - req )); // if application exist use it diff --git a/src/services/chirpstack/chirpstack-device.service.ts b/src/services/chirpstack/chirpstack-device.service.ts index 67478f00..89b8f940 100644 --- a/src/services/chirpstack/chirpstack-device.service.ts +++ b/src/services/chirpstack/chirpstack-device.service.ts @@ -2,9 +2,7 @@ import { BadRequestException, Injectable, InternalServerErrorException, Logger } import { ChirpstackDeviceActivationContentsDto } from "@dto/chirpstack/chirpstack-device-activation-response.dto"; import { ChirpstackDeviceContentsDto } from "@dto/chirpstack/chirpstack-device-contents.dto"; import { ChirpstackDeviceKeysContentDto } from "@dto/chirpstack/chirpstack-device-keys-response.dto"; -import { ChirpstackSingleApplicationResponseDto } from "@dto/chirpstack/chirpstack-single-application-response.dto"; import { CreateChirpstackDeviceDto } from "@dto/chirpstack/create-chirpstack-device.dto"; -import { ListAllDevicesResponseDto } from "@dto/chirpstack/list-all-devices-response.dto"; import { CreateLoRaWANSettingsDto } from "@dto/create-lorawan-settings.dto"; import { GenericChirpstackConfigurationService } from "@services/chirpstack/generic-chirpstack-configuration.service"; import { CreateChirpstackDeviceQueueItemDto } from "@dto/chirpstack/create-chirpstack-device-queue-item.dto"; @@ -21,13 +19,11 @@ import { IoTDevice } from "@entities/iot-device.entity"; import { LoRaWANDeviceWithChirpstackDataDto } from "@dto/lorawan-device-with-chirpstack-data.dto"; import { ActivationType } from "@enum/lorawan-activation-type.enum"; import { ChirpstackDeviceId } from "@dto/chirpstack/chirpstack-device-id.dto"; -import { ChirpstackApplicationResponseDto } from "@dto/chirpstack/chirpstack-application-response.dto"; import { LoRaWANStatsElementDto, LoRaWANStatsResponseDto } from "@dto/chirpstack/device/lorawan-stats.response.dto"; import { ConfigService } from "@nestjs/config"; import { DeviceProfileService } from "@services/chirpstack/device-profile.service"; import { ServiceError } from "@grpc/grpc-js"; -import { GetApplicationRequest, GetApplicationResponse } from "@chirpstack/chirpstack-api/api/application_pb"; import { ActivateDeviceRequest, CreateDeviceKeysRequest, @@ -198,13 +194,13 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi req.setApplicationId(application.chirpstackId); const devices = await this.getAllWithPagination( `devices`, - 10000, - 0, this.deviceServiceClient, - req + req, + 10000, + 0 ); - const responseDevvice: ChirpstackDeviceResponseContents[] = devices.resultList.map(e => { + const responseDevice: ChirpstackDeviceResponseContents[] = devices.resultList.map(e => { return { devEUI: e.devEui, name: e.name, @@ -219,7 +215,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi }); return { totalCount: devices.totalCount.toString(), - result: responseDevvice, + result: responseDevice, }; } @@ -455,8 +451,7 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi deviceEUI: string, chirpstackIds: ChirpstackDeviceId[] = null ): Promise { - const devices = !chirpstackIds ? await this.getAllChirpstackDevices() : chirpstackIds; - const alreadyExists = devices.some(x => x.devEUI.toLowerCase() === deviceEUI.toLowerCase()); + const alreadyExists = chirpstackIds.some(x => x.devEUI.toLowerCase() === deviceEUI.toLowerCase()); return alreadyExists; } @@ -555,35 +550,6 @@ export class ChirpstackDeviceService extends GenericChirpstackConfigurationServi }); }; - //TODO:: FIX THIS! - private async getAllChirpstackDevices(): Promise { - const req = new ListDevicesRequest(); - - const devices = await this.getAllWithPagination( - `devices`, - 1000, - 0, - this.deviceServiceClient, - req - ); - - const responseDevice: ChirpstackDeviceResponseContents[] = devices.resultList.map(e => { - return { - devEUI: e.devEui, - name: e.name, - description: e.description, - lastSeenAt: e.lastSeenAt ? timestampToDate(e.lastSeenAt) : undefined, - deviceStatusBattery: e.deviceStatus?.batteryLevel, - deviceStatusMargin: e.deviceStatus?.margin, - deviceStatusExternalPowerSource: e.deviceStatus?.externalPowerSource, - deviceProfileID: e.deviceProfileId, - deviceProfileName: e.deviceProfileName, - }; - }); - - return responseDevice; - } - private async getKeys(request: GetDeviceKeysRequest): Promise { return await this.makeRequest( request, diff --git a/src/services/chirpstack/chirpstack-gateway.service.ts b/src/services/chirpstack/chirpstack-gateway.service.ts index aa21fb9f..e91747de 100644 --- a/src/services/chirpstack/chirpstack-gateway.service.ts +++ b/src/services/chirpstack/chirpstack-gateway.service.ts @@ -207,6 +207,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ } } + //TODO: This could be moved to a helper function in the future, since it has a lot of similarities with metrics from chirpstack devices. private mapPackets(metrics: GetGatewayMetricsResponse) { const gatewayResponseDto: GatewayStatsElementDto[] = []; const packetCounts: { [timestamp: string]: { rx: number; tx: number } } = {}; @@ -432,10 +433,10 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ // Get all chirpstack gateways const chirpStackGateways = await this.getAllWithPagination( "gateways", - limit, - 0, this.gatewayClient, - listReq + listReq, + limit, + 0 ); const responseItem: GatewayResponseChirpstackDto[] = []; diff --git a/src/services/chirpstack/device-profile.service.ts b/src/services/chirpstack/device-profile.service.ts index c9c53dba..d7be9fd2 100644 --- a/src/services/chirpstack/device-profile.service.ts +++ b/src/services/chirpstack/device-profile.service.ts @@ -85,9 +85,19 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService const deviceProfile = this.mapToChirpstackDto(data); const request = new UpdateDeviceProfileRequest(); - data.deviceProfile.tags = await this.updateTags(id, req); data.deviceProfile = await this.updateDto(data.deviceProfile); + //Have to set these everytime, otherwise they will be erased. + deviceProfile.getTagsMap().set(this.ORG_ID_KEY, data.deviceProfile.internalOrganizationId.toString()); + deviceProfile.getTagsMap().set(this.UPDATED_BY_KEY, data.deviceProfile.updatedBy.toString()); + deviceProfile.getTagsMap().set(this.CREATED_BY_KEY, data.deviceProfile.createdBy.toString()); + + checkIfUserHasAccessToOrganization( + req, + data.deviceProfile.internalOrganizationId, + OrganizationAccessScope.ApplicationWrite + ); + request.setDeviceProfile(deviceProfile); return await this.put("device-profiles", this.deviceProfileClient, request); } @@ -99,31 +109,6 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService .some(x => x.name.toLocaleLowerCase() == name.toLocaleLowerCase()); } - private async updateTags(deviceProfileId: string, req: AuthenticatedRequest): Promise<{ [id: string]: string }> { - const request = new GetDeviceProfileRequest(); - const result = await this.getOneById( - "device-profiles", - deviceProfileId, - this.deviceProfileClient, - request - ); - const tags = result.getDeviceProfile().getTagsMap(); - tags.set(this.UPDATED_BY_KEY, req.user.userId.toString()); - if (result.getDeviceProfile().getTagsMap().get(this.ORG_ID_KEY) != null) { - checkIfUserHasAccessToOrganization( - req, - +result.getDeviceProfile().getTagsMap().get(this.ORG_ID_KEY), - OrganizationAccessScope.ApplicationWrite - ); - } - const tagsObject: { [id: string]: string } = {}; - tags.forEach((value, key) => { - tagsObject[key] = value; - }); - - return tagsObject; - } - public async deleteDeviceProfile(id: string, req: AuthenticatedRequest): Promise { const getReq = new GetDeviceProfileRequest(); const result = await this.getOneById( @@ -139,10 +124,10 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService const applications = await this.getAllWithPagination( "devices", - 1000, - 0, this.applicationServiceClient, - listAppReq + listAppReq, + 1000, + 0 ); let devices: DeviceListItem.AsObject[] = []; @@ -150,10 +135,10 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService listReq.setApplicationId(applications.resultList[index].id); const devicesForApp = await this.getAllWithPagination( "devices", - 10000, - 0, this.deviceServiceClient, - listReq + listReq, + 10000, + 0 ); devices = devices.concat(devicesForApp.resultList); } @@ -181,10 +166,10 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService const result = await this.getAllWithPagination( "device-profiles", - limit, - offset, this.deviceProfileClient, - req + req, + limit, + offset ); const deviceResultListDto: DeviceProfileListDto[] = result.resultList.map(e => { diff --git a/src/services/chirpstack/generic-chirpstack-configuration.service.ts b/src/services/chirpstack/generic-chirpstack-configuration.service.ts index f156f032..422a0c60 100644 --- a/src/services/chirpstack/generic-chirpstack-configuration.service.ts +++ b/src/services/chirpstack/generic-chirpstack-configuration.service.ts @@ -39,14 +39,14 @@ export class GenericChirpstackConfigurationService { return metadata; } - async post(endpoint: string, client?: any, request?: any): Promise { + async post(logName: string, client: any, request: any): Promise { const metaData = this.makeMetadataHeader(); const createPromise = new Promise((resolve, reject) => { client.create(request, metaData, (err: ServiceError, resp: any) => { if (err) { reject(err); } else { - this.innerLogger.debug(`post:${endpoint} success`); + this.innerLogger.debug(`post:${logName} success`); resolve(resp.toObject()); } }); @@ -54,18 +54,18 @@ export class GenericChirpstackConfigurationService { try { return await createPromise; } catch (err) { - this.innerLogger.error(`POST ${endpoint} got error: ${err}`); + this.innerLogger.error(`POST ${logName} got error: ${err}`); throw new BadRequestException(); } } - async put(endpoint: string, client?: any, request?: any): Promise { + async put(logName: string, client: any, request: any): Promise { const metaData = this.makeMetadataHeader(); const updatePromise = new Promise((resolve, reject) => { client.update(request, metaData, (err: ServiceError, resp: any) => { if (err) { reject(err); } else { - this.innerLogger.debug(`update :${endpoint} success`); + this.innerLogger.debug(`update :${logName} success`); resolve(resp); } }); @@ -74,12 +74,12 @@ export class GenericChirpstackConfigurationService { await updatePromise; return; } catch (err) { - this.innerLogger.error(`UPDATE ${endpoint} got error: ${err}`); + this.innerLogger.error(`UPDATE ${logName} got error: ${err}`); throw new BadRequestException(); } } - async getOneById(endpoint: string, id: string, client?: any, request?: any): Promise { + async getOneById(logName: string, id: string, client: any, request: any): Promise { const metaData = this.makeMetadataHeader(); request.setId(id); const getPromise = new Promise((resolve, reject) => { @@ -87,7 +87,7 @@ export class GenericChirpstackConfigurationService { if (err) { reject(err); } else { - this.innerLogger.debug(`get from:${endpoint} success`); + this.innerLogger.debug(`get from:${logName} success`); resolve(resp); } }); @@ -95,12 +95,12 @@ export class GenericChirpstackConfigurationService { try { return await getPromise; } catch (err) { - this.innerLogger.error(`GET ${endpoint} got error: ${err}`); + this.innerLogger.error(`GET ${logName} got error: ${err}`); throw new NotFoundException(); } } - async delete(endpoint: string, client?: any, request?: any): Promise { + async delete(logName: string, client: any, request: any): Promise { //MAYBE return boolean of result (succes vs failure) if (client) { const metaData = this.makeMetadataHeader(); @@ -109,7 +109,7 @@ export class GenericChirpstackConfigurationService { if (err) { reject(err); } else { - this.innerLogger.debug(`delete :${endpoint} success`); + this.innerLogger.debug(`delete :${logName} success`); resolve(resp); } }); @@ -118,20 +118,20 @@ export class GenericChirpstackConfigurationService { await deletePromise; return; } catch (err) { - this.innerLogger.error(`DELETE ${endpoint} got error: ${err}`); + this.innerLogger.error(`DELETE ${logName} got error: ${err}`); throw new BadRequestException(); } } } - async get(endpoint: string, client?: any, request?: any): Promise { + async get(logName: string, client: any, request: any): Promise { const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.get(request, metaData, (err: ServiceError, resp: any) => { if (err) { reject(err); } else { - this.innerLogger.debug(`get from:${endpoint} success`); + this.innerLogger.debug(`get from:${logName} success`); resolve(resp); } }); @@ -139,7 +139,7 @@ export class GenericChirpstackConfigurationService { try { return await getPromise; } catch (err) { - this.innerLogger.error(`GET ${endpoint} got error: ${err}`); + this.innerLogger.error(`GET ${logName} got error: ${err}`); throw new NotFoundException(); } } @@ -150,10 +150,10 @@ export class GenericChirpstackConfigurationService { const result = await this.getAllWithPagination( `applications?limit=100&organizationID=${tenantID}`, - 100, - undefined, this.applicationServiceClient, - req + req, + 100, + undefined ); const chirpstackApplicationResponseDto: ChirpstackApplicationResponseDto[] = []; result.resultList.map(e => { @@ -172,11 +172,11 @@ export class GenericChirpstackConfigurationService { } async getAllWithPagination( - endpoint: string, + logName: string, + client: any, + request: any, limit?: number, - offset?: number, - client?: any, - request?: any + offset?: number ): Promise { const metaData = this.makeMetadataHeader(); request.setLimit(limit), request.setOffset(offset); @@ -188,14 +188,14 @@ export class GenericChirpstackConfigurationService { } else { const result = resp.toObject(); resolve(result); - this.innerLogger.debug(`get all from:${endpoint} success`); + this.innerLogger.debug(`get all from:${logName} success`); } }); }); try { return await getListPromise; } catch (err) { - this.innerLogger.error(`GET ${endpoint} got error: ${err}`); + this.innerLogger.error(`GET ${logName} got error: ${err}`); throw new NotFoundException(); } } @@ -206,10 +206,10 @@ export class GenericChirpstackConfigurationService { const res = await this.getAllWithPagination( "organizations", + tenantClient, + req, limit, offset, - tenantClient, - req ); return res; } diff --git a/src/services/chirpstack/multicast.service.ts b/src/services/chirpstack/multicast.service.ts index c8a6def6..90e4f2b1 100644 --- a/src/services/chirpstack/multicast.service.ts +++ b/src/services/chirpstack/multicast.service.ts @@ -123,7 +123,6 @@ export class MulticastService extends GenericChirpstackConfigurationService { } async create(createMulticastDto: CreateMulticastDto, userId: number): Promise { - //since the multicast is gonna be created in both the DB with relations and in chirpstack, two different objects is gonna be used. const dbMulticast = new Multicast(); dbMulticast.lorawanMulticastDefinition = new LorawanMulticastDefinition(); @@ -183,7 +182,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { if (!existingMulticast.lorawanMulticastDefinition.chirpstackGroupId) { await this.createIfNotInChirpstack(lorawanDevices, updateMulticastDto, mappedMulticast); } else { - await this.updateLogic(existingMulticast, lorawanDevices, updateMulticastDto, oldMulticast); + await this.updateLogic(existingMulticast, lorawanDevices, updateMulticastDto); } } mappedMulticast.updatedBy = userId; @@ -193,8 +192,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { async updateMulticastToChirpstack( updateMulticastDto: UpdateMulticastDto, existingChirpStackMulticast: CreateMulticastChirpStackDto, - lorawanDevices: LoRaWANDevice[], - existingMulticast: Multicast + lorawanDevices: LoRaWANDevice[] ): Promise { const mappedChirpStackMulticast = await this.mapMulticastDtoToChirpStackMulticast( updateMulticastDto, @@ -205,16 +203,6 @@ export class MulticastService extends GenericChirpstackConfigurationService { req.setMulticastGroup(mappedChirpStackMulticast); try { await this.put(this.multicastGroupUrl, this.multicastServiceClient, req); - - const added: IoTDevice[] = []; - const removed: IoTDevice[] = []; - this.compareDevices(existingMulticast, updateMulticastDto, added, removed); - await this.updateDevices( - // add's and removes devices from chirpstack - removed, - added, - existingMulticast.lorawanMulticastDefinition.chirpstackGroupId - ); } catch (e) { throw new BadRequestException(e); } @@ -276,18 +264,18 @@ export class MulticastService extends GenericChirpstackConfigurationService { this.multicastServiceClient, req ); - + const multicast = res.getMulticastGroup(); const multicastDtoContent: ChirpstackMulticastContentsDto = { - applicationID: res.getMulticastGroup().getApplicationId(), - dr: res.getMulticastGroup().getDr(), - fCnt: res.getMulticastGroup().getFCnt(), - frequency: res.getMulticastGroup().getFrequency(), - mcAddr: res.getMulticastGroup().getMcAddr(), - mcAppSKey: res.getMulticastGroup().getMcAppSKey(), - mcNwkSKey: res.getMulticastGroup().getMcNwkSKey(), - name: res.getMulticastGroup().getName(), + applicationID: multicast.getApplicationId(), + dr: multicast.getDr(), + fCnt: multicast.getFCnt(), + frequency: multicast.getFrequency(), + mcAddr: multicast.getMcAddr(), + mcAppSKey: multicast.getMcAppSKey(), + mcNwkSKey: multicast.getMcNwkSKey(), + name: multicast.getName(), groupType: multicastGroup.ClassC, - id: res.getMulticastGroup().getId(), + id: multicast.getId(), }; const returnDto: CreateMulticastChirpStackDto = { multicastGroup: multicastDtoContent }; @@ -295,7 +283,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { return returnDto; } - async multicastDelete(id: number, existingMulticast: Multicast): Promise { + async deleteMulticast(id: number, existingMulticast: Multicast): Promise { const loraDevices = this.checkForLorawan(existingMulticast); if (loraDevices.length > 0) { await this.deleteMulticastChirpstack(existingMulticast.lorawanMulticastDefinition.chirpstackGroupId); @@ -382,31 +370,6 @@ export class MulticastService extends GenericChirpstackConfigurationService { } } - private async updateDevices(removed: IoTDevice[], added: IoTDevice[], chirpstackMulticastID: string) { - removed.forEach(async device => { - // if the removed devices is a lorawan, then delete from chirpstack - if (device.type === IoTDeviceType.LoRaWAN) { - let lorawanDevice: LoRaWANDevice = new LoRaWANDevice(); - lorawanDevice = device as LoRaWANDevice; - return await this.delete( - this.multicastGroupUrl + "/" + chirpstackMulticastID + "/" + "devices", - lorawanDevice.deviceEUI - ); - } - }); - added.forEach(async device => { - if (device.type === IoTDeviceType.LoRaWAN) { - let lorawanDevice: LoRaWANDevice = new LoRaWANDevice(); - lorawanDevice = device as LoRaWANDevice; - const addDevice = new AddDeviceToMulticastDto(); - addDevice.devEUI = lorawanDevice.deviceEUI; - addDevice.multicastGroupID = chirpstackMulticastID; - - await this.post(this.multicastGroupUrl + "/" + chirpstackMulticastID + "/" + "devices", addDevice); - } - }); - } - private async addDevices( multicastDto: CreateMulticastDto | UpdateMulticastDto, chirpstackMulticastID: IdResponse // the id returned from chirpstack when the multicast is created in chirpstack. @@ -429,17 +392,17 @@ export class MulticastService extends GenericChirpstackConfigurationService { } async addDeviceToMulticast( - endpoint: string, - client?: MulticastGroupServiceClient, - request?: AddDeviceToMulticastGroupRequest - ): Promise { + logName: string, + client: MulticastGroupServiceClient, + request: AddDeviceToMulticastGroupRequest + ): Promise { const metaData = this.makeMetadataHeader(); - const createPromise = new Promise((resolve, reject) => { + const createPromise = new Promise((resolve, reject) => { client.addDevice(request, metaData, (err: ServiceError, resp: any) => { if (err) { reject(err); } else { - this.logger.debug(`post:${endpoint} success`); + this.logger.debug(`post:${logName} success`); resolve(resp.toObject()); } }); @@ -447,49 +410,27 @@ export class MulticastService extends GenericChirpstackConfigurationService { try { return await createPromise; } catch (err) { - this.logger.error(`POST ${endpoint} got error: ${err}`); + this.logger.error(`POST ${logName} got error: ${err}`); throw new BadRequestException(); } } - private compareDevices( - oldMulticast: Multicast, - newMulticast: UpdateMulticastDto, - added: IoTDevice[], - removed: IoTDevice[] - ) { - oldMulticast.iotDevices.forEach(dbDevice => { - // if a device in the old multicast is not in the new one, then delete - if (newMulticast.iotDevices.findIndex(device => device.id === dbDevice.id) === -1) { - removed.push(dbDevice); - } - }); - - newMulticast.iotDevices.forEach(frontendDevice => { - // if a device in the new multicast is not in the old one, then add - if (oldMulticast.iotDevices.findIndex(device => device.id === frontendDevice.id) === -1) { - added.push(frontendDevice); - } - }); - } - async getDownlinkQueue(multicastID: string): Promise { const req = new ListMulticastGroupQueueRequest(); req.setMulticastGroupId(multicastID); const res = await this.getQueue(this.multicastServiceClient, req); - const queueDto: MulticastQueueItem[] = []; - res.getItemsList().forEach(queueItem => { - queueDto.push({ + const queueItems: MulticastQueueItem[] = res.getItemsList().map(queueItem => { + return { multicastGroupId: queueItem.getMulticastGroupId(), fCnt: queueItem.getFCnt(), fPort: queueItem.getFPort(), data: queueItem.getData_asB64(), - }); + }; }); const responseDto: MulticastDownlinkQueueResponseDto = { - deviceQueueItems: queueDto, + deviceQueueItems: queueItems, }; return responseDto; } @@ -538,7 +479,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { async deleteDownlinkQueue(multicastID: string): Promise { const req = new FlushMulticastGroupQueueRequest(); req.setMulticastGroupId(multicastID); - await this.deleteQueue(this.multicastServiceClient, req); + await this.flushQueue(this.multicastServiceClient, req); } private hexBytesToBase64(hexBytes: string): string { @@ -561,7 +502,6 @@ export class MulticastService extends GenericChirpstackConfigurationService { existingMulticast: Multicast, lorawanDevices: LoRaWANDevice[], updateMulticastDto: UpdateMulticastDto, - oldMulticast: Multicast ): Promise { const existingChirpStackMulticast = await this.getChirpstackMulticast( existingMulticast.lorawanMulticastDefinition.chirpstackGroupId @@ -574,17 +514,12 @@ export class MulticastService extends GenericChirpstackConfigurationService { lorawanDevices ) ) { - await this.updateMulticastToChirpstack( - updateMulticastDto, - existingChirpStackMulticast, - lorawanDevices, - oldMulticast - ); + await this.updateMulticastToChirpstack(updateMulticastDto, existingChirpStackMulticast, lorawanDevices); } else { throw new BadRequestException(ErrorCodes.InvalidPost); } } else { - throw new BadRequestException(ErrorCodes.InvalidPost); + throw new BadRequestException(ErrorCodes.DifferentServiceProfile); } } @@ -610,7 +545,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { } } - async deleteQueue(client: MulticastGroupServiceClient, request: FlushMulticastGroupQueueRequest): Promise { + async flushQueue(client: MulticastGroupServiceClient, request: FlushMulticastGroupQueueRequest): Promise { const metaData = this.makeMetadataHeader(); const getPromise = new Promise((resolve, reject) => { client.flushQueue(request, metaData, (err: ServiceError, resp: any) => { diff --git a/src/services/data-management/search.service.ts b/src/services/data-management/search.service.ts index b1d894f9..cfd2704b 100644 --- a/src/services/data-management/search.service.ts +++ b/src/services/data-management/search.service.ts @@ -1,6 +1,5 @@ import { GatewayServiceClient } from "@chirpstack/chirpstack-api/api/gateway_grpc_pb"; -import { ListGatewaysRequest } from "@chirpstack/chirpstack-api/api/gateway_pb"; -import { ListAllGatewaysResponseChirpstackDto, ListAllGatewaysResponseDto } from "@dto/chirpstack/list-all-gateways.dto"; +import { ListGatewaysRequest, ListGatewaysResponse } from "@chirpstack/chirpstack-api/api/gateway_pb"; import { AuthenticatedRequest } from "@dto/internal/authenticated-request"; import { ListAllSearchResultsResponseDto } from "@dto/list-all-search-results-response.dto"; import { SearchResultDto, SearchResultType } from "@dto/search-result.dto"; @@ -89,21 +88,18 @@ export class SearchService { } private async findGateways(trimmedQuery: string): Promise { - const gatewayClient = new GatewayServiceClient( - this.gatewayService.baseUrlGRPC, - credentials.createInsecure() - ); + const gatewayClient = new GatewayServiceClient(this.gatewayService.baseUrlGRPC, credentials.createInsecure()); const escapedQuery = encodeURI(trimmedQuery); const req = new ListGatewaysRequest(); req.setSearch(escapedQuery); - //TODO:: The return type might be changed. - const gateways = await this.gatewayService.getAllWithPagination( - `gateways?search=${escapedQuery}`, - 1000, - 0, + + const gateways = await this.gatewayService.getAllWithPagination( + `gateways`, gatewayClient, - req + req, + 1000, + 0 ); const mapped = await Promise.all( @@ -111,10 +107,9 @@ export class SearchService { const createdAt = timestampToDate(x.createdAt); const updatedAt = timestampToDate(x.updatedAt); - const resultDto = new SearchResultDto(x.name, x.id, createdAt, updatedAt, x.gatewayId); + const resultDto = new SearchResultDto(x.name, x.gatewayId, createdAt, updatedAt, x.gatewayId); const detailedInfo = await this.gatewayService.getOne(x.gatewayId); - resultDto.organizationId = detailedInfo.gateway.organizationId; return resultDto; }) @@ -212,7 +207,6 @@ export class SearchService { return this.iotDeviceRepository.createQueryBuilder("device"); } - // eslint-disable-next-line max-lines-per-function private async applySecuityAndSelect( req: AuthenticatedRequest, qb: SelectQueryBuilder, diff --git a/src/services/device-management/iot-device.service.ts b/src/services/device-management/iot-device.service.ts index 1e3c273a..ab39ad96 100644 --- a/src/services/device-management/iot-device.service.ts +++ b/src/services/device-management/iot-device.service.ts @@ -749,9 +749,7 @@ export class IoTDeviceService { } } - private async getLorawanDeviceEuis( - iotDevicesDtoMap: CreateIoTDeviceMapDto[] - ): Promise { + private async getLorawanDeviceEuis(iotDevicesDtoMap: CreateIoTDeviceMapDto[]): Promise { const iotLorawanDevices = iotDevicesDtoMap.reduce((res: string[], { iotDevice, iotDeviceDto }) => { if (iotDevice.constructor.name === LoRaWANDevice.name && iotDeviceDto.lorawanSettings) { res.push(iotDeviceDto.lorawanSettings.devEUI); From ca24ae02f797bec759ed19856fdc8b51a5518652 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Fri, 15 Dec 2023 00:00:37 +0100 Subject: [PATCH 19/24] minor cleanup and update to application so the names in chirpstack is right. --- .../chirpstack/chirpstack-application.service.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/services/chirpstack/chirpstack-application.service.ts b/src/services/chirpstack/chirpstack-application.service.ts index dfd0c40b..0c7990af 100644 --- a/src/services/chirpstack/chirpstack-application.service.ts +++ b/src/services/chirpstack/chirpstack-application.service.ts @@ -7,7 +7,6 @@ import { ListApplicationsRequest, UpdateApplicationRequest, } from "@chirpstack/chirpstack-api/api/application_pb"; -import { CreateApplicationDto } from "@dto/create-application.dto"; import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; import { Application as DbApplication } from "@entities/application.entity"; import { ListAllChirpstackApplicationsResponseDto } from "@dto/chirpstack/list-all-applications-response.dto"; @@ -41,7 +40,7 @@ export class ApplicationChirpstackService extends GenericChirpstackConfiguration this.applicationServiceClient, req, 100, - undefined, + undefined )); // if application exist use it @@ -80,8 +79,10 @@ export class ApplicationChirpstackService extends GenericChirpstackConfiguration public async createChirpstackApplication(dto: CreateChirpstackApplicationDto): Promise { const req = new CreateApplicationRequest(); const application = new Application(); - application.setDescription(dto.application.description ? dto.application.description: this.DEFAULT_DESCRIPTION); - application.setName(dto.application.name); + application.setDescription( + dto.application.description ? dto.application.description : this.DEFAULT_DESCRIPTION + ); + application.setName(this.applicationNamePrefix + dto.application.name); application.setTenantId(await this.getDefaultOrganizationId()); req.setApplication(application); @@ -102,8 +103,8 @@ export class ApplicationChirpstackService extends GenericChirpstackConfiguration const req = new UpdateApplicationRequest(); const application = new Application(); application.setId(dto.chirpstackId); - application.setDescription(this.DEFAULT_DESCRIPTION); - application.setName(this.applicationNamePrefix + "-" + dto.name); + application.setDescription(dto.description ? dto.description : this.DEFAULT_DESCRIPTION); + application.setName(this.applicationNamePrefix + dto.name); application.setTenantId(await this.getDefaultOrganizationId()); req.setApplication(application); try { From e5ed65db16e447d8f7e67ad00e5ac5fc00a9de2b Mon Sep 17 00:00:00 2001 From: August Andersen Date: Fri, 15 Dec 2023 00:17:28 +0100 Subject: [PATCH 20/24] removed unused jwt token --- src/config/configuration.ts | 1 - src/services/chirpstack/jwt-token.ts | 28 ---------------------------- 2 files changed, 29 deletions(-) delete mode 100644 src/services/chirpstack/jwt-token.ts diff --git a/src/config/configuration.ts b/src/config/configuration.ts index 24f8fc38..3ad205ee 100644 --- a/src/config/configuration.ts +++ b/src/config/configuration.ts @@ -27,7 +27,6 @@ export default (): any => { roleUri: process.env.KOMBIT_ROLE_NAME || "http://os2iot.dk/roles/usersystemrole/adgang/", }, chirpstack: { - jwtsecret: process.env.CHIRPSTACK_JWTSECRET || "verysecret", apikey: process.env.CHIRPSTACK_API_KEY || "apikey", }, logLevels: process.env.LOG_LEVEL ? GetLogLevels(process.env.LOG_LEVEL) : GetLogLevels("debug"), diff --git a/src/services/chirpstack/jwt-token.ts b/src/services/chirpstack/jwt-token.ts deleted file mode 100644 index e58284b6..00000000 --- a/src/services/chirpstack/jwt-token.ts +++ /dev/null @@ -1,28 +0,0 @@ -import configuration from "@config/configuration"; -import { Injectable } from "@nestjs/common"; -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -import * as nJwt from "njwt"; - -@Injectable() -export class JwtToken { - static setupToken(): string { - const claims = { - iss: "as", // issuer of the claim - aud: "as", // audience for which the claim is intended - iat: Math.floor(new Date().valueOf() / 1000 - 10), // unix time from which the token is valid - nbf: Math.floor(new Date().valueOf() / 1000 - 10), // unix time from which the token is valid - exp: Math.floor(new Date().valueOf() / 1000) + 60 * 60 * 24 * 14, // unix time when the token expires - sub: "user", // subject of the claim (an user) - username: "admin", // username the client claims to be - }; - - const jwt = nJwt.create( - claims, - configuration()["chirpstack"]["jwtsecret"], - "HS256" - ); - const token = jwt.compact(); - return token; - } -} From efad399354e783cbd0a523c6287d78a9b8010085 Mon Sep 17 00:00:00 2001 From: Frederik Christ Vestergaard Date: Fri, 15 Dec 2023 09:17:06 +0100 Subject: [PATCH 21/24] Fixed small formatting oversight --- .../chirpstack/generic-chirpstack-configuration.service.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/services/chirpstack/generic-chirpstack-configuration.service.ts b/src/services/chirpstack/generic-chirpstack-configuration.service.ts index 422a0c60..a5bca255 100644 --- a/src/services/chirpstack/generic-chirpstack-configuration.service.ts +++ b/src/services/chirpstack/generic-chirpstack-configuration.service.ts @@ -179,7 +179,8 @@ export class GenericChirpstackConfigurationService { offset?: number ): Promise { const metaData = this.makeMetadataHeader(); - request.setLimit(limit), request.setOffset(offset); + request.setLimit(limit); + request.setOffset(offset); const getListPromise = new Promise((resolve, reject) => { client.list(request, metaData, (err: ServiceError, resp: any) => { @@ -209,7 +210,7 @@ export class GenericChirpstackConfigurationService { tenantClient, req, limit, - offset, + offset ); return res; } From ec076c778058d5774bdbe3af2f6a095a49e89b68 Mon Sep 17 00:00:00 2001 From: Frederik Christ Vestergaard Date: Fri, 15 Dec 2023 10:37:43 +0100 Subject: [PATCH 22/24] Small name and format changes --- .../chirpstack/gateway-boostrapper.service.ts | 19 ++++++++---------- ...eneric-chirpstack-configuration.service.ts | 1 + src/services/chirpstack/multicast.service.ts | 18 ++++++++--------- .../lorawan-device-database-enrich-job.ts | 20 ++++++++++--------- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/services/chirpstack/gateway-boostrapper.service.ts b/src/services/chirpstack/gateway-boostrapper.service.ts index 7a0cb734..80fd9705 100644 --- a/src/services/chirpstack/gateway-boostrapper.service.ts +++ b/src/services/chirpstack/gateway-boostrapper.service.ts @@ -41,19 +41,16 @@ export class GatewayBootstrapperService implements OnApplicationBootstrap { // Don't overwrite ones which already have a status history const newHistoriesForMissingGateways = gateways.resultList.reduce((res: GatewayStatusHistory[], gateway) => { - if (!statusHistories.some(history => history.mac === gateway.gatewayId)) { - // Best fit is to imitate the status logic from Chirpstack. - if (gateway.lastSeenAt) { - const lastSeenDate = gateway.lastSeenAt; + if (!statusHistories.some(history => history.mac === gateway.gatewayId) && gateway.lastSeenAt) { + const lastSeenDate = gateway.lastSeenAt; - const wasOnline = errorTime.getTime() < lastSeenDate.getTime(); + const wasOnline = errorTime.getTime() < lastSeenDate.getTime(); - res.push({ - mac: gateway.gatewayId, - timestamp: now, - wasOnline, - } as GatewayStatusHistory); - } + res.push({ + mac: gateway.gatewayId, + timestamp: now, + wasOnline, + } as GatewayStatusHistory); } return res; diff --git a/src/services/chirpstack/generic-chirpstack-configuration.service.ts b/src/services/chirpstack/generic-chirpstack-configuration.service.ts index a5bca255..24ec28a0 100644 --- a/src/services/chirpstack/generic-chirpstack-configuration.service.ts +++ b/src/services/chirpstack/generic-chirpstack-configuration.service.ts @@ -58,6 +58,7 @@ export class GenericChirpstackConfigurationService { throw new BadRequestException(); } } + async put(logName: string, client: any, request: any): Promise { const metaData = this.makeMetadataHeader(); const updatePromise = new Promise((resolve, reject) => { diff --git a/src/services/chirpstack/multicast.service.ts b/src/services/chirpstack/multicast.service.ts index 90e4f2b1..4bd39cfc 100644 --- a/src/services/chirpstack/multicast.service.ts +++ b/src/services/chirpstack/multicast.service.ts @@ -13,9 +13,7 @@ import { ApplicationService } from "../device-management/application.service"; import { ChirpstackMulticastContentsDto } from "@dto/chirpstack/chirpstack-multicast-contents.dto"; import { LorawanMulticastDefinition } from "@entities/lorawan-multicast.entity"; import { IoTDeviceType } from "@enum/device-type.enum"; -import { AddDeviceToMulticastDto } from "@dto/chirpstack-add-device-multicast.dto"; import { LoRaWANDevice } from "@entities/lorawan-device.entity"; -import { IoTDevice } from "@entities/iot-device.entity"; import { MulticastDownlinkQueueResponseDto, MulticastQueueItem, @@ -46,6 +44,7 @@ import { MulticastGroupServiceClient } from "@chirpstack/chirpstack-api/api/mult import { ServiceError } from "@grpc/grpc-js"; import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; import { multicastGroup } from "@enum/multicast-type.enum"; + @Injectable() export class MulticastService extends GenericChirpstackConfigurationService { constructor( @@ -133,7 +132,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { mappedDbMulticast.lorawanMulticastDefinition.updatedBy = userId; if (!!createMulticastDto.iotDevices) { - const lorawanDevices = this.checkForLorawan(createMulticastDto); + const lorawanDevices = this.filterForLoRaWAN(createMulticastDto); if (lorawanDevices.length > 0) { if (await this.checkForDifferentAppID(lorawanDevices)) { // If they all have same serviceID / appID then proceed. @@ -175,8 +174,8 @@ export class MulticastService extends GenericChirpstackConfigurationService { ): Promise { const oldMulticast: Multicast = { ...existingMulticast }; const mappedMulticast = await this.mapMulticastDtoToDbMulticast(updateMulticastDto, existingMulticast); - const lorawanDevices = this.checkForLorawan(updateMulticastDto); - const oldLorawanDevices = this.checkForLorawan(oldMulticast); + const lorawanDevices = this.filterForLoRaWAN(updateMulticastDto); + const oldLorawanDevices = this.filterForLoRaWAN(oldMulticast); if (lorawanDevices.length > 0 || oldLorawanDevices.length > 0) { // check if new lorawan devices is included. If so, either create or update in chirpstack. Otherwise, just update db if (!existingMulticast.lorawanMulticastDefinition.chirpstackGroupId) { @@ -208,9 +207,8 @@ export class MulticastService extends GenericChirpstackConfigurationService { } } - checkForLorawan(multicastDto: CreateMulticastDto | Multicast | UpdateMulticastDto): LoRaWANDevice[] { - const lorawanDevices = multicastDto.iotDevices.filter(x => x.type === IoTDeviceType.LoRaWAN) as LoRaWANDevice[]; - return lorawanDevices; + filterForLoRaWAN(multicastDto: CreateMulticastDto | Multicast | UpdateMulticastDto): LoRaWANDevice[] { + return multicastDto.iotDevices.filter(x => x.type === IoTDeviceType.LoRaWAN) as LoRaWANDevice[]; } async validateNewDevicesAppID( @@ -284,7 +282,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { } async deleteMulticast(id: number, existingMulticast: Multicast): Promise { - const loraDevices = this.checkForLorawan(existingMulticast); + const loraDevices = this.filterForLoRaWAN(existingMulticast); if (loraDevices.length > 0) { await this.deleteMulticastChirpstack(existingMulticast.lorawanMulticastDefinition.chirpstackGroupId); } @@ -501,7 +499,7 @@ export class MulticastService extends GenericChirpstackConfigurationService { private async updateLogic( existingMulticast: Multicast, lorawanDevices: LoRaWANDevice[], - updateMulticastDto: UpdateMulticastDto, + updateMulticastDto: UpdateMulticastDto ): Promise { const existingChirpStackMulticast = await this.getChirpstackMulticast( existingMulticast.lorawanMulticastDefinition.chirpstackGroupId diff --git a/src/services/device-management/lorawan-device-database-enrich-job.ts b/src/services/device-management/lorawan-device-database-enrich-job.ts index 4e012d46..f6db7a63 100644 --- a/src/services/device-management/lorawan-device-database-enrich-job.ts +++ b/src/services/device-management/lorawan-device-database-enrich-job.ts @@ -9,10 +9,7 @@ import { InjectRepository } from "@nestjs/typeorm"; import { Gateway } from "@entities/gateway.entity"; import { Repository } from "typeorm"; import { timestampToDate } from "@helpers/date.helper"; -import { - GetGatewayRequest, - GetGatewayResponse, -} from "@chirpstack/chirpstack-api/api/gateway_pb"; +import { GetGatewayRequest, GetGatewayResponse } from "@chirpstack/chirpstack-api/api/gateway_pb"; import { GatewayServiceClient } from "@chirpstack/chirpstack-api/api/gateway_grpc_pb"; import { credentials } from "@grpc/grpc-js"; @@ -35,7 +32,7 @@ export class LorawanDeviceDatabaseEnrichJob { async fetchStatusForGateway() { // Select all gateways from our database and chirpstack (Cheaper than individual calls) const gateways = await this.gatewayService.getAll(); - const chirpstackDevices = await this.gatewayService.getAllGatewaysFromChirpstack(); + const chirpstackGateways = await this.gatewayService.getAllGatewaysFromChirpstack(); // Setup batched fetching of status (Only for today) await BluebirdPromise.all( @@ -55,7 +52,9 @@ export class LorawanDeviceDatabaseEnrichJob { ); // Save that to our database const stats = statsToday[0]; - const chirpstackGateway = chirpstackDevices.resultList.find(g => g.gatewayId === gateway.gatewayId); + const chirpstackGateway = chirpstackGateways.resultList.find( + g => g.gatewayId === gateway.gatewayId + ); await this.gatewayService.updateGatewayStats( gateway.gatewayId, @@ -101,10 +100,10 @@ export class LorawanDeviceDatabaseEnrichJob { // This is run once on startup and will create any gateways that exist in chirpstack but not our database @Timeout(10000) async importChirpstackGateways() { - const chirpstackDevices = await this.gatewayService.getAllGatewaysFromChirpstack(); + const chirpstackGateways = await this.gatewayService.getAllGatewaysFromChirpstack(); const dbGateways = await this.gatewayService.getAll(); // Filter for gateways not existing in our database - const unknownGateways = chirpstackDevices.resultList.filter( + const unknownGateways = chirpstackGateways.resultList.filter( g => dbGateways.resultList.findIndex(dbGateway => dbGateway.gatewayId === g.gatewayId) === -1 ); await BluebirdPromise.all( @@ -122,7 +121,10 @@ export class LorawanDeviceDatabaseEnrichJob { ); const chirpstackGateway = gwResponse.getGateway(); const organizationId = +chirpstackGateway.getTagsMap().get("internalOrganizationId"); - const gateway = this.gatewayService.mapChirpstackGatewayToDatabaseGateway(chirpstackGateway, gwResponse); + const gateway = this.gatewayService.mapChirpstackGatewayToDatabaseGateway( + chirpstackGateway, + gwResponse + ); gateway.organization = await this.organizationService.findById(organizationId); await this.gatewayRepository.save(gateway); } catch (err) { From 0d80d0b8626518fbb40ca917280a5ec323b6761a Mon Sep 17 00:00:00 2001 From: August Andersen Date: Fri, 15 Dec 2023 12:07:01 +0100 Subject: [PATCH 23/24] PR changes --- .../dto/chirpstack/gateway-response.dto.ts | 2 +- .../dto/chirpstack/list-all-gateways.dto.ts | 6 +-- .../chirpstack-application.service.ts | 24 +++++----- .../chirpstack/chirpstack-gateway.service.ts | 44 +++++++++---------- .../chirpstack/device-profile.service.ts | 3 +- 5 files changed, 35 insertions(+), 44 deletions(-) diff --git a/src/entities/dto/chirpstack/gateway-response.dto.ts b/src/entities/dto/chirpstack/gateway-response.dto.ts index 35382c69..71f4a27d 100644 --- a/src/entities/dto/chirpstack/gateway-response.dto.ts +++ b/src/entities/dto/chirpstack/gateway-response.dto.ts @@ -1,7 +1,7 @@ import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; import { CommonLocationDto } from "./common-location.dto"; -export class GatewayResponseChirpstackDto { +export class ChirpstackGatewayResponseDto { id?: number; gatewayId: string; name: string; diff --git a/src/entities/dto/chirpstack/list-all-gateways.dto.ts b/src/entities/dto/chirpstack/list-all-gateways.dto.ts index 7e95f872..3b0e4ab9 100644 --- a/src/entities/dto/chirpstack/list-all-gateways.dto.ts +++ b/src/entities/dto/chirpstack/list-all-gateways.dto.ts @@ -1,11 +1,11 @@ -import { GatewayResponseChirpstackDto, GatewayResponseDto } from "./gateway-response.dto"; +import { ChirpstackGatewayResponseDto, GatewayResponseDto } from "./gateway-response.dto"; export class ListAllGatewaysResponseDto { totalCount: number; resultList: GatewayResponseDto[]; } -export class ListAllGatewaysResponseChirpstackDto { +export class ListAllChirpstackGatewaysResponseDto { totalCount: number; - resultList: GatewayResponseChirpstackDto[]; + resultList: ChirpstackGatewayResponseDto[]; } diff --git a/src/services/chirpstack/chirpstack-application.service.ts b/src/services/chirpstack/chirpstack-application.service.ts index 0c7990af..7cba49b8 100644 --- a/src/services/chirpstack/chirpstack-application.service.ts +++ b/src/services/chirpstack/chirpstack-application.service.ts @@ -1,14 +1,14 @@ import { Injectable } from "@nestjs/common"; import { GenericChirpstackConfigurationService } from "./generic-chirpstack-configuration.service"; import { - Application, + Application as ChirpstackApplication, CreateApplicationRequest, DeleteApplicationRequest, ListApplicationsRequest, UpdateApplicationRequest, } from "@chirpstack/chirpstack-api/api/application_pb"; import { IdResponse } from "@interfaces/chirpstack-id-response.interface"; -import { Application as DbApplication } from "@entities/application.entity"; +import { Application } from "@entities/application.entity"; import { ListAllChirpstackApplicationsResponseDto } from "@dto/chirpstack/list-all-applications-response.dto"; import { LoRaWANDevice } from "@entities/lorawan-device.entity"; import { CreateChirpstackApplicationDto } from "@dto/chirpstack/create-chirpstack-application.dto"; @@ -17,8 +17,8 @@ import { Repository } from "typeorm"; @Injectable() export class ApplicationChirpstackService extends GenericChirpstackConfigurationService { - @InjectRepository(DbApplication) - private applicationRepository: Repository; + @InjectRepository(Application) + private applicationRepository: Repository; constructor() { super(); } @@ -51,18 +51,14 @@ export class ApplicationChirpstackService extends GenericChirpstackConfiguration // otherwise create new application if (!applicationId) { - applicationId = await this.createNewApplication( - applicationId, - iotDevice.application.name, - iotDevice.application.id - ); + applicationId = await this.createNewApplication(iotDevice.application.name, iotDevice.application.id); } return applicationId; } - public async createNewApplication(applicationId: string, name: string, id: number) { - applicationId = await this.createChirpstackApplication({ + public async createNewApplication(name: string, id: number) { + const applicationId = await this.createChirpstackApplication({ application: { name: `${this.applicationNamePrefix}${name}`, description: this.DEFAULT_DESCRIPTION, @@ -78,7 +74,7 @@ export class ApplicationChirpstackService extends GenericChirpstackConfiguration public async createChirpstackApplication(dto: CreateChirpstackApplicationDto): Promise { const req = new CreateApplicationRequest(); - const application = new Application(); + const application = new ChirpstackApplication(); application.setDescription( dto.application.description ? dto.application.description : this.DEFAULT_DESCRIPTION ); @@ -99,9 +95,9 @@ export class ApplicationChirpstackService extends GenericChirpstackConfiguration throw e; } } - public async updateApplication(dto: DbApplication): Promise { + public async updateApplication(dto: Application): Promise { const req = new UpdateApplicationRequest(); - const application = new Application(); + const application = new ChirpstackApplication(); application.setId(dto.chirpstackId); application.setDescription(dto.description ? dto.description : this.DEFAULT_DESCRIPTION); application.setName(this.applicationNamePrefix + dto.name); diff --git a/src/services/chirpstack/chirpstack-gateway.service.ts b/src/services/chirpstack/chirpstack-gateway.service.ts index e91747de..042fd6b7 100644 --- a/src/services/chirpstack/chirpstack-gateway.service.ts +++ b/src/services/chirpstack/chirpstack-gateway.service.ts @@ -10,7 +10,7 @@ import { ChirpstackResponseStatus } from "@dto/chirpstack/chirpstack-response.dt import { CreateGatewayDto } from "@dto/chirpstack/create-gateway.dto"; import { GatewayStatsElementDto } from "@dto/chirpstack/gateway-stats.response.dto"; import { - ListAllGatewaysResponseChirpstackDto, + ListAllChirpstackGatewaysResponseDto, ListAllGatewaysResponseDto, } from "@dto/chirpstack/list-all-gateways.dto"; import { SingleGatewayResponseDto } from "@dto/chirpstack/single-gateway-response.dto"; @@ -39,7 +39,7 @@ import { import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb"; import { Aggregation, Location } from "@chirpstack/chirpstack-api/common/common_pb"; import { dateToTimestamp, timestampToDate } from "@helpers/date.helper"; -import { GatewayResponseChirpstackDto, GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto"; +import { ChirpstackGatewayResponseDto, GatewayResponseDto } from "@dto/chirpstack/gateway-response.dto"; @Injectable() export class ChirpstackGatewayService extends GenericChirpstackConfigurationService { constructor( @@ -69,16 +69,14 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ gateway.organization = await this.organizationService.findById(dto.organizationId); const req = new CreateGatewayRequest(); - const chirpstackLocation = new Location(); - this.mapToChirpstackLocation(chirpstackLocation, dto); + const chirpstackLocation = this.mapToChirpstackLocation(dto); - const gatewayCs = new ChirpstackGateway(); - await this.mapToChirpstackGateway(gatewayCs, dto, chirpstackLocation); + const gatewayChirpstack = await this.mapToChirpstackGateway(dto, chirpstackLocation); Object.entries(dto.gateway.tags).forEach(([key, value]) => { - gatewayCs.getTagsMap().set(key, value); + gatewayChirpstack.getTagsMap().set(key, value); }); - req.setGateway(gatewayCs); + req.setGateway(gatewayChirpstack); try { await this.post("gateways", this.gatewayClient, req); await this.gatewayRepository.save(gateway); @@ -92,25 +90,26 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ } } - async mapToChirpstackGateway( - gateway: ChirpstackGateway, - dto: CreateGatewayDto | UpdateGatewayDto, - location: Location, - gatewayId?: string - ) { + async mapToChirpstackGateway(dto: CreateGatewayDto | UpdateGatewayDto, location: Location, gatewayId?: string) { + const gateway = new ChirpstackGateway(); gateway.setGatewayId(gatewayId ? gatewayId : dto.gateway.gatewayId); gateway.setDescription(dto.gateway.description); gateway.setName(dto.gateway.name); gateway.setLocation(location); gateway.setStatsInterval(30); gateway.setTenantId(dto.gateway.tenantId ? dto.gateway.tenantId : await this.getDefaultOrganizationId()); + + return gateway; } - mapToChirpstackLocation(location: Location, dto: CreateGatewayDto | UpdateGatewayDto) { + mapToChirpstackLocation(dto: CreateGatewayDto | UpdateGatewayDto) { + const location = new Location(); location.setAccuracy(dto.gateway.location.accuracy); location.setAltitude(dto.gateway.location.altitude); location.setLatitude(dto.gateway.location.latitude); location.setLongitude(dto.gateway.location.longitude); location.setSource(dto.gateway.location.source); + + return location; } addUserToTags(dto: CreateGatewayDto, userId: number): { [id: string]: string } { @@ -269,12 +268,9 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ gateway.updatedBy = req.user.userId; const request = new UpdateGatewayRequest(); - const location = new Location(); - this.mapToChirpstackLocation(location, dto); - - const gatewayCs = new ChirpstackGateway(); + const location = this.mapToChirpstackLocation(dto); - await this.mapToChirpstackGateway(gatewayCs, dto, location, gatewayId); + const gatewayCs = await this.mapToChirpstackGateway(dto, location, gatewayId); Object.entries(dto.gateway.tags).forEach(([key, value]) => { gatewayCs.getTagsMap().set(key, value); @@ -427,7 +423,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ return responseDto; } - async getAllGatewaysFromChirpstack(): Promise { + async getAllGatewaysFromChirpstack(): Promise { const limit = 1000; const listReq = new ListGatewaysRequest(); // Get all chirpstack gateways @@ -439,9 +435,9 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ 0 ); - const responseItem: GatewayResponseChirpstackDto[] = []; + const responseItem: ChirpstackGatewayResponseDto[] = []; chirpStackGateways.resultList.map(e => { - const resultItem: GatewayResponseChirpstackDto = { + const resultItem: ChirpstackGatewayResponseDto = { gatewayId: e.gatewayId, name: e.name, location: e.location, @@ -452,7 +448,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ }; responseItem.push(resultItem); }); - const responseList: ListAllGatewaysResponseChirpstackDto = { + const responseList: ListAllChirpstackGatewaysResponseDto = { totalCount: chirpStackGateways.totalCount, resultList: responseItem, }; diff --git a/src/services/chirpstack/device-profile.service.ts b/src/services/chirpstack/device-profile.service.ts index d7be9fd2..566efed3 100644 --- a/src/services/chirpstack/device-profile.service.ts +++ b/src/services/chirpstack/device-profile.service.ts @@ -329,9 +329,8 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService async getAdrAlgorithms(): Promise { const metaData = this.makeMetadataHeader(); - const test: google_protobuf_empty_pb.Empty = new Empty(); const getPromise = new Promise((resolve, reject) => { - this.deviceProfileClient.listAdrAlgorithms(test, metaData, (err: ServiceError, resp: any) => { + this.deviceProfileClient.listAdrAlgorithms(new Empty(), metaData, (err: ServiceError, resp: any) => { if (err) { reject(err); } else { From f53574ce5b8a55ef878785e6f3cf29651e0edc52 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Fri, 15 Dec 2023 12:07:31 +0100 Subject: [PATCH 24/24] Changed error message --- src/entities/enum/error-codes.enum.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entities/enum/error-codes.enum.ts b/src/entities/enum/error-codes.enum.ts index 1d47ee19..89ddd791 100644 --- a/src/entities/enum/error-codes.enum.ts +++ b/src/entities/enum/error-codes.enum.ts @@ -49,5 +49,5 @@ export enum ErrorCodes { UserDoesNotExistInArray = "MESSAGE.USER-DOES-NOT-EXIST", UserAlreadyInPermission = "MESSAGE.USER-ALREADY-IN-PERMISSION", CouldntGetApplications = "MESSAGE.COULD-NOT-GET-CS-APPLICATIONS", - DifferentServiceProfile = "MESSAGE.DIFFERENT-SERVICE-PROFILE", + DifferentServiceProfile = "MESSAGE.DIFFERENT-CREATION-SERVICE-PROFILE", }