From 2243bcb3a4e8290a888475a4ad5e96b8a44787d5 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Mon, 20 Nov 2023 11:36:55 +0530 Subject: [PATCH 001/185] feat: added dev and prod setup using esbuild --- backend-pg/.gitignore | 1 + backend-pg/esbuild.config.js | 20 + backend-pg/nodemon.json | 7 + backend-pg/package-lock.json | 1616 ++++++++++++++++++++++++++++++++++ backend-pg/package.json | 24 + backend-pg/src/app.ts | 22 + backend-pg/tsconfig.json | 31 + 7 files changed, 1721 insertions(+) create mode 100644 backend-pg/.gitignore create mode 100644 backend-pg/esbuild.config.js create mode 100644 backend-pg/nodemon.json create mode 100644 backend-pg/package-lock.json create mode 100644 backend-pg/package.json create mode 100644 backend-pg/src/app.ts create mode 100644 backend-pg/tsconfig.json diff --git a/backend-pg/.gitignore b/backend-pg/.gitignore new file mode 100644 index 000000000..1521c8b76 --- /dev/null +++ b/backend-pg/.gitignore @@ -0,0 +1 @@ +dist diff --git a/backend-pg/esbuild.config.js b/backend-pg/esbuild.config.js new file mode 100644 index 000000000..b99af058d --- /dev/null +++ b/backend-pg/esbuild.config.js @@ -0,0 +1,20 @@ +// final prod build +const { build } = require("esbuild"); + +build({ + entryPoints: ["./src/app.ts"], + minify: true, + format: "cjs", + platform: "node", + target: "node20", + bundle: true, + outfile: "dist/index.js", + plugins: [], +}) + .catch((err) => { + console.error(err); + process.exit(1); + }) + .then(() => { + console.log("Finished bundling server.."); + }); diff --git a/backend-pg/nodemon.json b/backend-pg/nodemon.json new file mode 100644 index 000000000..0dc2014e6 --- /dev/null +++ b/backend-pg/nodemon.json @@ -0,0 +1,7 @@ +{ + "watch": "./src", + "verbose": true, + "ignore": [".git", "node_modules"], + "exec": "node esbuild.config.js && node dist/index.js", + "ext": "ts json" +} diff --git a/backend-pg/package-lock.json b/backend-pg/package-lock.json new file mode 100644 index 000000000..01fcfa72f --- /dev/null +++ b/backend-pg/package-lock.json @@ -0,0 +1,1616 @@ +{ + "name": "backend-pg", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "backend-pg", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "fastify": "^4.24.3", + "ora": "^7.0.1" + }, + "devDependencies": { + "@types/node": "^20.9.1", + "esbuild": "^0.19.5", + "nodemon": "^3.0.1", + "typescript": "^5.2.2" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.5.tgz", + "integrity": "sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.5.tgz", + "integrity": "sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.5.tgz", + "integrity": "sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.5.tgz", + "integrity": "sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.5.tgz", + "integrity": "sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.5.tgz", + "integrity": "sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.5.tgz", + "integrity": "sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.5.tgz", + "integrity": "sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.5.tgz", + "integrity": "sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.5.tgz", + "integrity": "sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.5.tgz", + "integrity": "sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.5.tgz", + "integrity": "sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.5.tgz", + "integrity": "sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.5.tgz", + "integrity": "sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.5.tgz", + "integrity": "sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.5.tgz", + "integrity": "sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.5.tgz", + "integrity": "sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.5.tgz", + "integrity": "sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.5.tgz", + "integrity": "sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.5.tgz", + "integrity": "sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.5.tgz", + "integrity": "sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.5.tgz", + "integrity": "sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fastify/ajv-compiler": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz", + "integrity": "sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==", + "dependencies": { + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "fast-uri": "^2.0.0" + } + }, + "node_modules/@fastify/deepmerge": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@fastify/deepmerge/-/deepmerge-1.3.0.tgz", + "integrity": "sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==" + }, + "node_modules/@fastify/error": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.4.1.tgz", + "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==" + }, + "node_modules/@fastify/fast-json-stringify-compiler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz", + "integrity": "sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==", + "dependencies": { + "fast-json-stringify": "^5.7.0" + } + }, + "node_modules/@types/node": { + "version": "20.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.1.tgz", + "integrity": "sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "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==", + "dev": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/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, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/avvio": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.2.1.tgz", + "integrity": "sha512-TAlMYvOuwGyLK3PfBb5WKBXZmXz2fVCgv23d6zZFdle/q3gPjmxBaeuC0pY0Dzs5PWMSgfqqEZkrye19GlDTgw==", + "dependencies": { + "archy": "^1.0.0", + "debug": "^4.0.0", + "fastq": "^1.6.1" + } + }, + "node_modules/avvio/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/avvio/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/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/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.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" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", + "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==" + }, + "node_modules/esbuild": { + "version": "0.19.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.5.tgz", + "integrity": "sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.19.5", + "@esbuild/android-arm64": "0.19.5", + "@esbuild/android-x64": "0.19.5", + "@esbuild/darwin-arm64": "0.19.5", + "@esbuild/darwin-x64": "0.19.5", + "@esbuild/freebsd-arm64": "0.19.5", + "@esbuild/freebsd-x64": "0.19.5", + "@esbuild/linux-arm": "0.19.5", + "@esbuild/linux-arm64": "0.19.5", + "@esbuild/linux-ia32": "0.19.5", + "@esbuild/linux-loong64": "0.19.5", + "@esbuild/linux-mips64el": "0.19.5", + "@esbuild/linux-ppc64": "0.19.5", + "@esbuild/linux-riscv64": "0.19.5", + "@esbuild/linux-s390x": "0.19.5", + "@esbuild/linux-x64": "0.19.5", + "@esbuild/netbsd-x64": "0.19.5", + "@esbuild/openbsd-x64": "0.19.5", + "@esbuild/sunos-x64": "0.19.5", + "@esbuild/win32-arm64": "0.19.5", + "@esbuild/win32-ia32": "0.19.5", + "@esbuild/win32-x64": "0.19.5" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-content-type-parse": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", + "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==" + }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==" + }, + "node_modules/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==" + }, + "node_modules/fast-json-stringify": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.9.1.tgz", + "integrity": "sha512-NMrf+uU9UJnTzfxaumMDXK1NWqtPCfGoM9DYIE+ESlaTQqjlANFBy0VAbsm6FB88Mx0nceyi18zTo5kIEUlzxg==", + "dependencies": { + "@fastify/deepmerge": "^1.0.0", + "ajv": "^8.10.0", + "ajv-formats": "^2.1.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^2.1.0", + "json-schema-ref-resolver": "^1.0.1", + "rfdc": "^1.2.0" + } + }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "node_modules/fast-redact": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.3.0.tgz", + "integrity": "sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-uri": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.3.0.tgz", + "integrity": "sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==" + }, + "node_modules/fastify": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.24.3.tgz", + "integrity": "sha512-6HHJ+R2x2LS3y1PqxnwEIjOTZxFl+8h4kSC/TuDPXtA+v2JnV9yEtOsNSKK1RMD7sIR2y1ZsA4BEFaid/cK5pg==", + "dependencies": { + "@fastify/ajv-compiler": "^3.5.0", + "@fastify/error": "^3.4.0", + "@fastify/fast-json-stringify-compiler": "^4.3.0", + "abstract-logging": "^2.0.1", + "avvio": "^8.2.1", + "fast-content-type-parse": "^1.1.0", + "fast-json-stringify": "^5.8.0", + "find-my-way": "^7.7.0", + "light-my-request": "^5.11.0", + "pino": "^8.16.0", + "process-warning": "^2.2.0", + "proxy-addr": "^2.0.7", + "rfdc": "^1.3.0", + "secure-json-parse": "^2.7.0", + "semver": "^7.5.4", + "toad-cache": "^3.3.0" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/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, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-my-way": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-7.7.0.tgz", + "integrity": "sha512-+SrHpvQ52Q6W9f3wJoJBbAQULJuNEEQwBvlvYwACDhBTLOTMiQ0HYWh4+vC3OivGP2ENcTI1oKlFA2OepJNjhQ==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/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==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/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, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/json-schema-ref-resolver": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz", + "integrity": "sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/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==" + }, + "node_modules/light-my-request": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.11.0.tgz", + "integrity": "sha512-qkFCeloXCOMpmEdZ/MV91P8AT4fjwFXWaAFz3lUeStM8RcoM1ks4J/F8r1b3r6y/H4u3ACEJ1T+Gv5bopj7oDA==", + "dependencies": { + "cookie": "^0.5.0", + "process-warning": "^2.0.0", + "set-cookie-parser": "^2.4.1" + } + }, + "node_modules/log-symbols": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", + "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", + "dependencies": { + "chalk": "^5.0.0", + "is-unicode-supported": "^1.1.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nodemon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", + "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz", + "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^4.0.0", + "cli-spinners": "^2.9.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^1.3.0", + "log-symbols": "^5.1.0", + "stdin-discarder": "^0.1.0", + "string-width": "^6.1.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "8.16.2", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.16.2.tgz", + "integrity": "sha512-2advCDGVEvkKu9TTVSa/kWW7Z3htI/sBKEZpqiHk6ive0i/7f5b1rsU8jn0aimxqfnSz5bj/nOYkwhBUn5xxvg==", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "v1.1.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^2.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.7.0", + "thread-stream": "^2.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.1.0.tgz", + "integrity": "sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==", + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==" + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-warning": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.3.0.tgz", + "integrity": "sha512-N6mp1+2jpQr3oCFMz6SeHRGbv6Slb20bRhj4v3xR99HqNToAcOe1MFOp4tytyzOfJn+QtN8Rf7U/h2KAn4kC6g==" + }, + "node_modules/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==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + }, + "node_modules/readable-stream": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.4.2.tgz", + "integrity": "sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" + }, + "node_modules/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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", + "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==", + "dependencies": { + "ret": "~0.2.0" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" + }, + "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/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + }, + "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==" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sonic-boom": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.7.0.tgz", + "integrity": "sha512-IudtNvSqA/ObjN97tfgNmOKyDOs4dNcg4cUUsHDebqsgb8wGBBwb31LIgShNO8fye0dFI52X1+tFoKKI6Rq1Gg==", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/stdin-discarder": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", + "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", + "dependencies": { + "bl": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz", + "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^10.2.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/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, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/thread-stream": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.4.1.tgz", + "integrity": "sha512-d/Ex2iWd1whipbT681JmTINKw0ZwOUBZm7+Gjs64DHuX34mmw8vJL2bFAaNacaW72zYiTJxSHi5abUuOi5nsfg==", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/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, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toad-cache": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.3.0.tgz", + "integrity": "sha512-3oDzcogWGHZdkwrHyvJVpPjA7oNzY6ENOV3PsWJY9XYPZ6INo94Yd47s5may1U+nleBPwDhrRiTPMIvKaa3MQg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/backend-pg/package.json b/backend-pg/package.json new file mode 100644 index 000000000..15a3d47d7 --- /dev/null +++ b/backend-pg/package.json @@ -0,0 +1,24 @@ +{ + "name": "backend-pg", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "node esbuild.config.js", + "dev": "nodemon" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/node": "^20.9.1", + "esbuild": "^0.19.5", + "nodemon": "^3.0.1", + "typescript": "^5.2.2" + }, + "dependencies": { + "fastify": "^4.24.3", + "ora": "^7.0.1" + } +} diff --git a/backend-pg/src/app.ts b/backend-pg/src/app.ts new file mode 100644 index 000000000..0a6669343 --- /dev/null +++ b/backend-pg/src/app.ts @@ -0,0 +1,22 @@ +import Fasitfy from "fastify"; + +const fastify = Fasitfy({ + logger: true, +}); + +// Declare a route +fastify.get("/", async function handler(_request, _reply) { + return { hello: "world changed" }; +}); + +// Run the server! +const main = async () => { + try { + await fastify.listen({ port: 8000 }); + } catch (err) { + fastify.log.error(err); + process.exit(1); + } +}; + +main(); diff --git a/backend-pg/tsconfig.json b/backend-pg/tsconfig.json new file mode 100644 index 000000000..0246faa87 --- /dev/null +++ b/backend-pg/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "allowJs": true, + "removeComments": true, + "resolveJsonModule": true, + "typeRoots": [ + "./node_modules/@types" + ], + "sourceMap": true, + "outDir": "dist", + "strict": true, + "lib": [ + "esnext" + ], + "baseUrl": ".", + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "moduleResolution": "Node", + "skipLibCheck": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules" + ] +} From 05205d1eff739eadccc2ad0f4982c96adcec6d40 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Mon, 27 Nov 2023 15:47:32 +0530 Subject: [PATCH 002/185] feat(infisical-pg): added all previous simple server middlewares, swagger support --- backend-pg/.eslintrc.js | 42 + backend-pg/.prettierrc | 7 + backend-pg/esbuild.config.js | 20 - backend-pg/nodemon.json | 7 - backend-pg/package-lock.json | 4260 ++++++++++++++++-- backend-pg/package.json | 38 +- backend-pg/src/@types/fastify.d.ts | 19 + backend-pg/src/app.ts | 22 - backend-pg/src/lib/config/env.ts | 28 + backend-pg/src/lib/logger/index.ts | 1 + backend-pg/src/lib/logger/logger.ts | 71 + backend-pg/src/server/app.ts | 77 + backend-pg/src/server/config/rateLimiter.ts | 7 + backend-pg/src/server/plugins/fastify-zod.ts | 142 + backend-pg/src/server/plugins/ip.ts | 31 + backend-pg/src/server/plugins/swagger.ts | 48 + backend-pg/tsconfig.json | 28 +- 17 files changed, 4514 insertions(+), 334 deletions(-) create mode 100644 backend-pg/.eslintrc.js create mode 100644 backend-pg/.prettierrc delete mode 100644 backend-pg/esbuild.config.js delete mode 100644 backend-pg/nodemon.json create mode 100644 backend-pg/src/@types/fastify.d.ts delete mode 100644 backend-pg/src/app.ts create mode 100644 backend-pg/src/lib/config/env.ts create mode 100644 backend-pg/src/lib/logger/index.ts create mode 100644 backend-pg/src/lib/logger/logger.ts create mode 100644 backend-pg/src/server/app.ts create mode 100644 backend-pg/src/server/config/rateLimiter.ts create mode 100644 backend-pg/src/server/plugins/fastify-zod.ts create mode 100644 backend-pg/src/server/plugins/ip.ts create mode 100644 backend-pg/src/server/plugins/swagger.ts diff --git a/backend-pg/.eslintrc.js b/backend-pg/.eslintrc.js new file mode 100644 index 000000000..5d564d416 --- /dev/null +++ b/backend-pg/.eslintrc.js @@ -0,0 +1,42 @@ +module.exports = { + root: true, + env: { + browser: true, + es2021: true + }, + extends: ["airbnb-base", "airbnb-typescript/base", "prettier"], + plugins: ["prettier", "simple-import-sort", "import"], + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + project: "./tsconfig.json", + tsconfigRootDir: __dirname + }, + rules: { + "import/prefer-default-export": "off", + "simple-import-sort/exports": "error", + "import/first": "error", + "import/newline-after-import": "error", + "import/no-duplicates": "error", + "simple-import-sort/imports": [ + "warn", + { + groups: [ + ["^node:", "^[a-z]", "@fastify"], + ["^@app"], + ["@lib"], + ["@server"], + ["^~(/.*|$)"], + ["^\\.\\.(?!/?$)", "^\\.\\./?$", "^\\./(?=.*/)(?!/?$)", "^\\.(?!/?$)", "^\\./?$"] + ] + } + ] + }, + settings: { + "import/resolver": { + typescript: { + project: ["./tsconfig.json"] + } + } + } +}; diff --git a/backend-pg/.prettierrc b/backend-pg/.prettierrc new file mode 100644 index 000000000..0b8ef54d2 --- /dev/null +++ b/backend-pg/.prettierrc @@ -0,0 +1,7 @@ +{ + "singleQuote": false, + "printWidth": 100, + "trailingComma": "none", + "tabWidth": 2, + "semi": true +} diff --git a/backend-pg/esbuild.config.js b/backend-pg/esbuild.config.js deleted file mode 100644 index b99af058d..000000000 --- a/backend-pg/esbuild.config.js +++ /dev/null @@ -1,20 +0,0 @@ -// final prod build -const { build } = require("esbuild"); - -build({ - entryPoints: ["./src/app.ts"], - minify: true, - format: "cjs", - platform: "node", - target: "node20", - bundle: true, - outfile: "dist/index.js", - plugins: [], -}) - .catch((err) => { - console.error(err); - process.exit(1); - }) - .then(() => { - console.log("Finished bundling server.."); - }); diff --git a/backend-pg/nodemon.json b/backend-pg/nodemon.json deleted file mode 100644 index 0dc2014e6..000000000 --- a/backend-pg/nodemon.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "watch": "./src", - "verbose": true, - "ignore": [".git", "node_modules"], - "exec": "node esbuild.config.js && node dist/index.js", - "ext": "ts json" -} diff --git a/backend-pg/package-lock.json b/backend-pg/package-lock.json index 01fcfa72f..a89eb39b6 100644 --- a/backend-pg/package-lock.json +++ b/backend-pg/package-lock.json @@ -9,20 +9,62 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@fastify/cookie": "^9.2.0", + "@fastify/cors": "^8.4.1", + "@fastify/helmet": "^11.1.1", + "@fastify/rate-limit": "^9.0.0", + "@fastify/swagger": "^8.12.0", + "@fastify/swagger-ui": "^1.10.1", + "dotenv": "^16.3.1", + "eslint-config-airbnb-typescript": "^17.1.0", "fastify": "^4.24.3", - "ora": "^7.0.1" + "fastify-plugin": "^4.5.1", + "ora": "^7.0.1", + "pino": "^8.16.2", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.0" }, "devDependencies": { - "@types/node": "^20.9.1", - "esbuild": "^0.19.5", - "nodemon": "^3.0.1", - "typescript": "^5.2.2" + "@types/node": "^20.9.5", + "@typescript-eslint/eslint-plugin": "^6.12.0", + "@typescript-eslint/parser": "^6.12.0", + "eslint": "^8.54.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-prettier": "^9.0.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-simple-import-sort": "^10.0.0", + "pino-pretty": "^10.2.3", + "ts-node": "^10.9.1", + "tsx": "^4.4.0", + "typescript": "^5.3.2" + } + }, + "node_modules/@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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@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==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" } }, "node_modules/@esbuild/android-arm": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.5.tgz", - "integrity": "sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "cpu": [ "arm" ], @@ -36,9 +78,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.5.tgz", - "integrity": "sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "cpu": [ "arm64" ], @@ -52,9 +94,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.5.tgz", - "integrity": "sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "cpu": [ "x64" ], @@ -68,9 +110,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.5.tgz", - "integrity": "sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "cpu": [ "arm64" ], @@ -84,9 +126,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.5.tgz", - "integrity": "sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "cpu": [ "x64" ], @@ -100,9 +142,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.5.tgz", - "integrity": "sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "cpu": [ "arm64" ], @@ -116,9 +158,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.5.tgz", - "integrity": "sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "cpu": [ "x64" ], @@ -132,9 +174,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.5.tgz", - "integrity": "sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "cpu": [ "arm" ], @@ -148,9 +190,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.5.tgz", - "integrity": "sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "cpu": [ "arm64" ], @@ -164,9 +206,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.5.tgz", - "integrity": "sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "cpu": [ "ia32" ], @@ -180,9 +222,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.5.tgz", - "integrity": "sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "cpu": [ "loong64" ], @@ -196,9 +238,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.5.tgz", - "integrity": "sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "cpu": [ "mips64el" ], @@ -212,9 +254,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.5.tgz", - "integrity": "sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "cpu": [ "ppc64" ], @@ -228,9 +270,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.5.tgz", - "integrity": "sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "cpu": [ "riscv64" ], @@ -244,9 +286,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.5.tgz", - "integrity": "sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "cpu": [ "s390x" ], @@ -260,9 +302,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.5.tgz", - "integrity": "sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "cpu": [ "x64" ], @@ -276,9 +318,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.5.tgz", - "integrity": "sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "cpu": [ "x64" ], @@ -292,9 +334,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.5.tgz", - "integrity": "sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "cpu": [ "x64" ], @@ -308,9 +350,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.5.tgz", - "integrity": "sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "cpu": [ "x64" ], @@ -324,9 +366,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.5.tgz", - "integrity": "sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "cpu": [ "arm64" ], @@ -340,9 +382,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.5.tgz", - "integrity": "sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "cpu": [ "ia32" ], @@ -356,9 +398,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.5.tgz", - "integrity": "sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], @@ -371,6 +413,107 @@ "node": ">=12" } }, + "node_modules/@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==", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@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==", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/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==" + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "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==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fastify/accept-negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz", + "integrity": "sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==", + "engines": { + "node": ">=14" + } + }, "node_modules/@fastify/ajv-compiler": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz", @@ -381,6 +524,24 @@ "fast-uri": "^2.0.0" } }, + "node_modules/@fastify/cookie": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@fastify/cookie/-/cookie-9.2.0.tgz", + "integrity": "sha512-fkg1yjjQRHPFAxSHeLC8CqYuNzvR6Lwlj/KjrzQcGjNBK+K82nW+UfCjfN71g1GkoVoc1GTOgIWkFJpcMfMkHQ==", + "dependencies": { + "cookie-signature": "^1.1.0", + "fastify-plugin": "^4.0.0" + } + }, + "node_modules/@fastify/cors": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@fastify/cors/-/cors-8.4.1.tgz", + "integrity": "sha512-iYQJtrY3pFiDS5mo5zRaudzg2OcUdJ96PD6xfkKOOEilly5nnrFZx/W6Sce2T79xxlEn2qpU3t5+qS2phS369w==", + "dependencies": { + "fastify-plugin": "^4.0.0", + "mnemonist": "0.39.5" + } + }, "node_modules/@fastify/deepmerge": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@fastify/deepmerge/-/deepmerge-1.3.0.tgz", @@ -399,20 +560,746 @@ "fast-json-stringify": "^5.7.0" } }, + "node_modules/@fastify/helmet": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@fastify/helmet/-/helmet-11.1.1.tgz", + "integrity": "sha512-pjJxjk6SLEimITWadtYIXt6wBMfFC1I6OQyH/jYVCqSAn36sgAIFjeNiibHtifjCd+e25442pObis3Rjtame6A==", + "dependencies": { + "fastify-plugin": "^4.2.1", + "helmet": "^7.0.0" + } + }, + "node_modules/@fastify/rate-limit": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@fastify/rate-limit/-/rate-limit-9.0.0.tgz", + "integrity": "sha512-Gt5NXYyidUY47yO0QFvwwVwolbpFcq8Y6wSL0iV8v29IdUQVKhE9hcJE5N48LdnhTQDBdLiZDiR7nV4niMfOWw==", + "dependencies": { + "@lukeed/ms": "^2.0.1", + "fastify-plugin": "^4.0.0", + "toad-cache": "^3.3.0" + } + }, + "node_modules/@fastify/send": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz", + "integrity": "sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==", + "dependencies": { + "@lukeed/ms": "^2.0.1", + "escape-html": "~1.0.3", + "fast-decode-uri-component": "^1.0.1", + "http-errors": "2.0.0", + "mime": "^3.0.0" + } + }, + "node_modules/@fastify/static": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@fastify/static/-/static-6.12.0.tgz", + "integrity": "sha512-KK1B84E6QD/FcQWxDI2aiUCwHxMJBI1KeCUzm1BwYpPY1b742+jeKruGHP2uOluuM6OkBPI8CIANrXcCRtC2oQ==", + "dependencies": { + "@fastify/accept-negotiator": "^1.0.0", + "@fastify/send": "^2.0.0", + "content-disposition": "^0.5.3", + "fastify-plugin": "^4.0.0", + "glob": "^8.0.1", + "p-limit": "^3.1.0" + } + }, + "node_modules/@fastify/swagger": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/@fastify/swagger/-/swagger-8.12.0.tgz", + "integrity": "sha512-IMRc0xYuzRvtFDMuaWHyVbvM7CuAi0g3o2jaVgLDvETXPrXWAMWsHYR5niIdWBDPgGUq+soHkag1DKXyhPDB0w==", + "dependencies": { + "fastify-plugin": "^4.0.0", + "json-schema-resolver": "^2.0.0", + "openapi-types": "^12.0.0", + "rfdc": "^1.3.0", + "yaml": "^2.2.2" + } + }, + "node_modules/@fastify/swagger-ui": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@fastify/swagger-ui/-/swagger-ui-1.10.1.tgz", + "integrity": "sha512-u3EJqNKvVr3X+6jY5i6pbs6/tXCrSlqc2Y+PVjnHBTOGh/d36uHMz+z4jPFy9gie2my6iHUrAdM8itlVmoUjog==", + "dependencies": { + "@fastify/static": "^6.0.0", + "fastify-plugin": "^4.0.0", + "openapi-types": "^12.0.2", + "rfdc": "^1.3.0", + "yaml": "^2.2.2" + } + }, + "node_modules/@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==", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@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==" + }, + "node_modules/@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==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@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==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@lukeed/ms": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.1.tgz", + "integrity": "sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@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==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@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==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@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==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@swc/core": { + "version": "1.3.99", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.99.tgz", + "integrity": "sha512-8O996RfuPC4ieb4zbYMfbyCU9k4gSOpyCNnr7qBQ+o7IEmh8JCV6B8wwu+fT/Om/6Lp34KJe1IpJ/24axKS6TQ==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "@swc/counter": "^0.1.1", + "@swc/types": "^0.1.5" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.99", + "@swc/core-darwin-x64": "1.3.99", + "@swc/core-linux-arm64-gnu": "1.3.99", + "@swc/core-linux-arm64-musl": "1.3.99", + "@swc/core-linux-x64-gnu": "1.3.99", + "@swc/core-linux-x64-musl": "1.3.99", + "@swc/core-win32-arm64-msvc": "1.3.99", + "@swc/core-win32-ia32-msvc": "1.3.99", + "@swc/core-win32-x64-msvc": "1.3.99" + }, + "peerDependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.99", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.99.tgz", + "integrity": "sha512-Qj7Jct68q3ZKeuJrjPx7k8SxzWN6PqLh+VFxzA+KwLDpQDPzOlKRZwkIMzuFjLhITO4RHgSnXoDk/Syz0ZeN+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.3.99", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.99.tgz", + "integrity": "sha512-wR7m9QVJjgiBu1PSOHy7s66uJPa45Kf9bZExXUL+JAa9OQxt5y+XVzr+n+F045VXQOwdGWplgPnWjgbUUHEVyw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.99", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.99.tgz", + "integrity": "sha512-gcGv1l5t0DScEONmw5OhdVmEI/o49HCe9Ik38zzH0NtDkc+PDYaCcXU5rvfZP2qJFaAAr8cua8iJcOunOSLmnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.99", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.99.tgz", + "integrity": "sha512-XL1/eUsTO8BiKsWq9i3iWh7H99iPO61+9HYiWVKhSavknfj4Plbn+XyajDpxsauln5o8t+BRGitymtnAWJM4UQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.99", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.99.tgz", + "integrity": "sha512-fGrXYE6DbTfGNIGQmBefYxSk3rp/1lgbD0nVg4rl4mfFRQPi7CgGhrrqSuqZ/ezXInUIgoCyvYGWFSwjLXt/Qg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.99", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.99.tgz", + "integrity": "sha512-kvgZp/mqf3IJ806gUOL6gN6VU15+DfzM1Zv4Udn8GqgXiUAvbQehrtruid4Snn5pZTLj4PEpSCBbxgxK1jbssA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.99", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.99.tgz", + "integrity": "sha512-yt8RtZ4W/QgFF+JUemOUQAkVW58cCST7mbfKFZ1v16w3pl3NcWd9OrtppFIXpbjU1rrUX2zp2R7HZZzZ2Zk/aQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.99", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.99.tgz", + "integrity": "sha512-62p5fWnOJR/rlbmbUIpQEVRconICy5KDScWVuJg1v3GPLBrmacjphyHiJC1mp6dYvvoEWCk/77c/jcQwlXrDXw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.99", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.99.tgz", + "integrity": "sha512-PdppWhkoS45VGdMBxvClVgF1hVjqamtvYd82Gab1i4IV45OSym2KinoDCKE1b6j3LwBLOn2J9fvChGSgGfDCHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz", + "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@swc/helpers": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz", + "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@swc/types": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", + "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@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==", + "dev": true + }, + "node_modules/@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==" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" + }, "node_modules/@types/node": { - "version": "20.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.1.tgz", - "integrity": "sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==", + "version": "20.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.5.tgz", + "integrity": "sha512-Uq2xbNq0chGg+/WQEU0LJTSs/1nKxz6u1iemLcGomkSnKokbW1fbLqc3HOqCf2JP7KjlL4QkS7oZZTrOQHQYgQ==", "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, - "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==", - "dev": true + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz", + "integrity": "sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA==", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/type-utils": "6.12.0", + "@typescript-eslint/utils": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.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" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.12.0.tgz", + "integrity": "sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg==", + "dependencies": { + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz", + "integrity": "sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw==", + "dependencies": { + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.12.0.tgz", + "integrity": "sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng==", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/utils": "6.12.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@typescript-eslint/types": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.12.0.tgz", + "integrity": "sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q==", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz", + "integrity": "sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw==", + "dependencies": { + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/visitor-keys": "6.12.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.12.0.tgz", + "integrity": "sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.12.0", + "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/typescript-estree": "6.12.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz", + "integrity": "sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw==", + "dependencies": { + "@typescript-eslint/types": "6.12.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@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==" }, "node_modules/abort-controller": { "version": "3.0.0", @@ -430,6 +1317,34 @@ "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", @@ -472,17 +1387,18 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/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, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 8" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/archy": { @@ -490,6 +1406,127 @@ "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==" }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", @@ -498,6 +1535,17 @@ "node": ">=8.0.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/avvio": { "version": "8.2.1", "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.2.1.tgz", @@ -532,8 +1580,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -554,13 +1601,13 @@ } ] }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.6" } }, "node_modules/bl": { @@ -586,11 +1633,22 @@ "node": ">= 6" } }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -600,7 +1658,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -631,6 +1688,42 @@ "ieee754": "^1.2.1" } }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/chalk": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", @@ -642,33 +1735,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.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" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -694,11 +1760,48 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/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==" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" + }, + "node_modules/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==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } }, "node_modules/cookie": { "version": "0.5.0", @@ -708,15 +1811,180 @@ "node": ">= 0.6" } }, + "node_modules/cookie-signature": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.1.tgz", + "integrity": "sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/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==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, "dependencies": { "ms": "^2.1.1" } }, + "node_modules/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==" + }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -727,10 +1995,121 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==" }, + "node_modules/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==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/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, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/esbuild": { - "version": "0.19.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.5.tgz", - "integrity": "sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "hasInstallScript": true, "bin": { @@ -740,28 +2119,518 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.19.5", - "@esbuild/android-arm64": "0.19.5", - "@esbuild/android-x64": "0.19.5", - "@esbuild/darwin-arm64": "0.19.5", - "@esbuild/darwin-x64": "0.19.5", - "@esbuild/freebsd-arm64": "0.19.5", - "@esbuild/freebsd-x64": "0.19.5", - "@esbuild/linux-arm": "0.19.5", - "@esbuild/linux-arm64": "0.19.5", - "@esbuild/linux-ia32": "0.19.5", - "@esbuild/linux-loong64": "0.19.5", - "@esbuild/linux-mips64el": "0.19.5", - "@esbuild/linux-ppc64": "0.19.5", - "@esbuild/linux-riscv64": "0.19.5", - "@esbuild/linux-s390x": "0.19.5", - "@esbuild/linux-x64": "0.19.5", - "@esbuild/netbsd-x64": "0.19.5", - "@esbuild/openbsd-x64": "0.19.5", - "@esbuild/sunos-x64": "0.19.5", - "@esbuild/win32-arm64": "0.19.5", - "@esbuild/win32-ia32": "0.19.5", - "@esbuild/win32-x64": "0.19.5" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/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==" + }, + "node_modules/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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", + "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", + "dependencies": { + "@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.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-config-airbnb-base/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/eslint-config-airbnb-typescript": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", + "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", + "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", + "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/eslint-plugin-import/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/eslint-plugin-import/node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", + "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz", + "integrity": "sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "node_modules/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==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/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==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/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==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/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==" + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" } }, "node_modules/event-target-shim": { @@ -780,11 +2649,67 @@ "node": ">=0.8.x" } }, + "node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/fast-content-type-parse": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==" }, + "node_modules/fast-copy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.1.tgz", + "integrity": "sha512-Knr7NOtK3HWRYGtHoJrjkaWepqT8thIVGAwt0p0aUs1zqkAzXZV4vo9fFNwyb5fcqK1GKYFYxldQdIDVKhUAfA==", + "dev": true + }, "node_modules/fast-decode-uri-component": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", @@ -795,6 +2720,32 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/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==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/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==" + }, "node_modules/fast-json-stringify": { "version": "5.9.1", "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.9.1.tgz", @@ -809,6 +2760,11 @@ "rfdc": "^1.2.0" } }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, "node_modules/fast-querystring": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", @@ -825,6 +2781,12 @@ "node": ">=6" } }, + "node_modules/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==", + "dev": true + }, "node_modules/fast-uri": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.3.0.tgz", @@ -853,6 +2815,11 @@ "toad-cache": "^3.3.0" } }, + "node_modules/fastify-plugin": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.1.tgz", + "integrity": "sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==" + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -861,11 +2828,21 @@ "reusify": "^1.0.4" } }, + "node_modules/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==", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/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, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -886,6 +2863,47 @@ "node": ">=14" } }, + "node_modules/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==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==" + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -894,6 +2912,11 @@ "node": ">= 0.6" } }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -908,11 +2931,114 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", + "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/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, "dependencies": { "is-glob": "^4.0.1" }, @@ -920,13 +3046,214 @@ "node": ">= 6" } }, - "node_modules/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==", + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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 + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/helmet": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", + "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/help-me": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-4.2.0.tgz", + "integrity": "sha512-TAOnTB8Tz5Dw8penUuzHVrKNKlCIbwwbHnXraNJxPwf8LRtE2HlM84RYuezMFcwOJmoYOCWVDyJ8TQGxn9PgxA==", + "dev": true, + "dependencies": { + "glob": "^8.0.0", + "readable-stream": "^3.6.0" + } + }, + "node_modules/help-me/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==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/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==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=14.18.0" } }, "node_modules/ieee754": { @@ -948,17 +3275,64 @@ } ] }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -967,23 +3341,100 @@ "node": ">= 0.10" } }, - "node_modules/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, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", "dependencies": { - "binary-extensions": "^2.0.0" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -992,7 +3443,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -1000,6 +3450,24 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", @@ -1011,15 +3479,127 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/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, "engines": { "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-unicode-supported": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", @@ -1031,6 +3611,79 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/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==" + }, "node_modules/json-schema-ref-resolver": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz", @@ -1039,11 +3692,73 @@ "fast-deep-equal": "^3.1.3" } }, + "node_modules/json-schema-resolver": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/json-schema-resolver/-/json-schema-resolver-2.0.0.tgz", + "integrity": "sha512-pJ4XLQP4Q9HTxl6RVDLJ8Cyh1uitSs0CzDBAz1uoJ4sRD/Bk7cFSXL1FUXDW3zJ7YnfliJx6eu8Jn283bpZ4Yg==", + "dependencies": { + "debug": "^4.1.1", + "rfdc": "^1.1.4", + "uri-js": "^4.2.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/Eomm/json-schema-resolver?sponsor=1" + } + }, + "node_modules/json-schema-resolver/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/json-schema-resolver/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/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==" }, + "node_modules/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==" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/light-my-request": { "version": "5.11.0", "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.11.0.tgz", @@ -1054,6 +3769,25 @@ "set-cookie-parser": "^2.4.1" } }, + "node_modules/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==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==" + }, "node_modules/log-symbols": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", @@ -1080,6 +3814,49 @@ "node": ">=10" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/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 + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -1092,7 +3869,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1100,64 +3876,153 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mnemonist": { + "version": "0.39.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.5.tgz", + "integrity": "sha512-FPUtkhtJ0efmEFGpU14x7jGbTB+s18LrzRL2KgoWz9YvcY3cPomz8tih01GbHwnGk/OmkOKfqd/RAQoc8Lm7DQ==", + "dependencies": { + "obliterator": "^2.0.1" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/nodemon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", - "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "dependencies": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" + "path-key": "^4.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" }, "engines": { - "node": "*" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/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, + "node_modules/object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==" + }, "node_modules/on-exit-leak-free": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", @@ -1166,6 +4031,14 @@ "node": ">=14.0.0" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -1180,6 +4053,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==" + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dependencies": { + "@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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/ora": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz", @@ -1202,11 +4114,92 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/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==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -1244,11 +4237,72 @@ "split2": "^4.0.0" } }, + "node_modules/pino-pretty": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-10.2.3.tgz", + "integrity": "sha512-4jfIUc8TC1GPUfDyMSlW1STeORqkoxec71yhxIpLDQapUu8WOuoz2TTCoidrIssyz78LZC69whBMPIKCMbi3cw==", + "dev": true, + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^4.0.1", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.0.0", + "pump": "^3.0.0", + "readable-stream": "^4.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, "node_modules/pino-std-serializers": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==" }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", + "dev": true, + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -1274,11 +4328,15 @@ "node": ">= 0.10" } }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } }, "node_modules/punycode": { "version": "2.3.1", @@ -1288,6 +4346,25 @@ "node": ">=6" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/quick-format-unescaped": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", @@ -1308,18 +4385,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/real-require": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", @@ -1328,6 +4393,22 @@ "node": ">= 12.13.0" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -1336,6 +4417,39 @@ "node": ">=0.10.0" } }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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==", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/restore-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", @@ -1373,6 +4487,158 @@ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/run-applescript/node_modules/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, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/run-applescript/node_modules/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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/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, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/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, + "engines": { + "node": ">=6" + } + }, + "node_modules/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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1392,6 +4658,19 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-regex2": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", @@ -1432,21 +4711,81 @@ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" }, + "node_modules/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==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/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==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "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==" }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "engines": { - "node": ">=10" + "node": ">=8" } }, "node_modules/sonic-boom": { @@ -1465,6 +4804,14 @@ "node": ">= 10.x" } }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/stdin-discarder": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", @@ -1503,6 +4850,48 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -1517,18 +4906,78 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/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, - "dependencies": { - "has-flag": "^3.0.0" - }, + "node_modules/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==", "engines": { "node": ">=4" } }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/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==" + }, "node_modules/thread-stream": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.4.1.tgz", @@ -1537,11 +4986,22 @@ "real-require": "^0.2.0" } }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/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, "dependencies": { "is-number": "^7.0.0" }, @@ -1557,23 +5017,180 @@ "node": ">=12" } }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/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==", + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "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==", "dev": true, "dependencies": { - "nopt": "~1.0.10" + "@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" }, "bin": { - "nodetouch": "bin/nodetouch.js" + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/tsx": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.4.0.tgz", + "integrity": "sha512-4fwcEjRUxW20ciSaMB8zkpGwCPxuRGnadDuj/pBk5S9uT29zvWz15PK36GrKJo45mSJomDxVejZ73c6lr3811Q==", + "dev": true, + "dependencies": { + "esbuild": "~0.18.20", + "get-tsconfig": "^4.7.2" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "dev": true, + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", + "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -1582,11 +5199,19 @@ "node": ">=14.17" } }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/undici-types": { "version": "5.26.5", @@ -1594,6 +5219,15 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -1607,10 +5241,112 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/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==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, "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/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.0.tgz", + "integrity": "sha512-XQr8EwxPMzJGhoR+d/nRFWdi15VaZ+R5Uhssm+Xx5yS30xCpuutfKRm4rerE0SK9j2dWB5Z3FvDD0w8WMVGzkA==", + "peerDependencies": { + "zod": "^3.22.4" + } } } } diff --git a/backend-pg/package.json b/backend-pg/package.json index 15a3d47d7..5ec5e63aa 100644 --- a/backend-pg/package.json +++ b/backend-pg/package.json @@ -5,20 +5,44 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build": "node esbuild.config.js", - "dev": "nodemon" + "dev": "tsx watch --clear-screen=false ./src/server/app.ts | pino-pretty --colorize --colorizeObjects --singleLine", + "type:check": "tsc --noEmit", + "lint:fix": "eslint --fix 'src/**/*.ts'", + "lint": "eslint 'src/**/*.ts'" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { - "@types/node": "^20.9.1", - "esbuild": "^0.19.5", - "nodemon": "^3.0.1", - "typescript": "^5.2.2" + "@types/node": "^20.9.5", + "@typescript-eslint/eslint-plugin": "^6.12.0", + "@typescript-eslint/parser": "^6.12.0", + "eslint": "^8.54.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-prettier": "^9.0.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-simple-import-sort": "^10.0.0", + "pino-pretty": "^10.2.3", + "ts-node": "^10.9.1", + "tsx": "^4.4.0", + "typescript": "^5.3.2" }, "dependencies": { + "@fastify/cookie": "^9.2.0", + "@fastify/cors": "^8.4.1", + "@fastify/helmet": "^11.1.1", + "@fastify/rate-limit": "^9.0.0", + "@fastify/swagger": "^8.12.0", + "@fastify/swagger-ui": "^1.10.1", + "dotenv": "^16.3.1", + "eslint-config-airbnb-typescript": "^17.1.0", "fastify": "^4.24.3", - "ora": "^7.0.1" + "fastify-plugin": "^4.5.1", + "ora": "^7.0.1", + "pino": "^8.16.2", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.0" } } diff --git a/backend-pg/src/@types/fastify.d.ts b/backend-pg/src/@types/fastify.d.ts new file mode 100644 index 000000000..78cd61af4 --- /dev/null +++ b/backend-pg/src/@types/fastify.d.ts @@ -0,0 +1,19 @@ +import { ZodTypeProvider } from "@app/server/plugins/fastify-zod"; + +import "fastify"; + +declare module "fastify" { + interface FastifyRequest { + realIp: string; + } +} + +declare global { + type FastifyZodProvider = FastifyInstance< + RawServerDefault, + RawRequestDefaultExpression, + RawReplyDefaultExpression, + FastifyBaseLogger, + ZodTypeProvider + >; +} diff --git a/backend-pg/src/app.ts b/backend-pg/src/app.ts deleted file mode 100644 index 0a6669343..000000000 --- a/backend-pg/src/app.ts +++ /dev/null @@ -1,22 +0,0 @@ -import Fasitfy from "fastify"; - -const fastify = Fasitfy({ - logger: true, -}); - -// Declare a route -fastify.get("/", async function handler(_request, _reply) { - return { hello: "world changed" }; -}); - -// Run the server! -const main = async () => { - try { - await fastify.listen({ port: 8000 }); - } catch (err) { - fastify.log.error(err); - process.exit(1); - } -}; - -main(); diff --git a/backend-pg/src/lib/config/env.ts b/backend-pg/src/lib/config/env.ts new file mode 100644 index 000000000..5f7217e03 --- /dev/null +++ b/backend-pg/src/lib/config/env.ts @@ -0,0 +1,28 @@ +import { Logger } from "pino"; +import { z } from "zod"; + +const envSchema = z.object({ + NODE_ENV: z.enum(["development", "test", "production"]).default("development"), + SALT_ROUNDS: z.coerce.number().default(10), + // TODO(akhilmhdh): will be changed to one + ENCRYPTION_KEY: z.string().optional(), + ROOT_ENCRYPTION_KEY: z.string().optional(), + HTTPS_ENABLED: z + .enum(["true", "false"]) + .optional() + .transform((val) => val === "true") +}); + +let envCfg: Readonly>; + +export const getConfig = () => envCfg; +// cannot import singleton logger directly as it needs config to load various transport +export const initEnvConfig = (logger: Logger) => { + const parsedEnv = envSchema.safeParse(process.env); + if (!parsedEnv.success) { + logger.error("Invalid environment variables. Check the error below"); + logger.error(parsedEnv.error); + process.exit(-1); + } + envCfg = Object.freeze(parsedEnv.data); +}; diff --git a/backend-pg/src/lib/logger/index.ts b/backend-pg/src/lib/logger/index.ts new file mode 100644 index 000000000..df012e434 --- /dev/null +++ b/backend-pg/src/lib/logger/index.ts @@ -0,0 +1 @@ +export { initLogger,logger } from "./logger"; diff --git a/backend-pg/src/lib/logger/logger.ts b/backend-pg/src/lib/logger/logger.ts new file mode 100644 index 000000000..e04f82cc7 --- /dev/null +++ b/backend-pg/src/lib/logger/logger.ts @@ -0,0 +1,71 @@ +// logger follows a singleton pattern +// easier to use it that's all. +import pino, { Logger } from "pino"; +import { z } from "zod"; + +const logLevelToSeverityLookup: Record = { + "10": "TRACE", + "20": "DEBUG", + "30": "INFO", + "40": "WARNING", + "50": "ERROR", + "60": "CRITICAL" +}; + +// eslint-disable-next-line import/no-mutable-exports +export let logger: Readonly; +// akhilmhdh: why this instead of putting it in config right +// reason is to avoid a cyclical condition +// config needs logger to output error when invalid environment is provided +// logger needs config to get aws or other transport cred +// this would make logger independent package +const loggerConfig = z.object({ + AWS_CLOUDWATCH_LOG_GROUP_NAME: z.string().default("infisical-log-stream"), + AWS_CLOUDWATCH_LOG_REGION: z.string().default("us-east-1"), + AWS_CLOUDWATCH_LOG_ACCESS_KEY_ID: z.string().min(1).optional(), + AWS_CLOUDWATCH_LOG_ACCESS_KEY_SECRET: z.string().min(1).optional(), + AWS_CLOUDWATCH_LOG_INTERVAL: z.coerce.number().default(1000) +}); + +export const initLogger = async () => { + const targets: pino.TransportMultiOptions["targets"][number][] = [ + { level: "info", target: "pino/file", options: {} } + ]; + const cfg = loggerConfig.parse(process.env); + if (cfg.AWS_CLOUDWATCH_LOG_ACCESS_KEY_ID && cfg.AWS_CLOUDWATCH_LOG_ACCESS_KEY_SECRET) { + targets.push({ + target: "@serdnam/pino-cloudwatch-transport", + level: "info", + options: { + logGroupName: cfg.AWS_CLOUDWATCH_LOG_GROUP_NAME, + logStreamName: cfg.AWS_CLOUDWATCH_LOG_GROUP_NAME, + awsRegion: cfg.AWS_CLOUDWATCH_LOG_REGION, + awsAccessKeyId: cfg.AWS_CLOUDWATCH_LOG_ACCESS_KEY_ID, + awsSecretAccessKey: cfg.AWS_CLOUDWATCH_LOG_ACCESS_KEY_SECRET, + interval: cfg.AWS_CLOUDWATCH_LOG_INTERVAL + } + }); + } + + const transport = pino.transport({ + targets + }); + + logger = pino( + { + mixin(_context, level) { + return { severity: logLevelToSeverityLookup[level] || logLevelToSeverityLookup["30"] }; + }, + level: process.env.PINO_LOG_LEVEL || "info", + formatters: { + bindings: (bindings) => ({ + pid: bindings.pid, + hostname: bindings.hostname + // node_version: process.version + }) + } + }, + transport + ); + return logger; +}; diff --git a/backend-pg/src/server/app.ts b/backend-pg/src/server/app.ts new file mode 100644 index 000000000..079b25157 --- /dev/null +++ b/backend-pg/src/server/app.ts @@ -0,0 +1,77 @@ +import dotenv from "dotenv"; +import fasitfy from "fastify"; +import { z } from "zod"; +import type { FastifyCookieOptions } from "@fastify/cookie"; +import cookie from "@fastify/cookie"; +import type { FastifyCorsOptions } from "@fastify/cors"; +import cors from "@fastify/cors"; +import helmet from "@fastify/helmet"; +import type { FastifyRateLimitOptions } from "@fastify/rate-limit"; +import ratelimiter from "@fastify/rate-limit"; + +import { initEnvConfig } from "@lib/config/env"; +import { initLogger } from "@lib/logger"; + +import { globalRateLimiterCfg } from "./config/rateLimiter"; +import { serializerCompiler, validatorCompiler, ZodTypeProvider } from "./plugins/fastify-zod"; +import { fastifyIp } from "./plugins/ip"; +import { fastifySwagger } from "./plugins/swagger"; + +dotenv.config(); + +// Run the server! +const main = async () => { + const logger = await initLogger(); + initEnvConfig(logger); + + const server = fasitfy({ + logger, + trustProxy: true + }).withTypeProvider(); + + server.setValidatorCompiler(validatorCompiler); + server.setSerializerCompiler(serializerCompiler); + + try { + // TODO(akhilmhdh:pg): change this to environment variable with default + await server.register(cookie, { + secret: "infisical-cookie-secret" + }); + + await server.register(cors, { + credentials: true, + origin: "http://localhost:3000" + }); + // pull ip based on various proxy headers + await server.register(fastifyIp); + + // Rate limiters and security headers + await server.register(ratelimiter, globalRateLimiterCfg); + await server.register(helmet); + + await server.register(fastifySwagger); + + // Declare a route + server.route({ + method: "GET", + url: "/", + schema: { + response: { + 200: z.object({ hello: z.string() }) + } + }, + handler: () => ({ + hello: "world" + }) + }); + + await server.ready(); + server.swagger(); + await server.listen({ port: 8000 }); + } catch (err) { + server.log.error(err); + process.exit(1); + } +}; + +main(); diff --git a/backend-pg/src/server/config/rateLimiter.ts b/backend-pg/src/server/config/rateLimiter.ts new file mode 100644 index 000000000..e2f99c7e7 --- /dev/null +++ b/backend-pg/src/server/config/rateLimiter.ts @@ -0,0 +1,7 @@ +import type { RateLimitOptions } from "@fastify/rate-limit"; + +export const globalRateLimiterCfg: RateLimitOptions = { + timeWindow: 60 * 1000, + max: 100, + keyGenerator: (req) => req.realIp +}; diff --git a/backend-pg/src/server/plugins/fastify-zod.ts b/backend-pg/src/server/plugins/fastify-zod.ts new file mode 100644 index 000000000..02636a066 --- /dev/null +++ b/backend-pg/src/server/plugins/fastify-zod.ts @@ -0,0 +1,142 @@ +/* eslint-disable */ +// Code taken from https://www.npmjs.com/package/fastify-type-provider-zod +// Full credits goes to https://github.com/turkerdev +// Code taken to keep in in house +import type { FastifySchema, FastifySchemaCompiler, FastifyTypeProvider } from "fastify"; +import type { FastifySerializerCompiler } from "fastify/types/schema"; +import type { z, ZodAny, ZodTypeAny } from "zod"; +import { zodToJsonSchema } from "zod-to-json-schema"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type FreeformRecord = Record; + +const defaultSkipList = [ + "/documentation/", + "/documentation/initOAuth", + "/documentation/json", + "/documentation/uiConfig", + "/documentation/yaml", + "/documentation/*", + "/documentation/static/*" +]; + +export interface ZodTypeProvider extends FastifyTypeProvider { + output: this["input"] extends ZodTypeAny ? z.infer : never; +} + +interface Schema extends FastifySchema { + hide?: boolean; +} + +const zodToJsonSchemaOptions = { + target: "openApi3", + $refStrategy: "none" +} as const; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function hasOwnProperty(obj: T, prop: K): obj is T & Record { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +function resolveSchema(maybeSchema: ZodAny | { properties: ZodAny }): Pick { + if (hasOwnProperty(maybeSchema, "safeParse")) { + return maybeSchema; + } + if (hasOwnProperty(maybeSchema, "properties")) { + return maybeSchema.properties; + } + throw new Error(`Invalid schema passed: ${JSON.stringify(maybeSchema)}`); +} + +export const createJsonSchemaTransform = ({ skipList }: { skipList: readonly string[] }) => { + return ({ schema, url }: { schema: Schema; url: string }) => { + if (!schema) { + return { + schema, + url + }; + } + + const { response, headers, querystring, body, params, hide, ...rest } = schema; + + const transformed: FreeformRecord = {}; + + if (skipList.includes(url) || hide) { + transformed.hide = true; + return { schema: transformed, url }; + } + + const zodSchemas: FreeformRecord = { headers, querystring, body, params }; + + for (const prop in zodSchemas) { + const zodSchema = zodSchemas[prop]; + if (zodSchema) { + transformed[prop] = zodToJsonSchema(zodSchema, zodToJsonSchemaOptions); + } + } + + if (response) { + transformed.response = {}; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + for (const prop in response as any) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const schema = resolveSchema((response as any)[prop]); + + const transformedResponse = zodToJsonSchema( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + schema as any, + zodToJsonSchemaOptions + ); + transformed.response[prop] = transformedResponse; + } + } + + for (const prop in rest) { + const meta = rest[prop as keyof typeof rest]; + if (meta) { + transformed[prop] = meta; + } + } + + return { schema: transformed, url }; + }; +}; + +export const jsonSchemaTransform = createJsonSchemaTransform({ + skipList: defaultSkipList +}); + +export const validatorCompiler: FastifySchemaCompiler = + ({ schema }) => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (data): any => { + try { + return { value: schema.parse(data) }; + } catch (error) { + return { error }; + } + }; + +export class ResponseValidationError extends Error { + public details: FreeformRecord; + + constructor(validationResult: FreeformRecord) { + super("Response doesn't match the schema"); + this.name = "ResponseValidationError"; + this.details = validationResult.error; + } +} + +export const serializerCompiler: FastifySerializerCompiler = + ({ schema: maybeSchema }) => + (data) => { + const schema: Pick = resolveSchema(maybeSchema); + + const result = schema.safeParse(data); + if (result.success) { + return JSON.stringify(result.data); + } + + throw new ResponseValidationError(result); + }; diff --git a/backend-pg/src/server/plugins/ip.ts b/backend-pg/src/server/plugins/ip.ts new file mode 100644 index 000000000..d43bf8d70 --- /dev/null +++ b/backend-pg/src/server/plugins/ip.ts @@ -0,0 +1,31 @@ +import fp from "fastify-plugin"; + +/*! https://github.com/pbojinov/request-ip/blob/9501cdf6e73059cc70fc6890adb086348d7cca46/src/index.js. + MIT License. 2022 Petar Bojinov - petarbojinov+github@gmail.com */ +const headersOrder = [ + "x-client-ip", // Most common + "x-forwarded-for", // Mostly used by proxies + "cf-connecting-ip", // Cloudflare + "Cf-Pseudo-IPv4", // Cloudflare + "fastly-client-ip", + "true-client-ip", // Akamai and Cloudflare + "x-real-ip", // Nginx + "x-cluser-client-ip", // Rackspace LB + "forwarded-for", + "x-forwarded", + "forwarded", + "x-appengine-user-ip" // GCP App Engine +]; + +export const fastifyIp = fp(async (fastify) => { + fastify.decorateRequest("realIp", null); + fastify.addHook("onRequest", async (req) => { + const forwardedIpHeader = headersOrder.find((header) => Boolean(req.headers[header])); + const forwardedIp = forwardedIpHeader ? req.headers[forwardedIpHeader] : undefined; + if (forwardedIp) { + req.realIp = Array.isArray(forwardedIp) ? forwardedIp[0] : forwardedIp; + } else { + req.realIp = req.ip; + } + }); +}); diff --git a/backend-pg/src/server/plugins/swagger.ts b/backend-pg/src/server/plugins/swagger.ts new file mode 100644 index 000000000..008994da6 --- /dev/null +++ b/backend-pg/src/server/plugins/swagger.ts @@ -0,0 +1,48 @@ +import fp from "fastify-plugin"; +import swagger from "@fastify/swagger"; +import swaggerUI from "@fastify/swagger-ui"; + +import { jsonSchemaTransform } from "./fastify-zod"; + +export const fastifySwagger = fp(async (fastify) => { + await fastify.register(swagger, { + transform: jsonSchemaTransform, + openapi: { + info: { + title: "Infisical API", + description: "List of all available APIs that can be consumed", + version: "0.0.1" + }, + servers: [ + { + url: "https://app.infisical.com", + description: "Production server" + }, + { + url: "http://localhost:8000", + description: "Local server" + } + ], + components: { + securitySchemes: { + bearer: { + type: "http", + scheme: "bearer", + bearerFormat: "JWT", + description: "A service token in Infisical" + }, + apiKey: { + type: "apiKey", + in: "header", + name: "X-API-Key", + description: "An API Key in Infisical" + } + } + } + } + }); + + await fastify.register(swaggerUI, { + routePrefix: "/docs" + }); +}); diff --git a/backend-pg/tsconfig.json b/backend-pg/tsconfig.json index 0246faa87..9dccf2f1d 100644 --- a/backend-pg/tsconfig.json +++ b/backend-pg/tsconfig.json @@ -1,31 +1,27 @@ { "compilerOptions": { "target": "esnext", - "module": "esnext", + "module": "commonjs", "allowJs": true, - "removeComments": true, "resolveJsonModule": true, - "typeRoots": [ - "./node_modules/@types" - ], + "typeRoots": ["./node_modules/@types", "./src/@types"], "sourceMap": true, "outDir": "dist", "strict": true, - "lib": [ - "esnext" - ], - "baseUrl": ".", + "lib": ["esnext"], "forceConsistentCasingInFileNames": true, "esModuleInterop": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, "moduleResolution": "Node", - "skipLibCheck": true + "skipLibCheck": true, + "baseUrl": ".", + "paths": { + "@app/*": ["./src/*"], + "@lib/*": ["./src/lib/*"], + "@server/*": ["./src/server/*"] + } }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules" - ] + "include": ["src/**/*"], + "exclude": ["node_modules"] } From fcfd6b3fb2d421eed31d3950573ec7218d0e784e Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Mon, 4 Dec 2023 14:48:11 +0530 Subject: [PATCH 003/185] feat(infisical-pg): completed signup, login, password and backup key migration --- backend-pg/.dockerignore | 11 + backend-pg/Dockerfile.dev | 14 + backend-pg/nodemon.json | 6 + backend-pg/package-lock.json | 1309 ++++++ backend-pg/package.json | 24 +- backend-pg/scripts/create-backend-file.ts | 81 + backend-pg/scripts/create-migration.ts | 15 + backend-pg/src/@types/fastify-zod.d.ts | 19 + backend-pg/src/@types/fastify.d.ts | 35 +- backend-pg/src/@types/knex.d.ts | 43 + backend-pg/src/db/index.ts | 2 + backend-pg/src/db/instance.ts | 11 + backend-pg/src/db/knexfile.ts | 24 + .../src/db/migrations/20231128072457_user.ts | 37 + .../20231128092347_user-encryption-key.ts | 31 + .../migrations/20231129072939_auth-token.ts | 24 + .../20231130072734_auth-token-session.ts | 29 + .../migrations/20231201151432_backup-key.ts | 26 + .../src/db/schemas/backup-private-key.ts | 21 + backend-pg/src/db/schemas/index.ts | 15 + backend-pg/src/db/schemas/models.ts | 19 + backend-pg/src/db/schemas/token-session.ts | 17 + backend-pg/src/db/schemas/token.ts | 19 + .../src/db/schemas/user-encryption-key.ts | 26 + backend-pg/src/db/schemas/user.ts | 38 + backend-pg/src/db/utils.ts | 43 + backend-pg/src/lib/config/env.ts | 49 +- backend-pg/src/lib/crypto/index.ts | 1 + backend-pg/src/lib/crypto/srp.ts | 26 + backend-pg/src/lib/errors/index.ts | 36 + backend-pg/src/lib/types/index.ts | 5 + .../src/lib/validator/disposable_emails.txt | 3519 +++++++++++++++++ backend-pg/src/lib/validator/index.ts | 1 + .../src/lib/validator/validate-email.ts | 10 + backend-pg/src/lib/zod/index.ts | 12 + backend-pg/src/server/app.ts | 40 +- backend-pg/src/server/plugins/swagger.ts | 9 +- backend-pg/src/server/routes/index.ts | 44 + backend-pg/src/server/routes/v1/index.ts | 5 + .../src/server/routes/v1/password-router.ts | 115 + backend-pg/src/server/routes/v2/index.ts | 5 + backend-pg/src/server/routes/v2/mfa-router.ts | 89 + backend-pg/src/server/routes/v3/index.ts | 7 + .../src/server/routes/v3/login-router.ts | 97 + .../src/server/routes/v3/signup-router.ts | 103 + backend-pg/src/services/auth/auth-dal.ts | 131 + .../src/services/auth/auth-login-service.ts | 249 ++ .../src/services/auth/auth-login-type.ts | 20 + .../services/auth/auth-password-service.ts | 257 ++ .../src/services/auth/auth-password-type.ts | 35 + .../src/services/auth/auth-signup-service.ts | 169 + .../src/services/auth/auth-signup-type.ts | 38 + backend-pg/src/services/smtp/smtp-service.ts | 78 + .../smtp/templates/emailMfa.handlebars | 19 + .../templates/emailVerification.handlebars | 17 + .../historicalSecretLeakIncident.handlebars | 21 + .../smtp/templates/newDevice.handlebars | 19 + .../organizationInvitation.handlebars | 16 + .../smtp/templates/passwordReset.handlebars | 14 + .../templates/secretLeakIncident.handlebars | 25 + .../templates/workspaceInvitation.handlebars | 15 + backend-pg/src/services/token/token-dal.ts | 98 + .../src/services/token/token-service.ts | 134 + backend-pg/src/services/token/token-types.ts | 41 + docker-compose.pg.yml | 58 + .../ServerConfigContext.tsx | 8 +- frontend/src/hooks/api/auth/queries.tsx | 4 +- frontend/src/pages/_app.tsx | 9 +- 68 files changed, 7529 insertions(+), 58 deletions(-) create mode 100644 backend-pg/.dockerignore create mode 100644 backend-pg/Dockerfile.dev create mode 100644 backend-pg/nodemon.json create mode 100644 backend-pg/scripts/create-backend-file.ts create mode 100644 backend-pg/scripts/create-migration.ts create mode 100644 backend-pg/src/@types/fastify-zod.d.ts create mode 100644 backend-pg/src/@types/knex.d.ts create mode 100644 backend-pg/src/db/index.ts create mode 100644 backend-pg/src/db/instance.ts create mode 100644 backend-pg/src/db/knexfile.ts create mode 100644 backend-pg/src/db/migrations/20231128072457_user.ts create mode 100644 backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts create mode 100644 backend-pg/src/db/migrations/20231129072939_auth-token.ts create mode 100644 backend-pg/src/db/migrations/20231130072734_auth-token-session.ts create mode 100644 backend-pg/src/db/migrations/20231201151432_backup-key.ts create mode 100644 backend-pg/src/db/schemas/backup-private-key.ts create mode 100644 backend-pg/src/db/schemas/index.ts create mode 100644 backend-pg/src/db/schemas/models.ts create mode 100644 backend-pg/src/db/schemas/token-session.ts create mode 100644 backend-pg/src/db/schemas/token.ts create mode 100644 backend-pg/src/db/schemas/user-encryption-key.ts create mode 100644 backend-pg/src/db/schemas/user.ts create mode 100644 backend-pg/src/db/utils.ts create mode 100644 backend-pg/src/lib/crypto/index.ts create mode 100644 backend-pg/src/lib/crypto/srp.ts create mode 100644 backend-pg/src/lib/errors/index.ts create mode 100644 backend-pg/src/lib/types/index.ts create mode 100644 backend-pg/src/lib/validator/disposable_emails.txt create mode 100644 backend-pg/src/lib/validator/index.ts create mode 100644 backend-pg/src/lib/validator/validate-email.ts create mode 100644 backend-pg/src/lib/zod/index.ts create mode 100644 backend-pg/src/server/routes/index.ts create mode 100644 backend-pg/src/server/routes/v1/index.ts create mode 100644 backend-pg/src/server/routes/v1/password-router.ts create mode 100644 backend-pg/src/server/routes/v2/index.ts create mode 100644 backend-pg/src/server/routes/v2/mfa-router.ts create mode 100644 backend-pg/src/server/routes/v3/index.ts create mode 100644 backend-pg/src/server/routes/v3/login-router.ts create mode 100644 backend-pg/src/server/routes/v3/signup-router.ts create mode 100644 backend-pg/src/services/auth/auth-dal.ts create mode 100644 backend-pg/src/services/auth/auth-login-service.ts create mode 100644 backend-pg/src/services/auth/auth-login-type.ts create mode 100644 backend-pg/src/services/auth/auth-password-service.ts create mode 100644 backend-pg/src/services/auth/auth-password-type.ts create mode 100644 backend-pg/src/services/auth/auth-signup-service.ts create mode 100644 backend-pg/src/services/auth/auth-signup-type.ts create mode 100644 backend-pg/src/services/smtp/smtp-service.ts create mode 100644 backend-pg/src/services/smtp/templates/emailMfa.handlebars create mode 100644 backend-pg/src/services/smtp/templates/emailVerification.handlebars create mode 100644 backend-pg/src/services/smtp/templates/historicalSecretLeakIncident.handlebars create mode 100644 backend-pg/src/services/smtp/templates/newDevice.handlebars create mode 100644 backend-pg/src/services/smtp/templates/organizationInvitation.handlebars create mode 100644 backend-pg/src/services/smtp/templates/passwordReset.handlebars create mode 100644 backend-pg/src/services/smtp/templates/secretLeakIncident.handlebars create mode 100644 backend-pg/src/services/smtp/templates/workspaceInvitation.handlebars create mode 100644 backend-pg/src/services/token/token-dal.ts create mode 100644 backend-pg/src/services/token/token-service.ts create mode 100644 backend-pg/src/services/token/token-types.ts create mode 100644 docker-compose.pg.yml diff --git a/backend-pg/.dockerignore b/backend-pg/.dockerignore new file mode 100644 index 000000000..b484ea02a --- /dev/null +++ b/backend-pg/.dockerignore @@ -0,0 +1,11 @@ +node_modules +.env +.env.* +.git +.gitignore +Dockerfile +.dockerignore +docker-compose.* +.DS_Store +*.swp +*~ diff --git a/backend-pg/Dockerfile.dev b/backend-pg/Dockerfile.dev new file mode 100644 index 000000000..a279dd381 --- /dev/null +++ b/backend-pg/Dockerfile.dev @@ -0,0 +1,14 @@ +FROM node:20-alpine + +WORKDIR /app + +COPY package.json package.json +COPY package-lock.json package-lock.json + +RUN npm install + +COPY . . + +ENV HOST=0.0.0.0 + +CMD ["npm", "run", "dev:docker"] diff --git a/backend-pg/nodemon.json b/backend-pg/nodemon.json new file mode 100644 index 000000000..3f79eef77 --- /dev/null +++ b/backend-pg/nodemon.json @@ -0,0 +1,6 @@ +{ + "watch": ["src"], + "ext": ".ts,.js", + "ignore": [], + "exec": "tsx ./src/server/app.ts | pino-pretty --colorize --colorizeObjects --singleLine" +} diff --git a/backend-pg/package-lock.json b/backend-pg/package-lock.json index a89eb39b6..35a5d2383 100644 --- a/backend-pg/package-lock.json +++ b/backend-pg/package-lock.json @@ -15,17 +15,29 @@ "@fastify/rate-limit": "^9.0.0", "@fastify/swagger": "^8.12.0", "@fastify/swagger-ui": "^1.10.1", + "bcrypt": "^5.1.1", "dotenv": "^16.3.1", "eslint-config-airbnb-typescript": "^17.1.0", "fastify": "^4.24.3", "fastify-plugin": "^4.5.1", + "handlebars": "^4.7.8", + "jsonwebtoken": "^9.0.2", + "jsrp": "^0.2.4", + "knex": "^3.0.1", + "nodemailer": "^6.9.7", "ora": "^7.0.1", + "pg": "^8.11.3", "pino": "^8.16.2", "zod": "^3.22.4", "zod-to-json-schema": "^3.22.0" }, "devDependencies": { + "@types/bcrypt": "^5.0.2", + "@types/jsonwebtoken": "^9.0.5", + "@types/jsrp": "^0.2.6", "@types/node": "^20.9.5", + "@types/nodemailer": "^6.4.14", + "@types/prompt-sync": "^4.2.3", "@typescript-eslint/eslint-plugin": "^6.12.0", "@typescript-eslint/parser": "^6.12.0", "eslint": "^8.54.0", @@ -35,7 +47,9 @@ "eslint-plugin-import": "^2.29.0", "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-simple-import-sort": "^10.0.0", + "nodemon": "^3.0.2", "pino-pretty": "^10.2.3", + "prompt-sync": "^4.2.0", "ts-node": "^10.9.1", "tsx": "^4.4.0", "typescript": "^5.3.2" @@ -712,6 +726,25 @@ "node": ">=8" } }, + "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/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1007,6 +1040,15 @@ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, + "node_modules/@types/bcrypt": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", + "integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -1017,6 +1059,21 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz", + "integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jsrp": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@types/jsrp/-/jsrp-0.2.6.tgz", + "integrity": "sha512-2h3tFvkbHksiNcDiUdcJ08gXWG10fnahp30GJ2Tbt4vd4pfsbfkoKTaTbYykFoppaJ6DL3914nQ3PU1vVIlBRQ==", + "dev": true + }, "node_modules/@types/node": { "version": "20.9.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.5.tgz", @@ -1026,6 +1083,21 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/nodemailer": { + "version": "6.4.14", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.14.tgz", + "integrity": "sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/prompt-sync": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@types/prompt-sync/-/prompt-sync-4.2.3.tgz", + "integrity": "sha512-Ox77gCSx0YyeakGt/qfOZUSFNSSi+sh3ABoGOiCwiO2KODx492BJnUm9oIXS+AHJtqp12iM4RduY6viTJ9bYwA==", + "dev": true + }, "node_modules/@types/semver": { "version": "7.5.6", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", @@ -1301,6 +1373,11 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, + "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/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -1345,6 +1422,38 @@ "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/agent-base/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/ajv": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", @@ -1401,11 +1510,54 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/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, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "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/archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==" }, + "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", @@ -1601,6 +1753,19 @@ } ] }, + "node_modules/bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/big-integer": { "version": "1.6.52", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", @@ -1610,6 +1775,15 @@ "node": ">=0.6" } }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/bl": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", @@ -1688,6 +1862,19 @@ "ieee754": "^1.2.1" } }, + "node_modules/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==" + }, + "node_modules/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==", + "engines": { + "node": ">=4" + } + }, "node_modules/bundle-name": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", @@ -1735,6 +1922,50 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.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" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "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/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -1776,12 +2007,28 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "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/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1792,6 +2039,11 @@ "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" }, + "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", @@ -1819,6 +2071,18 @@ "node": ">=6.6.0" } }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -1935,6 +2199,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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", @@ -1943,6 +2212,14 @@ "node": ">= 0.8" } }, + "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/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -1990,6 +2267,14 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/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==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/emoji-regex": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", @@ -2143,6 +2428,14 @@ "@esbuild/win32-x64": "0.18.20" } }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -2579,6 +2872,14 @@ "node": ">=8" } }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "engines": { + "node": ">=6" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -2912,6 +3213,28 @@ "node": ">= 0.6" } }, + "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.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2964,6 +3287,62 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/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==" + }, + "node_modules/gauge/node_modules/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==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/get-intrinsic": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", @@ -2978,6 +3357,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/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==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -3017,6 +3404,11 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/getopts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz", + "integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==" + }, "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -3134,6 +3526,26 @@ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -3142,6 +3554,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/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, + "engines": { + "node": ">=4" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", @@ -3189,6 +3610,37 @@ "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/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/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/hasown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", @@ -3247,6 +3699,39 @@ "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/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/human-signals": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", @@ -3283,6 +3768,12 @@ "node": ">= 4" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3333,6 +3824,14 @@ "node": ">= 0.4" } }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -3365,6 +3864,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/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, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -3439,6 +3950,14 @@ "node": ">=0.10.0" } }, + "node_modules/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==", + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -3679,6 +4198,11 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -3739,6 +4263,56 @@ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "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" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsrp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsrp/-/jsrp-0.2.4.tgz", + "integrity": "sha512-+CjGAhZaj3k2MMXEy+xWYv7xJGnise/SlL1IIvnRuJ1ZiLtNPJJln/dMDCgORQCq1ouXDnW1FBxW5bkBFhK/8g==", + "dependencies": { + "create-hash": "^1.0.0", + "jsbn": "^1.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -3747,6 +4321,90 @@ "json-buffer": "3.0.1" } }, + "node_modules/knex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/knex/-/knex-3.0.1.tgz", + "integrity": "sha512-ruASxC6xPyDklRdrcDy6a9iqK+R9cGK214aiQa+D9gX2ZnHZKv6o6JC9ZfgxILxVAul4bZ13c3tgOAHSuQ7/9g==", + "dependencies": { + "colorette": "2.0.19", + "commander": "^10.0.0", + "debug": "4.3.4", + "escalade": "^3.1.1", + "esm": "^3.2.25", + "get-package-type": "^0.1.0", + "getopts": "2.3.0", + "interpret": "^2.2.0", + "lodash": "^4.17.21", + "pg-connection-string": "2.6.1", + "rechoir": "^0.8.0", + "resolve-from": "^5.0.0", + "tarn": "^3.0.2", + "tildify": "2.0.0" + }, + "bin": { + "knex": "bin/cli.js" + }, + "engines": { + "node": ">=16" + }, + "peerDependenciesMeta": { + "better-sqlite3": { + "optional": true + }, + "mysql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/knex/node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" + }, + "node_modules/knex/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/knex/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/knex/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3783,11 +4441,51 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/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==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/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==" + }, + "node_modules/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==" + }, + "node_modules/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==" + }, "node_modules/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==" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/log-symbols": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", @@ -3814,12 +4512,44 @@ "node": ">=10" } }, + "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", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3884,6 +4614,48 @@ "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/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/mnemonist": { "version": "0.39.5", "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.5.tgz", @@ -3902,6 +4674,117 @@ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, + "node_modules/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==" + }, + "node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + }, + "node_modules/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==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nodemailer": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.7.tgz", + "integrity": "sha512-rUtR77ksqex/eZRLmQ21LKVH5nAAsVicAtAYudK7JgwenEDZ0UIQ1adUGqErz7sMkWYxWTTU1aeP2Jga6WQyJw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/nodemon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.2.tgz", + "integrity": "sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "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-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-run-path": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", @@ -3929,6 +4812,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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/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==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -4142,6 +5044,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/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==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4190,6 +5097,94 @@ "node": ">=8" } }, + "node_modules/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/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 + }, + "node_modules/pg-connection-string": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.1.tgz", + "integrity": "sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/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==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "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" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/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==" + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -4267,6 +5262,41 @@ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==" }, + "node_modules/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==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4316,6 +5346,36 @@ "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.3.0.tgz", "integrity": "sha512-N6mp1+2jpQr3oCFMz6SeHRGbv6Slb20bRhj4v3xR99HqNToAcOe1MFOp4tytyzOfJn+QtN8Rf7U/h2KAn4kC6g==" }, + "node_modules/prompt-sync": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/prompt-sync/-/prompt-sync-4.2.0.tgz", + "integrity": "sha512-BuEzzc5zptP5LsgV5MZETjDaKSWfchl5U9Luiu8SKp7iZWD5tZalOxvNcZRwv+d2phNFr8xlbxmFNcRKfJOzJw==", + "dev": true, + "dependencies": { + "strip-ansi": "^5.0.0" + } + }, + "node_modules/prompt-sync/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/prompt-sync/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -4328,6 +5388,12 @@ "node": ">= 0.10" } }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -4370,6 +5436,14 @@ "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/readable-stream": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.4.2.tgz", @@ -4385,6 +5459,18 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/real-require": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", @@ -4393,6 +5479,17 @@ "node": ">= 12.13.0" } }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", @@ -4520,6 +5617,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, "node_modules/run-applescript": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", @@ -4706,6 +5812,11 @@ "node": ">=10" } }, + "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-cookie-parser": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", @@ -4743,6 +5854,18 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4780,6 +5903,18 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4796,6 +5931,14 @@ "atomic-sleep": "^1.0.0" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -4937,6 +6080,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/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, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/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", @@ -4973,6 +6128,30 @@ "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/tarn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", + "integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4986,6 +6165,14 @@ "real-require": "^0.2.0" } }, + "node_modules/tildify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==", + "engines": { + "node": ">=8" + } + }, "node_modules/titleize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", @@ -5025,6 +6212,38 @@ "node": ">=0.6" } }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/touch/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/ts-api-utils": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", @@ -5199,6 +6418,18 @@ "node": ">=14.17" } }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -5213,6 +6444,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -5247,6 +6484,20 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, + "node_modules/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==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5294,11 +6545,69 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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/wide-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/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==" + }, + "node_modules/wide-align/node_modules/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==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/backend-pg/package.json b/backend-pg/package.json index 5ec5e63aa..6499ab5e9 100644 --- a/backend-pg/package.json +++ b/backend-pg/package.json @@ -6,15 +6,28 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "tsx watch --clear-screen=false ./src/server/app.ts | pino-pretty --colorize --colorizeObjects --singleLine", + "dev:docker": "nodemon", "type:check": "tsc --noEmit", "lint:fix": "eslint --fix 'src/**/*.ts'", - "lint": "eslint 'src/**/*.ts'" + "lint": "eslint 'src/**/*.ts'", + "generate:component": "tsx ./scripts/create-backend-file.ts", + "migration:new": "tsx ./scripts/create-migration.ts", + "migration:up": "knex --knexfile ./src/db/knexfile.ts --client pg migrate:up", + "migration:down": "knex --knexfile ./src/db/knexfile.ts --client pg migrate:down", + "migration:list": "knex --knexfile ./src/db/knexfile.ts --client pg migrate:list", + "migration:latest": "knex --knexfile ./src/db/knexfile.ts --client pg migrate:latest", + "migration:rollback": "knex --knexfile ./src/db/knexfile.ts migrate:rollback" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { + "@types/bcrypt": "^5.0.2", + "@types/jsonwebtoken": "^9.0.5", + "@types/jsrp": "^0.2.6", "@types/node": "^20.9.5", + "@types/nodemailer": "^6.4.14", + "@types/prompt-sync": "^4.2.3", "@typescript-eslint/eslint-plugin": "^6.12.0", "@typescript-eslint/parser": "^6.12.0", "eslint": "^8.54.0", @@ -24,7 +37,9 @@ "eslint-plugin-import": "^2.29.0", "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-simple-import-sort": "^10.0.0", + "nodemon": "^3.0.2", "pino-pretty": "^10.2.3", + "prompt-sync": "^4.2.0", "ts-node": "^10.9.1", "tsx": "^4.4.0", "typescript": "^5.3.2" @@ -36,11 +51,18 @@ "@fastify/rate-limit": "^9.0.0", "@fastify/swagger": "^8.12.0", "@fastify/swagger-ui": "^1.10.1", + "bcrypt": "^5.1.1", "dotenv": "^16.3.1", "eslint-config-airbnb-typescript": "^17.1.0", "fastify": "^4.24.3", "fastify-plugin": "^4.5.1", + "handlebars": "^4.7.8", + "jsonwebtoken": "^9.0.2", + "jsrp": "^0.2.4", + "knex": "^3.0.1", + "nodemailer": "^6.9.7", "ora": "^7.0.1", + "pg": "^8.11.3", "pino": "^8.16.2", "zod": "^3.22.4", "zod-to-json-schema": "^3.22.0" diff --git a/backend-pg/scripts/create-backend-file.ts b/backend-pg/scripts/create-backend-file.ts new file mode 100644 index 000000000..2ea0a773a --- /dev/null +++ b/backend-pg/scripts/create-backend-file.ts @@ -0,0 +1,81 @@ +import { mkdirSync, writeFileSync } from "fs"; +import path from "path"; +import promptSync from "prompt-sync"; + +const prompt = promptSync({ + sigint: true +}); + +console.log(` +Component List +-------------- +1. Service component +2. Schema file +`); +const componentType = parseInt(prompt("Select a component: "), 10); + +if (componentType === 1) { + const componentName = prompt("Enter service name: "); + const dir = path.join(__dirname, `../src/services/${componentName}`); + const capitalizedComponentName = componentName.at(0)?.toUpperCase() + componentName.slice(1); + const dalTypeName = `T${capitalizedComponentName}DalFactory`; + const dalName = `${componentName}DalFactory`; + const serviceTypeName = `T${capitalizedComponentName}ServiceFactory`; + const serviceName = `${componentName}ServiceFactory`; + + mkdirSync(dir); + + writeFileSync( + path.join(dir, `${componentName}-dal.ts`), + `import { TDbClient } from "@app/db"; +import { TableName } from "@app/db/schemas"; + +export type ${dalTypeName} = {}; + +export const ${dalName} = (db: TDbClient): ${dalTypeName} => { + + return { }; +}; +` + ); + + writeFileSync( + path.join(dir, `${componentName}-service.ts`), + `import { ${dalTypeName} } from "./${componentName}-dal"; + +type ${serviceTypeName}Dep = { + ${componentName}Dal: ${dalTypeName}; +}; + +export type ${serviceTypeName} = ReturnType; + +export const ${serviceName} = ({ ${componentName}Dal }: ${serviceTypeName}Dep) => { + return {}; +}; +` + ); + writeFileSync(path.join(dir, `${componentName}-types.ts`), ""); +} else if (componentType === 2) { + const componentName = prompt("Type component name in lowercase with space seperated: "); + const dashcase = componentName.split(" ").join("-"); + const pascalCase = componentName + .split(" ") + .reduce( + (prev, curr) => prev + `${curr.at(0)?.toUpperCase()}${curr.slice(1).toLowerCase()}`, + "" + ); + writeFileSync( + path.join(__dirname, "../src/db/schemas", `${dashcase}.ts`), + ` +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const ${pascalCase}Schema = z.object({}); + +export type T${pascalCase} = z.infer; +export type T${pascalCase}Insert = Omit; +export type T${pascalCase}Update = Partial>; +` + ); +} diff --git a/backend-pg/scripts/create-migration.ts b/backend-pg/scripts/create-migration.ts new file mode 100644 index 000000000..9a80f290e --- /dev/null +++ b/backend-pg/scripts/create-migration.ts @@ -0,0 +1,15 @@ +import { execSync } from "child_process"; +import path from "path"; +import promptSync from "prompt-sync"; + +const prompt = promptSync(); + +const migrationName = prompt("Enter name for migration: "); + +execSync( + `npx knex migrate:make --knexfile ${path.join( + __dirname, + "../src/db/knexfile.ts" + )} -x ts ${migrationName}`, + { stdio: "inherit" } +); diff --git a/backend-pg/src/@types/fastify-zod.d.ts b/backend-pg/src/@types/fastify-zod.d.ts new file mode 100644 index 000000000..02d28b28d --- /dev/null +++ b/backend-pg/src/@types/fastify-zod.d.ts @@ -0,0 +1,19 @@ +import { + FastifyInstance, + RawReplyDefaultExpression, + RawRequestDefaultExpression, + RawServerDefault +} from "fastify"; +import { Logger } from "pino"; + +import { ZodTypeProvider } from "@app/server/plugins/fastify-zod"; + +declare global { + type FastifyZodProvider = FastifyInstance< + RawServerDefault, + RawRequestDefaultExpression, + RawReplyDefaultExpression, + Readonly, + ZodTypeProvider + >; +} diff --git a/backend-pg/src/@types/fastify.d.ts b/backend-pg/src/@types/fastify.d.ts index 78cd61af4..33b744166 100644 --- a/backend-pg/src/@types/fastify.d.ts +++ b/backend-pg/src/@types/fastify.d.ts @@ -1,19 +1,32 @@ -import { ZodTypeProvider } from "@app/server/plugins/fastify-zod"; +import { TUser } from "@app/db/schemas"; +import { TAuthDalFactory } from "@app/services/auth/auth-dal"; +import { TAuthLoginFactory } from "@app/services/auth/auth-login-service"; +import { TAuthPasswordFactory } from "@app/services/auth/auth-password-service"; +import { TAuthSignupFactory } from "@app/services/auth/auth-signup-service"; import "fastify"; declare module "fastify" { interface FastifyRequest { realIp: string; + // used for mfa session authentication + mfa: { + userId: string; + user: TUser; + }; + } + + interface FastifyInstance { + services: { + login: TAuthLoginFactory; + password: TAuthPasswordFactory; + signup: TAuthSignupFactory; + }; + + // this is exclusive use for middlewares in which we need to inject data + // everywhere else access using service layer + store: { + user: Pick; + }; } } - -declare global { - type FastifyZodProvider = FastifyInstance< - RawServerDefault, - RawRequestDefaultExpression, - RawReplyDefaultExpression, - FastifyBaseLogger, - ZodTypeProvider - >; -} diff --git a/backend-pg/src/@types/knex.d.ts b/backend-pg/src/@types/knex.d.ts new file mode 100644 index 000000000..8b3776fe3 --- /dev/null +++ b/backend-pg/src/@types/knex.d.ts @@ -0,0 +1,43 @@ +import { Knex } from "knex"; + +import { + TableName, + TBackupPrivateKey, + TBackupPrivateKeyInsert, + TToken, + TTokenInsert, + TTokenUpdate, + TUser, + TUserEncryptionKey, + TUserEncryptionKeyInsert, + TUserEncryptionKeyUpdate, + TUserInsert, + TUserUpdate +} from "@app/db/schemas"; +import { + TTokenSession, + TTokenSessionInsert, + TTokenSessionUpdate +} from "@app/db/schemas/token-session"; + +declare module "knex/types/tables" { + interface Tables extends { [key in TableName]: Knex.CompositeTableType } { + [TableName.Users]: Knex.CompositeTableType; + [TableName.UserEncryptionKey]: Knex.CompositeTableType< + TUserEncryptionKey, + TUserEncryptionKeyInsert, + TUserEncryptionKeyUpdate + >; + [TableName.AuthTokens]: Knex.CompositeTableType; + [TableName.AuthTokenSession]: Knex.CompositeTableType< + TTokenSession, + TTokenSessionInsert, + TTokenSessionUpdate + >; + [TableName.BackupPrivateKey]: Knex.CompositeTableType< + TBackupPrivateKey, + TBackupPrivateKeyInsert, + TTokenSessionUpdate + >; + } +} diff --git a/backend-pg/src/db/index.ts b/backend-pg/src/db/index.ts new file mode 100644 index 000000000..75992e2c6 --- /dev/null +++ b/backend-pg/src/db/index.ts @@ -0,0 +1,2 @@ +export type { TDbClient } from "./instance"; +export { initDbConnection } from "./instance"; diff --git a/backend-pg/src/db/instance.ts b/backend-pg/src/db/instance.ts new file mode 100644 index 000000000..1eb54c136 --- /dev/null +++ b/backend-pg/src/db/instance.ts @@ -0,0 +1,11 @@ +import knex from "knex"; + +export type TDbClient = ReturnType; +export const initDbConnection = (dbConnectionUri: string) => { + const db = knex({ + client: "pg", + connection: dbConnectionUri + }); + + return db; +}; diff --git a/backend-pg/src/db/knexfile.ts b/backend-pg/src/db/knexfile.ts new file mode 100644 index 000000000..071eb63fb --- /dev/null +++ b/backend-pg/src/db/knexfile.ts @@ -0,0 +1,24 @@ +import dotenv from "dotenv"; +import type { Knex } from "knex"; +import path from "path"; + +// eslint-disable-next-line +import "ts-node/register"; + +// Update with your config settings. +dotenv.config({ + path: path.join(__dirname, "../../.env"), + debug: true +}); +export default { + useNullAsDefault: true, + client: "postgres", + connection: process.env.DB_CONNECTION_URI, + pool: { + min: 2, + max: 10 + }, + migrations: { + tableName: "infisical_migrations" + } +} as Knex.Config; diff --git a/backend-pg/src/db/migrations/20231128072457_user.ts b/backend-pg/src/db/migrations/20231128072457_user.ts new file mode 100644 index 000000000..9fd26031c --- /dev/null +++ b/backend-pg/src/db/migrations/20231128072457_user.ts @@ -0,0 +1,37 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; +import { + createOnUpdateTrigger, + createUpdateAtTriggerFunction, + dropOnUpdateTrigger, + dropUpdatedAtTriggerFunction +} from "../utils"; + +export async function up(knex: Knex): Promise { + const isTablePresent = await knex.schema.hasTable(TableName.Users); + if (!isTablePresent) { + await knex.schema.createTable(TableName.Users, (t) => { + t.uuid("id").primary().defaultTo(knex.fn.uuid()); + t.string("email").notNullable(); + t.specificType("authMethods", "text[]"); + t.boolean("superAdmin").defaultTo(false); + t.string("firstName"); + t.string("lastName"); + t.boolean("isAccepted").defaultTo(false); + t.boolean("isMfaEnabled").defaultTo(false); + t.specificType("mfaMethods", "text[]"); + t.jsonb("devices"); + t.timestamps(true, true, true); + }); + } + // this is a one time function + await createUpdateAtTriggerFunction(knex); + await createOnUpdateTrigger(knex, TableName.Users); +} + +export async function down(knex: Knex): Promise { + await knex.schema.dropTableIfExists(TableName.Users); + await dropOnUpdateTrigger(knex, TableName.Users); + await dropUpdatedAtTriggerFunction(knex); +} diff --git a/backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts b/backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts new file mode 100644 index 000000000..b9b312456 --- /dev/null +++ b/backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts @@ -0,0 +1,31 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + const isTablePresent = await knex.schema.hasTable(TableName.UserEncryptionKey); + if (!isTablePresent) { + await knex.schema.createTable(TableName.UserEncryptionKey, (t) => { + t.increments().primary(); + t.text("clientPublicKey"); + t.text("serverPrivateKey"); + t.text("encryptionVersion").defaultTo(1); + t.text("protectedKey").notNullable(); + t.text("protectedKeyIV").notNullable(); + t.text("protectedKeyTag").notNullable(); + t.text("publicKey").notNullable(); + t.text("encryptedPrivateKey").notNullable(); + t.text("iv").notNullable(); + t.text("tag").notNullable(); + t.text("salt").notNullable(); + t.text("verifier").notNullable(); + // one to one relationship + t.uuid("userId").notNullable().unique(); + t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE"); + }); + } +} + +export async function down(knex: Knex): Promise { + await knex.schema.dropTableIfExists(TableName.UserEncryptionKey); +} diff --git a/backend-pg/src/db/migrations/20231129072939_auth-token.ts b/backend-pg/src/db/migrations/20231129072939_auth-token.ts new file mode 100644 index 000000000..0b186b8b0 --- /dev/null +++ b/backend-pg/src/db/migrations/20231129072939_auth-token.ts @@ -0,0 +1,24 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + const isTablePresent = await knex.schema.hasTable(TableName.AuthTokens); + if (!isTablePresent) { + await knex.schema.createTable(TableName.AuthTokens, (t) => { + t.string("type").notNullable(); + t.string("phoneNumber"); + t.string("tokenHash").notNullable(); + t.integer("triesLeft"); + t.datetime("expiresAt").notNullable(); + // does not need update trigger we will do it manually + t.timestamps(true, true, true); + t.uuid("userId"); + t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE"); + }); + } +} + +export async function down(knex: Knex): Promise { + await knex.schema.dropTableIfExists(TableName.AuthTokens); +} diff --git a/backend-pg/src/db/migrations/20231130072734_auth-token-session.ts b/backend-pg/src/db/migrations/20231130072734_auth-token-session.ts new file mode 100644 index 000000000..4acde142f --- /dev/null +++ b/backend-pg/src/db/migrations/20231130072734_auth-token-session.ts @@ -0,0 +1,29 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; +import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils"; + +export async function up(knex: Knex): Promise { + const isTablePresent = await knex.schema.hasTable(TableName.AuthTokenSession); + if (!isTablePresent) { + await knex.schema.createTable(TableName.AuthTokenSession, (t) => { + t.increments(); + t.string("ip").notNullable(); + t.string("userAgent"); + t.integer("refreshVersion").notNullable().defaultTo(1); + t.integer("accessVersion").notNullable().defaultTo(1); + t.datetime("lastUsed").notNullable(); + // does not need update trigger we will do it manually + t.timestamps(true, true, true); + t.uuid("userId").notNullable(); + t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE"); + }); + } + // this is a one time function + await createOnUpdateTrigger(knex, TableName.AuthTokenSession); +} + +export async function down(knex: Knex): Promise { + await knex.schema.dropTableIfExists(TableName.AuthTokenSession); + await dropOnUpdateTrigger(knex, TableName.AuthTokenSession); +} diff --git a/backend-pg/src/db/migrations/20231201151432_backup-key.ts b/backend-pg/src/db/migrations/20231201151432_backup-key.ts new file mode 100644 index 000000000..2f7ff9665 --- /dev/null +++ b/backend-pg/src/db/migrations/20231201151432_backup-key.ts @@ -0,0 +1,26 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + const doesTableExist = await knex.schema.hasTable(TableName.BackupPrivateKey); + if (!doesTableExist) { + await knex.schema.createTable(TableName.BackupPrivateKey, (t) => { + t.increments(); + t.string("encryptedPrivateKey").notNullable(); + t.string("iv").notNullable(); + t.string("tag").notNullable(); + t.string("algorithm").notNullable(); + t.string("keyEncoding").notNullable(); + t.string("salt").notNullable(); + t.string("verifier").notNullable(); + t.timestamps(true, true, true); + t.uuid("userId").notNullable().unique(); + t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE"); + }); + } +} + +export async function down(knex: Knex): Promise { + await knex.schema.dropTableIfExists(TableName.BackupPrivateKey); +} diff --git a/backend-pg/src/db/schemas/backup-private-key.ts b/backend-pg/src/db/schemas/backup-private-key.ts new file mode 100644 index 000000000..73bcc59a1 --- /dev/null +++ b/backend-pg/src/db/schemas/backup-private-key.ts @@ -0,0 +1,21 @@ +import { z } from "zod"; + +import { SecretEncryptionAlgo, SecretKeyEncoding, TImmutableDBKeys } from "./models"; + +export const BackupPrivateKeySchema = z.object({ + id: z.string(), + userId: z.string(), + encryptedPrivateKey: z.string(), + iv: z.string(), + tag: z.string(), + algorithm: z.nativeEnum(SecretEncryptionAlgo), + keyEncoding: z.nativeEnum(SecretKeyEncoding), + salt: z.string(), + verifier: z.string(), + createdAt: z.string().datetime(), + updatedAt: z.string().datetime() +}); + +export type TBackupPrivateKey = z.infer; +export type TBackupPrivateKeyInsert = Omit; +export type TBackupPrivateKeyUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/index.ts b/backend-pg/src/db/schemas/index.ts new file mode 100644 index 000000000..33c7fea0f --- /dev/null +++ b/backend-pg/src/db/schemas/index.ts @@ -0,0 +1,15 @@ +export { + BackupPrivateKeySchema, + TBackupPrivateKey, + TBackupPrivateKeyInsert, + TBackupPrivateKeyUpdate +} from "./backup-private-key"; +export { TableName } from "./models"; +export { TokenSchema, TToken, TTokenInsert, TTokenUpdate } from "./token"; +export { AuthMethod, TUser, TUserInsert, TUserUpdate, UserSchema } from "./user"; +export { + TUserEncryptionKey, + TUserEncryptionKeyInsert, + TUserEncryptionKeyUpdate, + UserEncryptionKey +} from "./user-encryption-key"; diff --git a/backend-pg/src/db/schemas/models.ts b/backend-pg/src/db/schemas/models.ts new file mode 100644 index 000000000..8c9cc0daa --- /dev/null +++ b/backend-pg/src/db/schemas/models.ts @@ -0,0 +1,19 @@ +export enum TableName { + Users = "users", + UserEncryptionKey = "user_encryption_keys", + AuthTokens = "auth_tokens", + AuthTokenSession = "auth_token_sessions", + BackupPrivateKey = "backup_private_key" +} + +export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt"; + +export enum SecretEncryptionAlgo { + AES_256_GCM = "aes-256-gcm" +} + +export enum SecretKeyEncoding { + UTF8 = "utf8", + BASE64 = "base64", + HEX = "hex" +} diff --git a/backend-pg/src/db/schemas/token-session.ts b/backend-pg/src/db/schemas/token-session.ts new file mode 100644 index 000000000..196871aa0 --- /dev/null +++ b/backend-pg/src/db/schemas/token-session.ts @@ -0,0 +1,17 @@ +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const TokenSessionSchema = z.object({ + id: z.string(), + userId: z.string(), + ip: z.string(), + userAgent: z.string(), + refreshVersion: z.number().default(1), + accessVersion: z.number().default(1), + lastUsed: z.string().datetime() +}); + +export type TTokenSession = z.infer; +export type TTokenSessionInsert = Omit; +export type TTokenSessionUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/token.ts b/backend-pg/src/db/schemas/token.ts new file mode 100644 index 000000000..401d5db87 --- /dev/null +++ b/backend-pg/src/db/schemas/token.ts @@ -0,0 +1,19 @@ +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const TokenSchema = z.object({ + id: z.number(), + type: z.enum(["emailConfirmation", "emailMfa", "organizationInvitation", "passwordReset"]), + phoneNumber: z.string().optional(), + tokenHash: z.string(), + triesLeft: z.number().optional(), + expiresAt: z.string().datetime().optional(), + createdAt: z.string().datetime(), + updatedAt: z.string().datetime(), + userId: z.string().optional() +}); + +export type TToken = z.infer; +export type TTokenInsert = Omit; +export type TTokenUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/user-encryption-key.ts b/backend-pg/src/db/schemas/user-encryption-key.ts new file mode 100644 index 000000000..103ee5bd2 --- /dev/null +++ b/backend-pg/src/db/schemas/user-encryption-key.ts @@ -0,0 +1,26 @@ +import { z } from "zod"; + +import { PickRequired } from "@app/lib/types"; + +import { TImmutableDBKeys } from "./models"; + +export const UserEncryptionKey = z.object({ + id: z.number(), + userId: z.string(), + serverPrivateKey: z.string().optional().nullable(), + clientPublicKey: z.string().optional().nullable(), + encryptionVersion: z.number().default(1).optional(), + protectedKey: z.string(), + protectedKeyIV: z.string(), + protectedKeyTag: z.string(), + publicKey: z.string(), + encryptedPrivateKey: z.string(), + iv: z.string(), + tag: z.string(), + salt: z.string(), + verifier: z.string() +}); + +export type TUserEncryptionKey = z.infer; +export type TUserEncryptionKeyInsert = Omit, TImmutableDBKeys>; +export type TUserEncryptionKeyUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/user.ts b/backend-pg/src/db/schemas/user.ts new file mode 100644 index 000000000..59428f08d --- /dev/null +++ b/backend-pg/src/db/schemas/user.ts @@ -0,0 +1,38 @@ +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export enum AuthMethod { + EMAIL = "email", + GOOGLE = "google", + GITHUB = "github", + GITLAB = "gitlab", + OKTA_SAML = "okta-saml", + AZURE_SAML = "azure-saml", + JUMPCLOUD_SAML = "jumpcloud-saml" +} + +export const UserSchema = z.object({ + id: z.string(), + authMethods: z.nativeEnum(AuthMethod).array().default([AuthMethod.EMAIL]).optional().nullable(), + email: z.string(), + isSuperAdmin: z.boolean().default(false).optional(), + firstName: z.string().optional().nullable(), + lastName: z.string().optional().nullable(), + isMfaEnabled: z.boolean().default(false).optional(), + mfaMethods: z.string().array().default([]).optional().nullable(), + isAccepted: z.boolean().default(false).optional(), + devices: z.string().nullable().optional() +}); + +export const UserDeviceSchema = z + .object({ + ip: z.string(), + userAgent: z.string() + }) + .array() + .default([]); + +export type TUser = z.infer; +export type TUserInsert = Omit; +export type TUserUpdate = Partial>; diff --git a/backend-pg/src/db/utils.ts b/backend-pg/src/db/utils.ts new file mode 100644 index 000000000..9c537f5b5 --- /dev/null +++ b/backend-pg/src/db/utils.ts @@ -0,0 +1,43 @@ +import { Knex } from "knex"; + +export const createJunctionTable = ( + knex: Knex, + tableName: string, + table1Name: string, + table2Name: string +) => + knex.schema.createTable(tableName, (table) => { + table.increments(); // Primary key + table.integer(`${table1Name}Id`).unsigned().notNullable(); // Foreign key for table1 + table.integer(`${table2Name}Id`).unsigned().notNullable(); // Foreign key for table2 + table.foreign(`${table1Name}Id`).references("id").inTable(table2Name); + table.foreign(`${table2Name}Id`).references("id").inTable(table1Name); + }); + +// one time logic +// this is a postgres function log to set updateAt to present time whenever row gets updated +export const createUpdateAtTriggerFunction = (knex: Knex) => + knex.raw(` +CREATE OR REPLACE FUNCTION on_update_timestamp() RETURNS TRIGGER AS $$ BEGIN NEW."updatedAt" = NOW(); +RETURN NEW; +END; +$$ LANGUAGE plpgsql; +`); + +export const dropUpdatedAtTriggerFunction = (knex: Knex) => + knex.raw(` +DROP FUNCTION IF EXISTS on_update_timestamp() CASCADE; +`); + +// we would be using this to apply updatedAt where ever we wanta +// remember to set `timestamps(true,true,true)` before this on schema +export const createOnUpdateTrigger = (knex: Knex, tableName: string) => + knex.raw(` +CREATE TRIGGER ${tableName}_updatedAt +BEFORE UPDATE ON ${tableName} +FOR EACH ROW +EXECUTE PROCEDURE on_update_timestamp(); +`); + +export const dropOnUpdateTrigger = (knex: Knex, tableName: string) => + knex.raw(`DROP TRIGGER IF EXISTS ${tableName}_updatedAt ON ${tableName}`); diff --git a/backend-pg/src/lib/config/env.ts b/backend-pg/src/lib/config/env.ts index 5f7217e03..ed03e6850 100644 --- a/backend-pg/src/lib/config/env.ts +++ b/backend-pg/src/lib/config/env.ts @@ -1,16 +1,39 @@ import { Logger } from "pino"; import { z } from "zod"; +import { zpStr } from "../zod"; + +const zodStrBool = z + .enum(["true", "false"]) + .optional() + .transform((val) => val === "true"); + const envSchema = z.object({ + PORT: z.coerce.number().default(4000), + HOST: zpStr(z.string().default("localhost")), + DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database conntection string")), NODE_ENV: z.enum(["development", "test", "production"]).default("development"), SALT_ROUNDS: z.coerce.number().default(10), // TODO(akhilmhdh): will be changed to one - ENCRYPTION_KEY: z.string().optional(), - ROOT_ENCRYPTION_KEY: z.string().optional(), - HTTPS_ENABLED: z - .enum(["true", "false"]) - .optional() - .transform((val) => val === "true") + ENCRYPTION_KEY: zpStr(z.string().optional()), + ROOT_ENCRYPTION_KEY: zpStr(z.string().optional()), + HTTPS_ENABLED: zodStrBool, + // smtp options + SMTP_HOST: zpStr(z.string().optional()), + SMTP_SECURE: zodStrBool, + SMTP_PORT: z.coerce.number().default(587), + SMTP_USERNAME: zpStr(z.string().optional()), + SMTP_PASSWORD: zpStr(z.string().optional()), + SMTP_FROM_ADDRESS: zpStr(z.string().optional()), + SMTP_FROM_NAME: zpStr(z.string().optional().default("Infisical")), + COOKIE_SECRET_SIGN_KEY: z.string().default("g5giLbOMpaJhqEogXApkiw2ZFW5Q0jvA"), + SITE_URL: zpStr(z.string().optional()), + // jwt options + JWT_AUTH_SECRET: zpStr(z.string()), + JWT_AUTH_LIFETIME: zpStr(z.string().default("10d")), + JWT_SIGNUP_LIFETIME: zpStr(z.string().default("15m")), + JWT_REFRESH_LIFETIME: zpStr(z.string().default("90d")), + JWT_MFA_LIFETIME: zpStr(z.string().default("5m")) }); let envCfg: Readonly>; @@ -21,8 +44,20 @@ export const initEnvConfig = (logger: Logger) => { const parsedEnv = envSchema.safeParse(process.env); if (!parsedEnv.success) { logger.error("Invalid environment variables. Check the error below"); - logger.error(parsedEnv.error); + logger.error(parsedEnv.error.issues); process.exit(-1); } envCfg = Object.freeze(parsedEnv.data); + return envCfg; }; + +export const formatSmtpConfig = () => ({ + host: envCfg.SMTP_HOST, + port: envCfg.SMTP_PORT, + auth: + envCfg.SMTP_USERNAME && envCfg.SMTP_PASSWORD + ? { user: envCfg.SMTP_USERNAME, pass: envCfg.SMTP_PASSWORD } + : undefined, + secure: envCfg.SMTP_SECURE, + from: `"${envCfg.SMTP_FROM_NAME}" <${envCfg.SMTP_FROM_ADDRESS}>` +}); diff --git a/backend-pg/src/lib/crypto/index.ts b/backend-pg/src/lib/crypto/index.ts new file mode 100644 index 000000000..ae317cfa6 --- /dev/null +++ b/backend-pg/src/lib/crypto/index.ts @@ -0,0 +1 @@ +export { generateSrpServerKey, srpCheckClientProof } from "./srp"; diff --git a/backend-pg/src/lib/crypto/srp.ts b/backend-pg/src/lib/crypto/srp.ts new file mode 100644 index 000000000..b05f3734d --- /dev/null +++ b/backend-pg/src/lib/crypto/srp.ts @@ -0,0 +1,26 @@ +import jsrp from "jsrp"; + +export const generateSrpServerKey = async (salt: string, verifier: string) => { + // eslint-disable-next-line new-cap + const server = new jsrp.server(); + await new Promise((resolve) => { + server.init({ salt, verifier }, () => resolve(null)); + }); + return { pubKey: server.getPublicKey(), privateKey: server.getPrivateKey() }; +}; + +export const srpCheckClientProof = async ( + salt: string, + verifier: string, + serverPrivateKey: string, + clientPublicKey: string, + clientProof: string +) => { + // eslint-disable-next-line new-cap + const server = new jsrp.server(); + await new Promise((resolve) => { + server.init({ salt, verifier, b: serverPrivateKey }, () => resolve(null)); + }); + server.setClientPublicKey(clientPublicKey); + return server.checkClientProof(clientProof); +}; diff --git a/backend-pg/src/lib/errors/index.ts b/backend-pg/src/lib/errors/index.ts new file mode 100644 index 000000000..ab090fa46 --- /dev/null +++ b/backend-pg/src/lib/errors/index.ts @@ -0,0 +1,36 @@ +/* eslint-disable max-classes-per-file */ +export class DatabaseError extends Error { + name: string; + + error: unknown; + + constructor({ name, error, message }: { message?: string; name: string; error: unknown }) { + super(message || "Failed to execute db ops"); + this.name = name; + this.error = error; + } +} + +export class UnauthorizedError extends Error { + name: string; + + error: unknown; + + constructor({ name, error, message }: { message?: string; name: string; error: unknown }) { + super(message ?? "You are not allowed to access this resourve"); + this.name = name; + this.error = error; + } +} + +export class BadRequestError extends Error { + name: string; + + error: unknown; + + constructor({ name, error, message }: { message?: string; name: string; error: unknown }) { + super(message ?? "The request is invalid"); + this.name = name; + this.error = error; + } +} diff --git a/backend-pg/src/lib/types/index.ts b/backend-pg/src/lib/types/index.ts new file mode 100644 index 000000000..c70fe1fd7 --- /dev/null +++ b/backend-pg/src/lib/types/index.ts @@ -0,0 +1,5 @@ +export type RequiredKeys = { + [K in keyof T]-?: undefined extends T[K] ? never : K; +}[keyof T]; + +export type PickRequired = Pick>; diff --git a/backend-pg/src/lib/validator/disposable_emails.txt b/backend-pg/src/lib/validator/disposable_emails.txt new file mode 100644 index 000000000..c71323b3a --- /dev/null +++ b/backend-pg/src/lib/validator/disposable_emails.txt @@ -0,0 +1,3519 @@ +0-mail.com +027168.com +0815.ru +0815.ry +0815.su +0845.ru +0box.eu +0clickemail.com +0n0ff.net +0nelce.com +0v.ro +0w.ro +0wnd.net +0wnd.org +0x207.info +1-8.biz +1-tm.com +10-minute-mail.com +1000rebates.stream +100likers.com +105kg.ru +10dk.email +10mail.com +10mail.org +10minut.com.pl +10minut.xyz +10minutemail.be +10minutemail.cf +10minutemail.co.uk +10minutemail.co.za +10minutemail.com +10minutemail.de +10minutemail.ga +10minutemail.gq +10minutemail.ml +10minutemail.net +10minutemail.nl +10minutemail.pro +10minutemail.us +10minutemailbox.com +10minutemails.in +10minutenemail.de +10minutesmail.com +10minutesmail.fr +10minutmail.pl +10x9.com +11163.com +123-m.com +12hosting.net +12houremail.com +12minutemail.com +12minutemail.net +12storage.com +140unichars.com +147.cl +14n.co.uk +15qm.com +1blackmoon.com +1ce.us +1chuan.com +1clck2.com +1fsdfdsfsdf.tk +1mail.ml +1pad.de +1s.fr +1secmail.com +1secmail.net +1secmail.org +1st-forms.com +1to1mail.org +1usemail.com +1webmail.info +1zhuan.com +2012-2016.ru +20email.eu +20email.it +20mail.eu +20mail.in +20mail.it +20minutemail.com +20minutemail.it +20mm.eu +2120001.net +21cn.com +247web.net +24hinbox.com +24hourmail.com +24hourmail.net +2anom.com +2chmail.net +2ether.net +2fdgdfgdfgdf.tk +2odem.com +2prong.com +2wc.info +300book.info +30mail.ir +30minutemail.com +30wave.com +3202.com +36ru.com +3d-painting.com +3l6.com +3mail.ga +3trtretgfrfe.tk +4-n.us +4057.com +418.dk +42o.org +4gfdsgfdgfd.tk +4k5.net +4mail.cf +4mail.ga +4nextmail.com +4nmv.ru +4tb.host +4warding.com +4warding.net +4warding.org +50set.ru +55hosting.net +5ghgfhfghfgh.tk +5gramos.com +5july.org +5mail.cf +5mail.ga +5minutemail.net +5oz.ru +5tb.in +5x25.com +5ymail.com +60minutemail.com +672643.net +675hosting.com +675hosting.net +675hosting.org +6hjgjhgkilkj.tk +6ip.us +6mail.cf +6mail.ga +6mail.ml +6paq.com +6somok.ru +6url.com +75hosting.com +75hosting.net +75hosting.org +7days-printing.com +7mail.ga +7mail.ml +7tags.com +80665.com +8127ep.com +8mail.cf +8mail.ga +8mail.ml +99.com +99cows.com +99experts.com +9mail.cf +9me.site +9mot.ru +9ox.net +9q.ro +a-bc.net +a45.in +a7996.com +aa5zy64.com +abacuswe.us +abakiss.com +abcmail.email +abilitywe.us +abovewe.us +absolutewe.us +abundantwe.us +abusemail.de +abuser.eu +abyssmail.com +ac20mail.in +academiccommunity.com +academywe.us +acceleratewe.us +accentwe.us +acceptwe.us +acclaimwe.us +accordwe.us +accreditedwe.us +acentri.com +achievementwe.us +achievewe.us +acornwe.us +acrossgracealley.com +acrylicwe.us +activatewe.us +activitywe.us +acucre.com +acuitywe.us +acumenwe.us +adaptivewe.us +adaptwe.us +add3000.pp.ua +addictingtrailers.com +adeptwe.us +adfskj.com +adios.email +adiq.eu +aditus.info +admiralwe.us +ado888.biz +adobeccepdm.com +adoniswe.us +adpugh.org +adroh.com +adsd.org +adubiz.info +advantagewe.us +advantimo.com +adventurewe.us +adventwe.us +advisorwe.us +advocatewe.us +adwaterandstir.com +aegde.com +aegia.net +aegiscorp.net +aegiswe.us +aelo.es +aeonpsi.com +afarek.com +affiliate-nebenjob.info +affiliatedwe.us +affilikingz.de +affinitywe.us +affluentwe.us +affordablewe.us +afia.pro +afrobacon.com +afterhourswe.us +agedmail.com +agendawe.us +agger.ro +agilewe.us +agorawe.us +agtx.net +aheadwe.us +ahem.email +ahk.jp +ahmedkhlef.com +air2token.com +airmailbox.website +airsi.de +ajaxapp.net +akapost.com +akerd.com +akgq701.com +akmail.in +al-qaeda.us +albionwe.us +alchemywe.us +alfaceti.com +aliaswe.us +alienware13.com +aligamel.com +alisongamel.com +alivance.com +alivewe.us +all-cats.ru +allaccesswe.us +allamericanwe.us +allaroundwe.us +alldirectbuy.com +allegiancewe.us +allegrowe.us +allemojikeyboard.com +allgoodwe.us +alliancewe.us +allinonewe.us +allofthem.net +alloutwe.us +allowed.org +alloywe.us +allprowe.us +allseasonswe.us +allstarwe.us +allthegoodnamesaretaken.org +allurewe.us +almondwe.us +alph.wtf +alpha-web.net +alphaomegawe.us +alpinewe.us +altairwe.us +altitudewe.us +altuswe.us +ama-trade.de +ama-trans.de +amadeuswe.us +amail.club +amail.com +amail1.com +amail4.me +amazon-aws.org +amberwe.us +ambiancewe.us +ambitiouswe.us +amelabs.com +americanawe.us +americasbestwe.us +americaswe.us +amicuswe.us +amilegit.com +amiri.net +amiriindustries.com +amplewe.us +amplifiedwe.us +amplifywe.us +ampsylike.com +analogwe.us +analysiswe.us +analyticalwe.us +analyticswe.us +analyticwe.us +anappfor.com +anappthat.com +andreihusanu.ro +andthen.us +animesos.com +anit.ro +ano-mail.net +anon-mail.de +anonbox.net +anonmail.top +anonmails.de +anonymail.dk +anonymbox.com +anonymized.org +anonymousness.com +anotherdomaincyka.tk +ansibleemail.com +anthony-junkmail.com +antireg.com +antireg.ru +antispam.de +antispam24.de +antispammail.de +anyalias.com +aoeuhtns.com +apfelkorps.de +aphlog.com +apkmd.com +appc.se +appinventor.nl +appixie.com +apps.dj +appzily.com +arduino.hk +ariaz.jetzt +armyspy.com +aron.us +arroisijewellery.com +art-en-ligne.pro +artman-conception.com +arur01.tk +arurgitu.gq +arvato-community.de +aschenbrandt.net +asdasd.nl +asdasd.ru +ashleyandrew.com +ask-mail.com +asorent.com +ass.pp.ua +astonut.tk +astroempires.info +asu.mx +asu.su +at.hm +at0mik.org +atnextmail.com +attnetwork.com +augmentationtechnology.com +ausgefallen.info +auti.st +autorobotica.com +autosouvenir39.ru +autotwollow.com +autowb.com +aver.com +averdov.com +avia-tonic.fr +avls.pt +awatum.de +awdrt.org +awiki.org +awsoo.com +axiz.org +axon7zte.com +axsup.net +ayakamail.cf +azazazatashkent.tk +azcomputerworks.com +azmeil.tk +b1of96u.com +b2bx.net +b2cmail.de +badgerland.eu +badoop.com +badpotato.tk +balaket.com +banit.club +banit.me +bank-opros1.ru +bareed.ws +barryogorman.com +bartdevos.be +basscode.org +bauwerke-online.com +bazaaboom.com +bbbbyyzz.info +bbhost.us +bbitf.com +bbitj.com +bbitq.com +bcaoo.com +bcast.ws +bcb.ro +bccto.me +bdmuzic.pw +beaconmessenger.com +bearsarefuzzy.com +beddly.com +beefmilk.com +belamail.org +belljonestax.com +beluckygame.com +benipaula.org +bepureme.com +beribase.ru +beribaza.ru +berirabotay.ru +best-john-boats.com +bestchoiceusedcar.com +bestlistbase.com +bestoption25.club +bestparadize.com +bestsoundeffects.com +besttempmail.com +betr.co +bgtmail.com +bgx.ro +bheps.com +bidourlnks.com +big1.us +bigprofessor.so +bigstring.com +bigwhoop.co.za +bij.pl +binka.me +binkmail.com +binnary.com +bio-muesli.info +bio-muesli.net +bione.co +bitwhites.top +bitymails.us +blackgoldagency.ru +blackmarket.to +bladesmail.net +blip.ch +blnkt.net +block521.com +blogmyway.org +blogos.net +blogspam.ro +blondemorkin.com +bluedumpling.info +bluewerks.com +bnote.com +boatmail.us +bobmail.info +bobmurchison.com +bofthew.com +bonobo.email +boofx.com +bookthemmore.com +bootybay.de +borged.com +borged.net +borged.org +bot.nu +boun.cr +bouncr.com +boxformail.in +boximail.com +boxmail.lol +boxomail.live +boxtemp.com.br +bptfp.net +brand-app.biz +brandallday.net +brasx.org +breakthru.com +brefmail.com +brennendesreich.de +briggsmarcus.com +broadbandninja.com +bsnow.net +bspamfree.org +bspooky.com +bst-72.com +btb-notes.com +btc.email +btcmail.pw +btcmod.com +btizet.pl +buccalmassage.ru +budaya-tionghoa.com +budayationghoa.com +buffemail.com +bugfoo.com +bugmenever.com +bugmenot.com +bukhariansiddur.com +bulrushpress.com +bum.net +bumpymail.com +bunchofidiots.com +bund.us +bundes-li.ga +bunsenhoneydew.com +burnthespam.info +burstmail.info +businessbackend.com +businesssuccessislifesuccess.com +buspad.org +bussitussi.com +buymoreplays.com +buyordie.info +buyusdomain.com +buyusedlibrarybooks.org +buzzcluby.com +byebyemail.com +byespm.com +byom.de +c51vsgq.com +cachedot.net +californiafitnessdeals.com +cam4you.cc +camping-grill.info +candymail.de +cane.pw +capitalistdilemma.com +car101.pro +carbtc.net +cars2.club +carsencyclopedia.com +cartelera.org +caseedu.tk +cashflow35.com +casualdx.com +cavi.mx +cbair.com +cbes.net +cc.liamria +ccmail.uk +cdfaq.com +cdpa.cc +ceed.se +cek.pm +cellurl.com +centermail.com +centermail.net +cetpass.com +cfo2go.ro +chacuo.net +chaichuang.com +chalupaurybnicku.cz +chammy.info +chasefreedomactivate.com +chatich.com +cheaphub.net +cheatmail.de +chenbot.email +chibakenma.ml +chickenkiller.com +chielo.com +childsavetrust.org +chilkat.com +chinamkm.com +chithinh.com +chitthi.in +choco.la +chogmail.com +choicemail1.com +chong-mail.com +chong-mail.net +chong-mail.org +chumpstakingdumps.com +cigar-auctions.com +civikli.com +civx.org +ckaazaza.tk +ckiso.com +cl-cl.org +cl0ne.net +claimab.com +clandest.in +classesmail.com +clearwatermail.info +click-email.com +clickdeal.co +clipmail.eu +clixser.com +clonemoi.tk +cloud-mail.top +cloudns.cx +clout.wiki +clrmail.com +cmail.club +cmail.com +cmail.net +cmail.org +cnamed.com +cndps.com +cnew.ir +cnmsg.net +cnsds.de +co.cc +cobarekyo1.ml +cocoro.uk +cocovpn.com +codeandscotch.com +codivide.com +coffeetimer24.com +coieo.com +coin-host.net +coinlink.club +coldemail.info +compareshippingrates.org +completegolfswing.com +comwest.de +conf.work +consumerriot.com +contbay.com +cooh-2.site +coolandwacky.us +coolimpool.org +coreclip.com +cosmorph.com +courrieltemporaire.com +coza.ro +crankhole.com +crapmail.org +crastination.de +crazespaces.pw +crazymailing.com +cream.pink +crepeau12.com +cringemonster.com +cross-law.ga +cross-law.gq +crossmailjet.com +crossroadsmail.com +crunchcompass.com +crusthost.com +cs.email +csh.ro +cszbl.com +ctmailing.us +ctos.ch +cu.cc +cubiclink.com +cuendita.com +cuirushi.org +cuoly.com +cupbest.com +curlhph.tk +curryworld.de +cust.in +cutout.club +cutradition.com +cuvox.de +cyber-innovation.club +cyber-phone.eu +cylab.org +d1yun.com +d3p.dk +daabox.com +dab.ro +dacoolest.com +daemsteam.com +daibond.info +daily-email.com +daintly.com +damai.webcam +dammexe.net +damnthespam.com +dandikmail.com +darkharvestfilms.com +daryxfox.net +dasdasdascyka.tk +dash-pads.com +dataarca.com +datarca.com +datazo.ca +datenschutz.ru +datum2.com +davidkoh.net +davidlcreative.com +dawin.com +daymail.life +daymailonline.com +dayrep.com +dbunker.com +dcctb.com +dcemail.com +ddcrew.com +de-a.org +dea-21olympic.com +deadaddress.com +deadchildren.org +deadfake.cf +deadfake.ga +deadfake.ml +deadfake.tk +deadspam.com +deagot.com +dealja.com +dealrek.com +deekayen.us +defomail.com +degradedfun.net +deinbox.com +delayload.com +delayload.net +delikkt.de +delivrmail.com +demen.ml +dengekibunko.ga +dengekibunko.gq +dengekibunko.ml +der-kombi.de +derkombi.de +derluxuswagen.de +desoz.com +despam.it +despammed.com +dev-null.cf +dev-null.ga +dev-null.gq +dev-null.ml +developermail.com +devnullmail.com +deyom.com +dharmatel.net +dhm.ro +dhy.cc +dialogus.com +diapaulpainting.com +dicopto.com +digdig.org +digital-message.com +digitalesbusiness.info +digitalmail.info +digitalmariachis.com +digitalsanctuary.com +dildosfromspace.com +dim-coin.com +dingbone.com +diolang.com +directmail24.net +disaq.com +disbox.net +disbox.org +discard.cf +discard.email +discard.ga +discard.gq +discard.ml +discard.tk +discardmail.com +discardmail.de +discos4.com +disign-concept.eu +disign-revelation.com +dispo.in +dispomail.eu +disposable-e.ml +disposable-email.ml +disposable.cf +disposable.ga +disposable.ml +disposable.site +disposableaddress.com +disposableemailaddresses.com +disposableinbox.com +disposablemails.com +dispose.it +disposeamail.com +disposemail.com +disposemymail.com +dispostable.com +divad.ga +divermail.com +divismail.ru +diwaq.com +dlemail.ru +dmarc.ro +dndent.com +dnses.ro +doanart.com +dob.jp +dodgeit.com +dodgemail.de +dodgit.com +dodgit.org +dodsi.com +doiea.com +dolphinnet.net +domforfb1.tk +domforfb18.tk +domforfb19.tk +domforfb2.tk +domforfb23.tk +domforfb27.tk +domforfb29.tk +domforfb3.tk +domforfb4.tk +domforfb5.tk +domforfb6.tk +domforfb7.tk +domforfb8.tk +domforfb9.tk +domozmail.com +donemail.ru +dongqing365.com +dontreg.com +dontsendmespam.de +doojazz.com +doquier.tk +dotman.de +dotmsg.com +dotslashrage.com +doublemail.de +douchelounge.com +dozvon-spb.ru +dp76.com +dr69.site +drdrb.com +drdrb.net +dred.ru +drevo.si +drivetagdev.com +drmail.in +droolingfanboy.de +dropcake.de +dropjar.com +droplar.com +dropmail.me +dropsin.net +dsgvo.ru +dsiay.com +dspwebservices.com +duam.net +duck2.club +dudmail.com +duk33.com +dukedish.com +dump-email.info +dumpandjunk.com +dumpmail.de +dumpyemail.com +durandinterstellar.com +duskmail.com +dwse.edu.pl +dyceroprojects.com +dz17.net +e-mail.com +e-mail.org +e-marketstore.ru +e-tomarigi.com +e3z.de +e4ward.com +eanok.com +easy-trash-mail.com +easynetwork.info +easytrashmail.com +eatmea2z.club +eay.jp +ebbob.com +ebeschlussbuch.de +ecallheandi.com +ecolo-online.fr +edgex.ru +edinburgh-airporthotels.com +edv.to +ee1.pl +ee2.pl +eeedv.de +eelmail.com +efxs.ca +egzones.com +einmalmail.de +einrot.com +einrot.de +eintagsmail.de +elearningjournal.org +electro.mn +elitevipatlantamodels.com +elki-mkzn.ru +email-fake.cf +email-fake.com +email-fake.ga +email-fake.gq +email-fake.ml +email-fake.tk +email-jetable.fr +email-lab.com +email-temp.com +email.edu.pl +email.net +email1.pro +email60.com +emailage.cf +emailage.ga +emailage.gq +emailage.ml +emailage.tk +emailate.com +emailcu.icu +emaildienst.de +emaildrop.io +emailfake.com +emailfake.ml +emailfreedom.ml +emailgenerator.de +emailgo.de +emailias.com +emailigo.de +emailinfive.com +emailisvalid.com +emaillime.com +emailmiser.com +emailna.co +emailnax.com +emailo.pro +emailondeck.com +emailportal.info +emailproxsy.com +emailresort.com +emails.ga +emailsecurer.com +emailsensei.com +emailsingularity.net +emailspam.cf +emailspam.ga +emailspam.gq +emailspam.ml +emailspam.tk +emailsy.info +emailtech.info +emailtemporanea.com +emailtemporanea.net +emailtemporar.ro +emailtemporario.com.br +emailthe.net +emailtmp.com +emailto.de +emailure.net +emailwarden.com +emailxfer.com +emailz.cf +emailz.ga +emailz.gq +emailz.ml +emeil.in +emeil.ir +emeraldwebmail.com +emil.com +emkei.cf +emkei.ga +emkei.gq +emkei.ml +emkei.tk +eml.pp.ua +emlhub.com +emlpro.com +emltmp.com +empireanime.ga +emstjzh.com +emz.net +enayu.com +enterto.com +envy17.com +eoffice.top +eoopy.com +epb.ro +ephemail.net +ephemeral.email +eposta.buzz +eposta.work +eqiluxspam.ga +ereplyzy.com +ericjohnson.ml +ero-tube.org +esadverse.com +esbano-ru.ru +esc.la +escapehatchapp.com +esemay.com +esgeneri.com +esiix.com +esprity.com +estate-invest.fr +eth2btc.info +ether123.net +ethereum1.top +ethersports.org +ethersportz.info +etotvibor.ru +etranquil.com +etranquil.net +etranquil.org +euaqa.com +evanfox.info +eveav.com +evilcomputer.com +evopo.com +evyush.com +exdonuts.com +existiert.net +exitstageleft.net +explodemail.com +express.net.ua +extracurricularsociety.com +extremail.ru +eyepaste.com +ez.lv +ezehe.com +ezfill.com +ezstest.com +f4k.es +f5.si +facebook-email.cf +facebook-email.ga +facebook-email.ml +facebookmail.gq +facebookmail.ml +fackme.gq +fadingemail.com +faecesmail.me +fag.wf +failbone.com +faithkills.com +fake-box.com +fake-email.pp.ua +fake-mail.cf +fake-mail.ga +fake-mail.ml +fakedemail.com +fakeinbox.cf +fakeinbox.com +fakeinbox.ga +fakeinbox.info +fakeinbox.ml +fakeinbox.tk +fakeinformation.com +fakemail.fr +fakemail.io +fakemailgenerator.com +fakemailz.com +fallinhay.com +fammix.com +fanclub.pm +fangoh.com +fansworldwide.de +fantasymail.de +farrse.co.uk +fast-email.info +fast-mail.fr +fastacura.com +fastchevy.com +fastchrysler.com +fasternet.biz +fastkawasaki.com +fastmazda.com +fastmitsubishi.com +fastnissan.com +fastsubaru.com +fastsuzuki.com +fasttoyota.com +fastyamaha.com +fatflap.com +fbma.tk +fddns.ml +fdfdsfds.com +femailtor.com +fer-gabon.org +fermaxxi.ru +fettometern.com +fexbox.org +fexbox.ru +fexpost.com +fextemp.com +ficken.de +fictionsite.com +fightallspam.com +figjs.com +figshot.com +figurescoin.com +fiifke.de +filbert4u.com +filberts4u.com +film-blog.biz +filzmail.com +findemail.info +findu.pl +finews.biz +fir.hk +firemailbox.club +fitnesrezink.ru +fivemail.de +fixmail.tk +fizmail.com +fleckens.hu +flemail.ru +flowu.com +flu.cc +fluidsoft.us +flurred.com +fly-ts.de +flyinggeek.net +flyspam.com +foobarbot.net +footard.com +foreastate.com +forecastertests.com +foreskin.cf +foreskin.ga +foreskin.gq +foreskin.ml +foreskin.tk +forgetmail.com +fornow.eu +forspam.net +forward.cat +fosil.pro +foxja.com +foxtrotter.info +fr.cr +fr.nf +fr33mail.info +fragolina2.tk +frapmail.com +frappina.tk +free-email.cf +free-email.ga +free-temp.net +freebabysittercam.com +freeblackbootytube.com +freecat.net +freedom4you.info +freedompop.us +freefattymovies.com +freehotmail.net +freeinbox.email +freelance-france.eu +freeletter.me +freemail.ms +freemails.cf +freemails.ga +freemails.ml +freemeil.ga +freemeil.gq +freemeil.ml +freeml.net +freeplumpervideos.com +freerubli.ru +freeschoolgirlvids.com +freesistercam.com +freeteenbums.com +freundin.ru +friendlymail.co.uk +front14.org +frwdmail.com +ftp.sh +ftpinc.ca +fuckedupload.com +fuckingduh.com +fuckme69.club +fucknloveme.top +fuckxxme.top +fudgerub.com +fuirio.com +fukaru.com +fukurou.ch +fullangle.org +fulvie.com +fun64.com +funnycodesnippets.com +funnymail.de +furzauflunge.de +futuramind.com +fuwamofu.com +fuwari.be +fux0ringduh.com +fxnxs.com +fyii.de +g14l71lb.com +g1xmail.top +g2xmail.top +g3xmail.top +g4hdrop.us +gafy.net +gage.ga +galaxy.tv +gally.jp +gamail.top +gamegregious.com +gamgling.com +garasikita.pw +garbagecollector.org +garbagemail.org +gardenscape.ca +garizo.com +garliclife.com +garrymccooey.com +gav0.com +gawab.com +gbcmail.win +gbmail.top +gcmail.top +gdmail.top +gedmail.win +geekforex.com +geew.ru +gehensiemirnichtaufdensack.de +geldwaschmaschine.de +gelitik.in +genderfuck.net +geronra.com +geschent.biz +get-mail.cf +get-mail.ga +get-mail.ml +get-mail.tk +get.pp.ua +get1mail.com +get2mail.fr +getairmail.cf +getairmail.com +getairmail.ga +getairmail.gq +getairmail.ml +getairmail.tk +geteit.com +getfun.men +getmails.eu +getnada.com +getnowtoday.cf +getonemail.com +getonemail.net +getover.de +getsimpleemail.com +gett.icu +gexik.com +ggmal.ml +ghosttexter.de +giacmosuaviet.info +giaiphapmuasam.com +giantmail.de +gifto12.com +ginzi.be +ginzi.co.uk +ginzi.es +ginzi.net +ginzy.co.uk +ginzy.eu +girlmail.win +girlsindetention.com +girlsundertheinfluence.com +gishpuppy.com +giveh2o.info +givememail.club +givmail.com +glitch.sx +globaltouron.com +glubex.com +glucosegrin.com +gmal.com +gmatch.org +gmial.com +gmx1mail.top +gmxmail.top +gmxmail.win +gnctr-calgary.com +go2usa.info +go2vpn.net +goemailgo.com +golemico.com +gomail.in +goonby.com +goplaygame.ru +gorillaswithdirtyarmpits.com +goround.info +gosuslugi-spravka.ru +gothere.biz +gotmail.com +gotmail.net +gotmail.org +gowikibooks.com +gowikicampus.com +gowikicars.com +gowikifilms.com +gowikigames.com +gowikimusic.com +gowikinetwork.com +gowikitravel.com +gowikitv.com +grandmamail.com +grandmasmail.com +great-host.in +greencafe24.com +greendike.com +greenhousemail.com +greensloth.com +greggamel.com +greggamel.net +gregorsky.zone +gregorygamel.com +gregorygamel.net +grish.de +griuc.schule +grn.cc +groupbuff.com +grr.la +grugrug.ru +gruz-m.ru +gs-arc.org +gsredcross.org +gsrv.co.uk +gsxstring.ga +gudanglowongan.com +guerillamail.biz +guerillamail.com +guerillamail.de +guerillamail.info +guerillamail.net +guerillamail.org +guerillamailblock.com +guerrillamail.biz +guerrillamail.com +guerrillamail.de +guerrillamail.info +guerrillamail.net +guerrillamail.org +guerrillamailblock.com +gufum.com +gustr.com +gxemail.men +gynzi.co.uk +gynzi.es +gynzy.at +gynzy.es +gynzy.eu +gynzy.gr +gynzy.info +gynzy.lt +gynzy.mobi +gynzy.pl +gynzy.ro +gynzy.sk +gzb.ro +h8s.org +habitue.net +hacccc.com +hackersquad.tk +hackthatbit.ch +hahawrong.com +haida-edu.cn +hairs24.ru +haltospam.com +hamham.uk +hangxomcuatoilatotoro.ml +happydomik.ru +harakirimail.com +haribu.com +hartbot.de +hasanmail.ml +hat-geld.de +hatespam.org +hawrong.com +haydoo.com +hazelnut4u.com +hazelnuts4u.com +hazmatshipping.org +hccmail.win +headstrong.de +heathenhammer.com +heathenhero.com +hecat.es +heisei.be +hellodream.mobi +helloricky.com +helpinghandtaxcenter.org +helpjobs.ru +heros3.com +herp.in +herpderp.nl +hezll.com +hi5.si +hiddentragedy.com +hidebox.org +hidebusiness.xyz +hidemail.de +hidemail.pro +hidemail.us +hidzz.com +highbros.org +hiltonvr.com +himail.online +hmail.us +hmamail.com +hmh.ro +hoanggiaanh.com +hoanglong.tech +hochsitze.com +hola.org +holl.ga +honeys.be +honor-8.com +hopemail.biz +hornyalwary.top +host1s.com +hostcalls.com +hostguru.top +hostingmail.me +hostlaba.com +hot-mail.cf +hot-mail.ga +hot-mail.gq +hot-mail.ml +hot-mail.tk +hotmai.com +hotmailproduct.com +hotmial.com +hotpop.com +hotprice.co +hotsoup.be +housat.com +hpc.tw +hs.vc +ht.cx +huangniu8.com +hukkmu.tk +hulapla.de +humaility.com +hungpackage.com +hushmail.cf +huskion.net +hvastudiesucces.nl +hwsye.net +i2pmail.org +i6.cloudns.cc +iaoss.com +ibnuh.bz +icantbelieveineedtoexplainthisshit.com +icemail.club +ichigo.me +icx.in +icx.ro +idx4.com +idxue.com +ieatspam.eu +ieatspam.info +ieh-mail.de +iencm.com +iffymedia.com +ige.es +igg.biz +ignoremail.com +ihateyoualot.info +ihazspam.ca +iheartspam.org +ikbenspamvrij.nl +illistnoise.com +ilovespam.com +imail1.net +imails.info +imailt.com +imgof.com +imgv.de +immo-gerance.info +imstations.com +imul.info +in-ulm.de +in2reach.com +inactivemachine.com +inbax.tk +inbound.plus +inbox.si +inbox2.info +inboxalias.com +inboxbear.com +inboxclean.com +inboxclean.org +inboxdesign.me +inboxed.im +inboxed.pw +inboxkitten.com +inboxproxy.com +inboxstore.me +inclusiveprogress.com +incognitomail.com +incognitomail.net +incognitomail.org +incq.com +ind.st +indieclad.com +indirect.ws +indomaed.pw +indomina.cf +indoserver.stream +indosukses.press +ineec.net +infocom.zp.ua +inggo.org +inkomail.com +inmynetwork.tk +inoutmail.de +inoutmail.eu +inoutmail.info +inoutmail.net +inpwa.com +insanumingeniumhomebrew.com +insorg-mail.info +instaddr.ch +instance-email.com +instant-mail.de +instantblingmail.info +instantemailaddress.com +instantmail.fr +internet-v-stavropole.ru +internetoftags.com +interstats.org +intersteller.com +intopwa.com +intopwa.net +intopwa.org +investore.co +iozak.com +ip4.pp.ua +ip6.li +ip6.pp.ua +ipoo.org +ippandansei.tk +ipsur.org +irabops.com +irc.so +irish2me.com +irishspringrealty.com +iroid.com +ironiebehindert.de +irssi.tv +is.af +isdaq.com +ishop2k.com +isosq.com +istii.ro +isukrainestillacountry.com +it7.ovh +italy-mail.com +itcompu.com +itfast.net +itunesgiftcodegenerator.com +iubridge.com +iuemail.men +iwi.net +ixaks.com +ixx.io +j-p.us +jafps.com +jajxz.com +janproz.com +jaqis.com +jdmadventures.com +jdz.ro +je-recycle.info +jellow.ml +jellyrolls.com +jeoce.com +jet-renovation.fr +jetable.com +jetable.net +jetable.org +jetable.pp.ua +jiooq.com +jmail.ovh +jmail.ro +jnxjn.com +jobbikszimpatizans.hu +jobbrett.com +jobposts.net +jobs-to-be-done.net +joelpet.com +joetestalot.com +jopho.com +joseihorumon.info +josse.ltd +jourrapide.com +jpco.org +jsrsolutions.com +jumonji.tk +jungkamushukum.com +junk.to +junk1e.com +junkmail.ga +junkmail.gq +just-email.com +justemail.ml +juyouxi.com +jwork.ru +kademen.com +kadokawa.cf +kadokawa.ga +kadokawa.gq +kadokawa.ml +kadokawa.tk +kaengu.ru +kagi.be +kakadua.net +kalapi.org +kamen-market.ru +kamsg.com +kaovo.com +kappala.info +kara-turk.net +karatraman.ml +kariplan.com +karta-kykyruza.ru +kartvelo.com +kasmail.com +kaspop.com +katztube.com +kazelink.ml +kbox.li +kcrw.de +keepmymail.com +keinhirn.de +keipino.de +kekita.com +kellychibale-researchgroup-uct.com +kemptvillebaseball.com +kennedy808.com +kiani.com +killmail.com +killmail.net +kimsdisk.com +kingsq.ga +kino-100.ru +kiois.com +kismail.ru +kisstwink.com +kitnastar.com +kjkszpjcompany.com +kkmail.be +kksm.be +klassmaster.com +klassmaster.net +klick-tipp.us +klipschx12.com +kloap.com +kludgemush.com +klzlk.com +kmail.li +kmhow.com +knol-power.nl +kobrandly.com +kommunity.biz +kon42.com +konultant-jurist.ru +kook.ml +kopagas.com +kopaka.net +korona-nedvizhimosti.ru +koshu.ru +kosmetik-obatkuat.com +kostenlosemailadresse.de +koszmail.pl +kpay.be +kpooa.com +kpost.be +krd.ag +krsw.tk +kruay.com +krypton.tk +ksmtrck.tk +kuhrap.com +kulmeo.com +kulturbetrieb.info +kurzepost.de +kutakbisajauhjauh.gq +kvhrr.com +kvhrs.com +kvhrw.com +kwift.net +kwilco.net +kyal.pl +kyois.com +kzccv.com +l-c-a.us +l33r.eu +l6factors.com +labetteraverouge.at +labworld.org +lacedmail.com +lackmail.net +lackmail.ru +lacto.info +lags.us +lain.ch +lak.pp.ua +lakelivingstonrealestate.com +lakqs.com +lamasticots.com +landmail.co +laoeq.com +larisia.com +larland.com +last-chance.pro +lastmail.co +lastmail.com +lawlita.com +lazyinbox.com +lazyinbox.us +ldaho.biz +ldop.com +ldtp.com +le-tim.ru +lee.mx +leeching.net +leetmail.co +legalrc.loan +lellno.gq +lenovog4.com +lerbhe.com +letmeinonthis.com +letthemeatspam.com +lez.se +lgxscreen.com +lhsdv.com +liamcyrus.com +lifebyfood.com +lifetimefriends.info +lifetotech.com +ligsb.com +lillemap.net +lilo.me +lindenbaumjapan.com +link2mail.net +linkedintuts2016.pw +linshiyouxiang.net +linuxmail.so +litedrop.com +liveradio.tk +lkgn.se +llogin.ru +loadby.us +loan101.pro +loaoa.com +loapq.com +locanto1.club +locantofuck.top +locantowsite.club +locomodev.net +login-email.cf +login-email.ga +login-email.ml +login-email.tk +logular.com +loh.pp.ua +loin.in +lolfreak.net +lolmail.biz +lookugly.com +lordsofts.com +lortemail.dk +losemymail.com +lovemeet.faith +lovemeleaveme.com +lpfmgmtltd.com +lr7.us +lr78.com +lroid.com +lru.me +ls-server.ru +lsyx24.com +luckymail.org +lukecarriere.com +lukemail.info +lukop.dk +luv2.us +lyfestylecreditsolutions.com +lyft.live +lyricspad.net +lzoaq.com +m21.cc +m4ilweb.info +maboard.com +mac-24.com +macr2.com +macromaid.com +macromice.info +magamail.com +maggotymeat.ga +magicbox.ro +magim.be +magspam.net +maidlow.info +mail-card.net +mail-easy.fr +mail-filter.com +mail-help.net +mail-hosting.co +mail-hub.info +mail-now.top +mail-owl.com +mail-share.com +mail-temporaire.com +mail-temporaire.fr +mail-tester.com +mail.by +mail.wtf +mail0.ga +mail1.top +mail114.net +mail1a.de +mail1web.org +mail21.cc +mail22.club +mail2rss.org +mail333.com +mail4trash.com +mail666.ru +mail7.io +mail707.com +mail72.com +mailapp.top +mailback.com +mailbidon.com +mailbiz.biz +mailblocks.com +mailbox.in.ua +mailbox52.ga +mailbox80.biz +mailbox82.biz +mailbox87.de +mailbox92.biz +mailboxy.fun +mailbucket.org +mailcat.biz +mailcatch.com +mailchop.com +mailcker.com +maildax.me +mailde.de +mailde.info +maildrop.cc +maildrop.cf +maildrop.ga +maildrop.gq +maildrop.ml +maildu.de +maildx.com +maileater.com +mailed.in +mailed.ro +maileimer.de +maileme101.com +mailexpire.com +mailf5.com +mailfa.tk +mailfall.com +mailfirst.icu +mailforspam.com +mailfree.ga +mailfree.gq +mailfree.ml +mailfreeonline.com +mailfs.com +mailguard.me +mailgutter.com +mailhazard.com +mailhazard.us +mailhex.com +mailhub.pro +mailhz.me +mailimate.com +mailin8r.com +mailinatar.com +mailinater.com +mailinator.co.uk +mailinator.com +mailinator.gq +mailinator.info +mailinator.net +mailinator.org +mailinator.us +mailinator0.com +mailinator1.com +mailinator2.com +mailinator2.net +mailinator3.com +mailinator4.com +mailinator5.com +mailinator6.com +mailinator7.com +mailinator8.com +mailinator9.com +mailincubator.com +mailismagic.com +mailita.tk +mailjunk.cf +mailjunk.ga +mailjunk.gq +mailjunk.ml +mailjunk.tk +mailmate.com +mailme.gq +mailme.ir +mailme.lv +mailme24.com +mailmetrash.com +mailmoat.com +mailmoth.com +mailms.com +mailna.biz +mailna.co +mailna.in +mailna.me +mailnator.com +mailnesia.com +mailnull.com +mailonaut.com +mailorc.com +mailorg.org +mailosaur.net +mailox.fun +mailpick.biz +mailpluss.com +mailpooch.com +mailpoof.com +mailpress.gq +mailproxsy.com +mailquack.com +mailrock.biz +mailsac.com +mailscrap.com +mailseal.de +mailshell.com +mailshiv.com +mailsiphon.com +mailslapping.com +mailslite.com +mailsucker.net +mailt.net +mailt.top +mailtechx.com +mailtemp.info +mailtemporaire.com +mailtemporaire.fr +mailto.plus +mailtome.de +mailtothis.com +mailtraps.com +mailtrash.net +mailtrix.net +mailtv.net +mailtv.tv +mailuniverse.co.uk +mailzi.ru +mailzilla.com +mailzilla.org +mainerfolg.info +makemenaughty.club +makemetheking.com +malahov.de +malayalamdtp.com +mama3.org +mamulenok.ru +mandraghen.cf +manifestgenerator.com +mannawo.com +mansiondev.com +manybrain.com +mark-compressoren.ru +marketlink.info +markmurfin.com +mask03.ru +masonline.info +maswae.world +matamuasu.ga +matchpol.net +matra.site +max-mail.org +mbox.re +mbx.cc +mcache.net +mciek.com +mdhc.tk +meantinc.com +mebelnu.info +mechanicalresumes.com +medkabinet-uzi.ru +meepsheep.eu +meidecn.com +meinspamschutz.de +meltedbrownies.com +meltmail.com +memsg.site +mentonit.net +mepost.pw +merry.pink +messagebeamer.de +messwiththebestdielikethe.rest +metadownload.org +metaintern.net +metalunits.com +mezimages.net +mfsa.info +mfsa.ru +mhzayt.online +miaferrari.com +miauj.com +midcoastcustoms.com +midcoastcustoms.net +midcoastsolutions.com +midcoastsolutions.net +midiharmonica.com +midlertidig.com +midlertidig.net +midlertidig.org +mierdamail.com +migmail.net +migmail.pl +migumail.com +mihep.com +mijnhva.nl +ministry-of-silly-walks.de +minsmail.com +mintemail.com +mirai.re +misterpinball.de +miucce.com +mji.ro +mjj.edu.ge +mjukglass.nu +mkpfilm.com +ml8.ca +mm.my +mm5.se +mnode.me +moakt.cc +moakt.co +moakt.com +moakt.ws +mobileninja.co.uk +mobilevpn.top +moburl.com +mockmyid.com +moeri.org +mofu.be +mohmal.com +mohmal.im +mohmal.in +mohmal.tech +moimoi.re +molms.com +momentics.ru +monachat.tk +monadi.ml +moneypipe.net +monumentmail.com +moonwake.com +moot.es +moreawesomethanyou.com +moreorcs.com +morriesworld.ml +morsin.com +moruzza.com +motique.de +mountainregionallibrary.net +mox.pp.ua +moy-elektrik.ru +moza.pl +mozej.com +mp-j.ga +mr24.co +mrvpm.net +mrvpt.com +msgos.com +mspeciosa.com +msrc.ml +mswork.ru +msxd.com +mt2009.com +mt2014.com +mt2015.com +mtmdev.com +muathegame.com +muchomail.com +mucincanon.com +muehlacker.tk +muell.icu +muell.monster +muell.xyz +muellemail.com +muellmail.com +munoubengoshi.gq +musiccode.me +mutant.me +mvrht.com +mvrht.net +mwarner.org +mxclip.com +mxfuel.com +my-pomsies.ru +my-teddyy.ru +my10minutemail.com +mybitti.de +mycleaninbox.net +mycorneroftheinter.net +myde.ml +mydefipet.live +mydemo.equipment +myecho.es +myemailboxy.com +mygeoweb.info +myindohome.services +myinterserver.ml +mykickassideas.com +mymail-in.net +mymail90.com +mymailoasis.com +mynetstore.de +myopang.com +mypacks.net +mypartyclip.de +myphantomemail.com +mysamp.de +myspaceinc.com +myspaceinc.net +myspaceinc.org +myspacepimpedup.com +myspamless.com +mystvpn.com +mysugartime.ru +mytemp.email +mytempemail.com +mytempmail.com +mytrashmail.com +mywarnernet.net +mywrld.site +mywrld.top +myzx.com +mzico.com +n1nja.org +na-cat.com +nabuma.com +nada.email +nada.ltd +nagi.be +nakedtruth.biz +nanonym.ch +naslazhdai.ru +nationalgardeningclub.com +nawmin.info +nbzmr.com +negated.com +neko2.net +nekochan.fr +neomailbox.com +neotlozhniy-zaim.ru +nepwk.com +nervmich.net +nervtmich.net +net1mail.com +netcom.ws +netmails.com +netmails.net +netricity.nl +netris.net +netviewer-france.com +netzidiot.de +nevermail.de +newbpotato.tk +newfilm24.ru +newideasfornewpeople.info +newmail.top +next.ovh +nextmail.info +nextstopvalhalla.com +nezdiro.org +nezid.com +nezumi.be +nezzart.com +nfast.net +nguyenusedcars.com +nh3.ro +nice-4u.com +nicknassar.com +nincsmail.com +nincsmail.hu +niseko.be +niwl.net +nm7.cc +nmail.cf +nnh.com +nnot.net +nnoway.ru +no-spam.ws +no-ux.com +noblepioneer.com +nobugmail.com +nobulk.com +nobuma.com +noclickemail.com +nodezine.com +nogmailspam.info +noicd.com +nokiamail.com +nolemail.ga +nomail.cf +nomail.ga +nomail.pw +nomail2me.com +nomorespamemails.com +nonspam.eu +nonspammer.de +nonze.ro +noref.in +norseforce.com +norwegischlernen.info +nospam4.us +nospamfor.us +nospamthanks.info +nothingtoseehere.ca +notif.me +notmailinator.com +notrnailinator.com +notsharingmy.info +now.im +nowhere.org +nowmymail.com +nowmymail.net +nproxi.com +nthrl.com +ntlhelp.net +nubescontrol.com +nullbox.info +nurfuerspam.de +nut.cc +nutpa.net +nuts2trade.com +nvhrw.com +nwldx.com +nwytg.com +nwytg.net +ny7.me +nypato.com +nyrmusic.com +o2stk.org +o7i.net +oalsp.com +obfusko.com +objectmail.com +obobbo.com +oborudovanieizturcii.ru +obxpestcontrol.com +octovie.com +odaymail.com +odem.com +odnorazovoe.ru +oepia.com +oerpub.org +offshore-proxies.net +ohaaa.de +ohi.tw +oida.icu +oing.cf +okclprojects.com +okinawa.li +okrent.us +okzk.com +olimp-case.ru +olypmall.ru +omail.pro +omnievents.org +omtecha.com +one-mail.top +one-time.email +one2mail.info +onekisspresave.com +onemail.host +oneoffemail.com +oneoffmail.com +onetm.jp +onewaymail.com +onlatedotcom.info +online.ms +onlineidea.info +onqin.com +ontyne.biz +oohioo.com +oolus.com +oonies-shoprus.ru +oopi.org +oosln.com +opayq.com +openavz.com +opendns.ro +opentrash.com +opmmedia.ga +opp24.com +optimaweb.me +opwebw.com +oranek.com +ordinaryamerican.net +oreidresume.com +orgmbx.cc +oroki.de +oshietechan.link +otherinbox.com +ourklips.com +ourpreviewdomain.com +outlawspam.com +outmail.win +ovomail.co +ovpn.to +owleyes.ch +owlpic.com +ownsyou.de +oxopoha.com +ozyl.de +p-banlis.ru +p33.org +p71ce1m.com +pa9e.com +pachilly.com +packiu.com +pagamenti.tk +paharpurmim.ga +pakadebu.ga +pamaweb.com +pancakemail.com +papierkorb.me +paplease.com +para2019.ru +parlimentpetitioner.tk +pastebitch.com +patonce.com +pavilionx2.com +payperex2.com +payspun.com +pe.hu +pecinan.com +pecinan.net +pecinan.org +penisgoes.in +penoto.tk +pepbot.com +peterdethier.com +petloca.com +petrzilka.net +pewpewpewpew.pw +pfui.ru +phone-elkey.ru +photo-impact.eu +photomark.net +pi.vu +piaa.me +pig.pp.ua +pii.at +piki.si +pimpedupmyspace.com +pinehill-seattle.org +pingir.com +pipemail.space +pisls.com +pitaniezdorovie.ru +pivo-bar.ru +pixiil.com +pjjkp.com +placebomail10.com +pleasenoham.org +plexfirm.com +plexolan.de +plhk.ru +ploae.com +plw.me +poehali-otdihat.ru +pojok.ml +pokemail.net +pokiemobile.com +polarkingxx.ml +politikerclub.de +polyfaust.net +pooae.com +poofy.org +pookmail.com +poopiebutt.club +popcornfarm7.com +popcornfly.com +popesodomy.com +popgx.com +porjoton.com +porsh.net +posdz.com +posta.store +postacin.com +postonline.me +poutineyourface.com +powered.name +powerencry.com +powlearn.com +pp7rvv.com +ppetw.com +pptrvv.com +pqoia.com +pratikmail.com +pratikmail.net +pratikmail.org +prazdnik-37.ru +predatorrat.cf +predatorrat.ga +predatorrat.gq +predatorrat.ml +predatorrat.tk +premium-mail.fr +primabananen.net +prin.be +privacy.net +privatdemail.net +privy-mail.com +privy-mail.de +privymail.de +pro-tag.org +pro5g.com +procrackers.com +profast.top +projectcl.com +promailt.com +proprietativalcea.ro +propscore.com +protempmail.com +proxymail.eu +proxyparking.com +prtnx.com +prtshr.com +prtz.eu +psh.me +psles.com +psnator.com +psoxs.com +puglieisi.com +puji.pro +punkass.com +puppetmail.de +purcell.email +purelogistics.org +put2.net +puttanamaiala.tk +putthisinyourspamdatabase.com +pwrby.com +qasti.com +qbfree.us +qc.to +qibl.at +qiott.com +qipmail.net +qiq.us +qisdo.com +qisoa.com +qmrbe.com +qoika.com +qopow.com +qq.my +qsl.ro +qtum-ico.com +quadrafit.com +quick-mail.cc +quickemail.info +quickinbox.com +quickmail.nl +quicksend.ch +ququb.com +qvy.me +qwickmail.com +r4nd0m.de +ra3.us +rabin.ca +rabiot.reisen +rackabzar.com +raetp9.com +rainbowly.ml +raketenmann.de +rancidhome.net +randomail.io +randomail.net +rapt.be +raqid.com +rax.la +raxtest.com +razemail.com +razuz.com +rbb.org +rcasd.com +rcpt.at +rdklcrv.xyz +re-gister.com +reality-concept.club +reallymymail.com +realtyalerts.ca +rebates.stream +receiveee.com +recipeforfailure.com +recode.me +reconmail.com +recyclemail.dk +redfeathercrow.com +reftoken.net +regbypass.com +regspaces.tk +reimondo.com +rejectmail.com +rejo.technology +reliable-mail.com +remail.cf +remail.ga +remarkable.rocks +remote.li +reptilegenetics.com +resgedvgfed.tk +revolvingdoorhoax.org +rfc822.org +rhyta.com +richfinances.pw +riddermark.de +rifkian.ga +rippb.com +risingsuntouch.com +riski.cf +rklips.com +rkomo.com +rm2rf.com +rma.ec +rmqkr.net +rnailinator.com +ro.lt +robertspcrepair.com +robot-mail.com +rollindo.agency +ronnierage.net +rootfest.net +rosebearmylove.ru +rotaniliam.com +rover.info +rowe-solutions.com +royal.net +royaldoodles.org +royalmarket.life +royandk.com +rppkn.com +rsvhr.com +rtrtr.com +rtskiya.xyz +rudymail.ml +rumgel.com +runi.ca +rupayamail.com +ruru.be +rustydoor.com +rvb.ro +ryteto.me +s0ny.net +s33db0x.com +sabrestlouis.com +sackboii.com +saeoil.com +safaat.cf +safermail.info +safersignup.de +safetymail.info +safetypost.de +saharanightstempe.com +salmeow.tk +samsclass.info +sandcars.net +sandelf.de +sandwhichvideo.com +sanfinder.com +sanim.net +sanstr.com +sast.ro +satisfyme.club +satukosong.com +sausen.com +saynotospams.com +scatmail.com +scay.net +schachrol.com +schafmail.de +schmeissweg.tk +schrott-email.de +scrsot.com +sd3.in +sdvft.com +sdvgeft.com +sdvrecft.com +secmail.pw +secretemail.de +secure-mail.biz +secure-mail.cc +secured-link.net +securehost.com.es +seekapps.com +seekjobs4u.com +sejaa.lv +selfdestructingmail.com +selfdestructingmail.org +send22u.info +sendfree.org +sendingspecialflyers.com +sendnow.win +sendspamhere.com +senseless-entertainment.com +server.ms +services391.com +sexforswingers.com +sexical.com +sexyalwasmi.top +shadap.org +shalar.net +sharedmailbox.org +sharklasers.com +sheryli.com +shhmail.com +shhuut.org +shieldedmail.com +shieldemail.com +shiftmail.com +shipfromto.com +shiphazmat.org +shipping-regulations.com +shippingterms.org +shitaway.tk +shitmail.de +shitmail.me +shitmail.org +shmeriously.com +shopxda.com +shortmail.net +shotmail.ru +showslow.de +shrib.com +shut.name +shut.ws +siberpay.com +sidelka-mytischi.ru +siftportal.ru +sify.com +sika3.com +sikux.com +siliwangi.ga +silvercoin.life +sim-simka.ru +simaenaga.com +simpleitsecurity.info +sin.cl +sinaite.net +sinema.ml +sinfiltro.cl +singlespride.com +sinnlos-mail.de +sino.tw +siteposter.net +sizzlemctwizzle.com +sjuaq.com +skeefmail.com +skrx.tk +sky-inbox.com +sky-ts.de +skyrt.de +slapsfromlastnight.com +slaskpost.se +slave-auctions.net +slippery.email +slipry.net +slopsbox.com +slothmail.net +slushmail.com +sluteen.com +sly.io +smallker.tk +smapfree24.com +smapfree24.de +smapfree24.eu +smapfree24.info +smapfree24.org +smartnator.com +smarttalent.pw +smashmail.de +smellfear.com +smellrear.com +smellypotato.tk +smtp99.com +smwg.info +snakemail.com +snapwet.com +sneakmail.de +snece.com +social-mailer.tk +socialfurry.org +sofia.re +sofimail.com +sofort-mail.de +sofortmail.de +sofrge.com +softkey-office.ru +softpls.asia +sogetthis.com +sohai.ml +sohus.cn +soioa.com +soisz.com +solar-impact.pro +solvemail.info +solventtrap.wiki +songsign.com +sonshi.cf +soodmail.com +soodomail.com +soodonims.com +soombo.com +soon.it +spacebazzar.ru +spam-be-gone.com +spam.care +spam.la +spam.org.es +spam.su +spam4.me +spamail.de +spamarrest.com +spamavert.com +spambob.com +spambob.net +spambob.org +spambog.com +spambog.de +spambog.net +spambog.ru +spambooger.com +spambox.info +spambox.me +spambox.org +spambox.us +spamcero.com +spamcon.org +spamcorptastic.com +spamcowboy.com +spamcowboy.net +spamcowboy.org +spamday.com +spamdecoy.net +spamex.com +spamfighter.cf +spamfighter.ga +spamfighter.gq +spamfighter.ml +spamfighter.tk +spamfree.eu +spamfree24.com +spamfree24.de +spamfree24.eu +spamfree24.info +spamfree24.net +spamfree24.org +spamgoes.in +spamherelots.com +spamhereplease.com +spamhole.com +spamify.com +spaminator.de +spamkill.info +spaml.com +spaml.de +spamlot.net +spammer.fail +spammotel.com +spammy.host +spamobox.com +spamoff.de +spamsalad.in +spamslicer.com +spamsphere.com +spamspot.com +spamstack.net +spamthis.co.uk +spamthis.network +spamthisplease.com +spamtrail.com +spamtrap.ro +spamtroll.net +spamwc.cf +spamwc.ga +spamwc.gq +spamwc.ml +speedgaus.net +sperma.cf +spikio.com +spindl-e.com +spoofmail.de +spr.io +spritzzone.de +spruzme.com +spybox.de +spymail.com +squizzy.de +squizzy.net +sroff.com +sry.li +ssoia.com +stanfordujjain.com +starlight-breaker.net +starpower.space +startfu.com +startkeys.com +statdvr.com +stathost.net +statiix.com +stayhome.li +steam-area.ru +steambot.net +stexsy.com +stinkefinger.net +stop-my-spam.cf +stop-my-spam.com +stop-my-spam.ga +stop-my-spam.ml +stop-my-spam.pp.ua +stop-my-spam.tk +stopspam.app +storiqax.top +storj99.com +storj99.top +streetwisemail.com +stromox.com +stuckmail.com +stuffmail.de +stumpfwerk.com +stylist-volos.ru +submic.com +suburbanthug.com +suckmyd.com +sueshaw.com +suexamplesb.com +suioe.com +super-auswahl.de +supergreatmail.com +supermailer.jp +superplatyna.com +superrito.com +supersave.net +superstachel.de +superyp.com +suremail.info +sute.jp +svip520.cn +svk.jp +svxr.org +sweetpotato.ml +sweetxxx.de +swift-mail.net +swift10minutemail.com +syinxun.com +sylvannet.com +symphonyresume.com +syosetu.gq +syujob.accountants +szerz.com +tafmail.com +tafoi.gr +taglead.com +tagmymedia.com +tagyourself.com +talkinator.com +tanukis.org +tapchicuoihoi.com +taphear.com +tapi.re +tarzanmail.cf +tastrg.com +taukah.com +tb-on-line.net +tcwlm.com +tcwlx.com +tdtda.com +tech69.com +techblast.ch +techemail.com +techgroup.me +technoproxy.ru +teerest.com +teewars.org +tefl.ro +telecomix.pl +teleg.eu +teleworm.com +teleworm.us +tellos.xyz +teml.net +temp-link.net +temp-mail.com +temp-mail.de +temp-mail.org +temp-mail.pp.ua +temp-mail.ru +temp-mails.com +tempail.com +tempalias.com +tempe-mail.com +tempemail.biz +tempemail.co.za +tempemail.com +tempemail.net +tempinbox.co.uk +tempinbox.com +tempmail.cn +tempmail.co +tempmail.de +tempmail.eu +tempmail.it +tempmail.pp.ua +tempmail.us +tempmail.ws +tempmail2.com +tempmaildemo.com +tempmailer.com +tempmailer.de +tempmailer.net +tempmailo.com +tempomail.fr +tempomail.org +temporarily.de +temporarioemail.com.br +temporary-mail.net +temporaryemail.net +temporaryemail.us +temporaryforwarding.com +temporaryinbox.com +temporarymailaddress.com +tempr.email +tempsky.com +tempthe.net +tempymail.com +tensi.org +ternaklele.ga +testore.co +testudine.com +thanksnospam.info +thankyou2010.com +thatim.info +thc.st +theaviors.com +thebearshark.com +thecarinformation.com +thechildrensfocus.com +thecity.biz +thecloudindex.com +thediamants.org +thedirhq.info +theeyeoftruth.com +thejoker5.com +thelightningmail.net +thelimestones.com +thembones.com.au +themegreview.com +themostemail.com +thereddoors.online +theroyalweb.club +thescrappermovie.com +theteastory.info +thex.ro +thichanthit.com +thietbivanphong.asia +thisisnotmyrealemail.com +thismail.net +thisurl.website +thnikka.com +thoas.ru +thraml.com +thrma.com +throam.com +thrott.com +throwam.com +throwawayemailaddress.com +throwawaymail.com +throwawaymail.pp.ua +throya.com +thrubay.com +thunderbolt.science +thunkinator.org +thxmate.com +tiapz.com +tic.ec +tilien.com +timgiarevn.com +timkassouf.com +tinoza.org +tinyurl24.com +tipsb.com +tittbit.in +tiv.cc +tizi.com +tkitc.de +tlpn.org +tmail.com +tmail.ws +tmailinator.com +tmails.net +tmmbt.net +tmpbox.net +tmpemails.com +tmpeml.com +tmpeml.info +tmpjr.me +tmpmail.net +tmpmail.org +tmpx.sa.com +toddsbighug.com +tofeat.com +toiea.com +tokem.co +tokenmail.de +tonaeto.com +tonne.to +tonymanso.com +toomail.biz +toon.ml +top-shop-tovar.ru +top101.de +top1mail.ru +top1post.ru +topinrock.cf +topmail2.com +topmail2.net +topofertasdehoy.com +topranklist.de +toprumours.com +tormail.org +toss.pw +tosunkaya.com +totallynotfake.net +totalvista.com +totesmail.com +totoan.info +tourcc.com +tp-qa-mail.com +tpwlb.com +tqoai.com +tqosi.com +tradermail.info +tranceversal.com +trash-amil.com +trash-mail.at +trash-mail.cf +trash-mail.com +trash-mail.de +trash-mail.ga +trash-mail.gq +trash-mail.ml +trash-mail.tk +trash-me.com +trash2009.com +trash2010.com +trash2011.com +trashcanmail.com +trashdevil.com +trashdevil.de +trashemail.de +trashemails.de +trashinbox.com +trashmail.at +trashmail.com +trashmail.de +trashmail.gq +trashmail.io +trashmail.me +trashmail.net +trashmail.org +trashmail.ws +trashmailer.com +trashmailgenerator.de +trashmails.com +trashymail.com +trashymail.net +trasz.com +trayna.com +trbvm.com +trbvn.com +trbvo.com +trend-maker.ru +trgfu.com +trgovinanaveliko.info +trialmail.de +trickmail.net +trillianpro.com +triots.com +trixtrux1.ru +trollproject.com +tropicalbass.info +trungtamtoeic.com +truthfinderlogin.com +tryalert.com +tryninja.io +tryzoe.com +ttirv.org +ttszuo.xyz +tualias.com +tuofs.com +turoid.com +turual.com +turuma.com +tutuapp.bid +tvchd.com +tverya.com +twinmail.de +twkly.ml +twocowmail.net +twoweirdtricks.com +twzhhq.online +txen.de +txtadvertise.com +tyhe.ro +tyldd.com +tympe.net +uacro.com +uber-mail.com +ubismail.net +ubm.md +ucche.us +ucupdong.ml +uemail99.com +ufacturing.com +uggsrock.com +uguuchantele.com +uhe2.com +uhhu.ru +uiu.us +ujijima1129.gq +uk.to +ultra.fyi +ultrada.ru +uma3.be +umail.net +undo.it +unicodeworld.com +unids.com +unimark.org +unit7lahaina.com +unmail.ru +uooos.com +upliftnow.com +uplipht.com +uploadnolimit.com +upozowac.info +urfunktion.se +urhen.com +uroid.com +us.af +us.to +usa.cc +usako.net +usbc.be +used-product.fr +ushijima1129.cf +ushijima1129.ga +ushijima1129.gq +ushijima1129.ml +ushijima1129.tk +utiket.us +uu.gl +uu2.ovh +uuf.me +uwork4.us +uyhip.com +vaasfc4.tk +vaati.org +valemail.net +valhalladev.com +vankin.de +vctel.com +vda.ro +vddaz.com +vdig.com +veanlo.com +vemomail.win +venompen.com +veo.kr +ver0.cf +ver0.ga +ver0.gq +ver0.ml +ver0.tk +vercelli.cf +vercelli.ga +vercelli.gq +vercelli.ml +verdejo.com +vermutlich.net +veryday.ch +veryday.eu +veryday.info +veryrealemail.com +vesa.pw +vevs.de +vfemail.net +via.tokyo.jp +vickaentb.tk +victime.ninja +victoriantwins.com +vidchart.com +viditag.com +viewcastmedia.com +viewcastmedia.net +viewcastmedia.org +vikingsonly.com +vinernet.com +vintomaper.com +vipepe.com +vipmail.name +vipmail.pw +vipxm.net +viralplays.com +virtualemail.info +visal007.tk +visal168.cf +visal168.ga +visal168.gq +visal168.ml +visal168.tk +vixletdev.com +vixtricks.com +vkcode.ru +vmailing.info +vmani.com +vmpanda.com +vnedu.me +voidbay.com +volaj.com +voltaer.com +vomoto.com +vorga.org +votiputox.org +voxelcore.com +vpn.st +vps30.com +vps911.net +vradportal.com +vremonte24-store.ru +vrmtr.com +vsimcard.com +vssms.com +vtxmail.us +vubby.com +vuiy.pw +vusra.com +vztc.com +w-asertun.ru +w3internet.co.uk +wakingupesther.com +walala.org +walkmail.net +walkmail.ru +wallm.com +wanko.be +watch-harry-potter.com +watchever.biz +watchfull.net +watchironman3onlinefreefullmovie.com +wazabi.club +wbdev.tech +wbml.net +web-contact.info +web-ideal.fr +web-inc.net +web-mail.pp.ua +web2mailco.com +webcontact-france.eu +webemail.me +webhook.site +webm4il.info +webmail24.top +webtrip.ch +webuser.in +wee.my +wef.gr +weg-werf-email.de +wegwerf-email-addressen.de +wegwerf-email-adressen.de +wegwerf-email.at +wegwerf-email.de +wegwerf-email.net +wegwerf-emails.de +wegwerfadresse.de +wegwerfemail.com +wegwerfemail.de +wegwerfemail.info +wegwerfemail.net +wegwerfemail.org +wegwerfemailadresse.com +wegwerfmail.de +wegwerfmail.info +wegwerfmail.net +wegwerfmail.org +wegwerpmailadres.nl +wegwrfmail.de +wegwrfmail.net +wegwrfmail.org +wekawa.com +welikecookies.com +wellsfargocomcardholders.com +wemel.top +wetrainbayarea.com +wetrainbayarea.org +wfgdfhj.tk +wg0.com +wh4f.org +whatiaas.com +whatifanalytics.com +whatpaas.com +whatsaas.com +whiffles.org +whopy.com +whyspam.me +wibblesmith.com +wickmail.net +widaryanto.info +widget.gg +wierie.tk +wifimaple.com +wifioak.com +wikidocuslava.ru +wilemail.com +willhackforfood.biz +willselfdestruct.com +wimsg.com +winemaven.info +wins.com.br +wlist.ro +wmail.cf +wmail.club +wokcy.com +wolfmail.ml +wolfsmail.tk +wollan.info +worldspace.link +wpdork.com +wpg.im +wralawfirm.com +writeme.us +wronghead.com +ws.gy +wsym.de +wudet.men +wuespdj.xyz +wupics.com +wuuvo.com +wuzup.net +wuzupmail.net +wwjmp.com +wwwnew.eu +wxnw.net +x24.com +xagloo.co +xagloo.com +xbaby69.top +xcode.ro +xcodes.net +xcompress.com +xcoxc.com +xcpy.com +xemaps.com +xemne.com +xents.com +xjoi.com +xkx.me +xl.cx +xmail.com +xmailer.be +xmaily.com +xn--9kq967o.com +xn--d-bga.net +xojxe.com +xost.us +xoxox.cc +xperiae5.com +xrap.de +xrho.com +xvx.us +xwaretech.com +xwaretech.info +xwaretech.net +xww.ro +xxhamsterxx.ga +xxi2.com +xxlocanto.us +xxolocanto.us +xxqx3802.com +xy9ce.tk +xyzfree.net +xzsok.com +yabai-oppai.tk +yahmail.top +yahooproduct.net +yamail.win +yanet.me +yannmail.win +yapped.net +yaqp.com +yarnpedia.ga +ycare.de +ycn.ro +ye.vc +yedi.org +yeezus.ru +yep.it +yermail.net +yhg.biz +ynmrealty.com +yodx.ro +yogamaven.com +yoggm.com +yomail.info +yoo.ro +yopmail.com +yopmail.fr +yopmail.gq +yopmail.net +yopmail.pp.ua +yordanmail.cf +you-spam.com +yougotgoated.com +youmail.ga +youmailr.com +youneedmore.info +youpymail.com +yourdomain.com +youremail.cf +yourewronghereswhy.com +yourlms.biz +yourspamgoesto.space +yourtube.ml +yroid.com +yspend.com +ytpayy.com +yugasandrika.com +yui.it +yuoia.com +yuurok.com +yxzx.net +yyolf.net +z-o-e-v-a.ru +z0d.eu +z1p.biz +z86.ru +zain.site +zainmax.net +zaktouni.fr +zarabotokdoma11.ru +zasod.com +zaym-zaym.ru +zcrcd.com +zdenka.net +ze.tc +zebins.com +zebins.eu +zehnminuten.de +zehnminutenmail.de +zepp.dk +zetmail.com +zfymail.com +zhaoqian.ninja +zhaoyuanedu.cn +zhcne.com +zhewei88.com +zhorachu.com +zik.dj +zipcad.com +zipo1.gq +zippymail.info +zipsendtest.com +zoaxe.com +zoemail.com +zoemail.net +zoemail.org +zoetropes.org +zombie-hive.com +zomg.info +zsero.com +zumpul.com +zv68.com +zxcv.com +zxcvbnm.com +zymuying.com +zzi.us +zzrgg.com +zzz.com diff --git a/backend-pg/src/lib/validator/index.ts b/backend-pg/src/lib/validator/index.ts new file mode 100644 index 000000000..6bc415680 --- /dev/null +++ b/backend-pg/src/lib/validator/index.ts @@ -0,0 +1 @@ +export { isDisposableEmail } from "./validate-email"; diff --git a/backend-pg/src/lib/validator/validate-email.ts b/backend-pg/src/lib/validator/validate-email.ts new file mode 100644 index 000000000..ec3ef3976 --- /dev/null +++ b/backend-pg/src/lib/validator/validate-email.ts @@ -0,0 +1,10 @@ +import fs from "fs/promises"; +import path from "path"; + +export const isDisposableEmail = async (email: string) => { + const emailDomain = email.split("@")[1]; + const disposableEmails = await fs.readFile(path.join(__dirname, "disposable_emails.txt"), "utf8"); + + if (disposableEmails.split("\n").includes(emailDomain)) return true; + return false; +}; diff --git a/backend-pg/src/lib/zod/index.ts b/backend-pg/src/lib/zod/index.ts new file mode 100644 index 000000000..3b04f033e --- /dev/null +++ b/backend-pg/src/lib/zod/index.ts @@ -0,0 +1,12 @@ +import { z } from "zod"; + +// this is a patched zod string to remove empty string to undefined +export const zpStr = ( + schema: T, + opt: { stripNull: boolean } = { stripNull: true } +) => + z.preprocess((val) => { + if (opt.stripNull && val === null) return undefined; + if (typeof val !== "string") return val; + return val.trim() || undefined; + }, schema); diff --git a/backend-pg/src/server/app.ts b/backend-pg/src/server/app.ts index 079b25157..66f43073b 100644 --- a/backend-pg/src/server/app.ts +++ b/backend-pg/src/server/app.ts @@ -1,6 +1,5 @@ import dotenv from "dotenv"; import fasitfy from "fastify"; -import { z } from "zod"; import type { FastifyCookieOptions } from "@fastify/cookie"; import cookie from "@fastify/cookie"; import type { FastifyCorsOptions } from "@fastify/cors"; @@ -9,20 +8,24 @@ import helmet from "@fastify/helmet"; import type { FastifyRateLimitOptions } from "@fastify/rate-limit"; import ratelimiter from "@fastify/rate-limit"; -import { initEnvConfig } from "@lib/config/env"; +import { initDbConnection } from "@app/db"; +import { smtpServiceFactory } from "@app/services/smtp/smtp-service"; + +import { formatSmtpConfig, initEnvConfig } from "@lib/config/env"; import { initLogger } from "@lib/logger"; import { globalRateLimiterCfg } from "./config/rateLimiter"; import { serializerCompiler, validatorCompiler, ZodTypeProvider } from "./plugins/fastify-zod"; import { fastifyIp } from "./plugins/ip"; import { fastifySwagger } from "./plugins/swagger"; +import { registerRoutes } from "./routes"; dotenv.config(); // Run the server! const main = async () => { const logger = await initLogger(); - initEnvConfig(logger); + const envCfg = initEnvConfig(logger); const server = fasitfy({ logger, @@ -32,42 +35,31 @@ const main = async () => { server.setValidatorCompiler(validatorCompiler); server.setSerializerCompiler(serializerCompiler); + const db = initDbConnection(envCfg.DB_CONNECTION_URI); + const smtp = smtpServiceFactory(formatSmtpConfig()); + try { - // TODO(akhilmhdh:pg): change this to environment variable with default await server.register(cookie, { - secret: "infisical-cookie-secret" + secret: envCfg.COOKIE_SECRET_SIGN_KEY }); await server.register(cors, { credentials: true, - origin: "http://localhost:3000" + origin: true }); // pull ip based on various proxy headers await server.register(fastifyIp); - // Rate limiters and security headers - await server.register(ratelimiter, globalRateLimiterCfg); - await server.register(helmet); - await server.register(fastifySwagger); - // Declare a route - server.route({ - method: "GET", - url: "/", - schema: { - response: { - 200: z.object({ hello: z.string() }) - } - }, - handler: () => ({ - hello: "world" - }) - }); + // Rate limiters and security headers + await server.register(ratelimiter, globalRateLimiterCfg); + await server.register(helmet, { contentSecurityPolicy: false }); + await server.register(registerRoutes, { prefix: "/api", smtp, db }); await server.ready(); server.swagger(); - await server.listen({ port: 8000 }); + await server.listen({ port: envCfg.PORT, host: envCfg.HOST }); } catch (err) { server.log.error(err); process.exit(1); diff --git a/backend-pg/src/server/plugins/swagger.ts b/backend-pg/src/server/plugins/swagger.ts index 008994da6..6b8295a87 100644 --- a/backend-pg/src/server/plugins/swagger.ts +++ b/backend-pg/src/server/plugins/swagger.ts @@ -4,6 +4,7 @@ import swaggerUI from "@fastify/swagger-ui"; import { jsonSchemaTransform } from "./fastify-zod"; +// TODO(akhilmhdh-pg): change the localhost port later export const fastifySwagger = fp(async (fastify) => { await fastify.register(swagger, { transform: jsonSchemaTransform, @@ -15,12 +16,12 @@ export const fastifySwagger = fp(async (fastify) => { }, servers: [ { - url: "https://app.infisical.com", - description: "Production server" + url: "http://localhost:4000", + description: "Local server" }, { - url: "http://localhost:8000", - description: "Local server" + url: "https://app.infisical.com", + description: "Production server" } ], components: { diff --git a/backend-pg/src/server/routes/index.ts b/backend-pg/src/server/routes/index.ts new file mode 100644 index 000000000..3488843ad --- /dev/null +++ b/backend-pg/src/server/routes/index.ts @@ -0,0 +1,44 @@ +import { Knex } from "knex"; + +import { authDalFactory } from "@app/services/auth/auth-dal"; +import { authLoginServiceFactory } from "@app/services/auth/auth-login-service"; +import { authPaswordServiceFactory } from "@app/services/auth/auth-password-service"; +import { authSignupServiceFactory } from "@app/services/auth/auth-signup-service"; +import { TSmtpService } from "@app/services/smtp/smtp-service"; +import { tokenDalFactory } from "@app/services/token/token-dal"; +import { tokenServiceFactory } from "@app/services/token/token-service"; + +import { registerV1Routes } from "./v1"; +import { registerV2Routes } from "./v2"; +import { registerV3Routes } from "./v3"; + +export const registerRoutes = async ( + server: FastifyZodProvider, + { db, smtp }: { db: Knex; smtp: TSmtpService } +) => { + // db layers + const authDal = authDalFactory(db); + const authTokenDal = tokenDalFactory(db); + + // service layers + const tokenService = tokenServiceFactory({ tokenDal: authTokenDal }); + const loginService = authLoginServiceFactory({ authDal, smtpService: smtp, tokenService }); + const passwordService = authPaswordServiceFactory({ tokenService, smtpService: smtp, authDal }); + const signupService = authSignupServiceFactory({ tokenService, smtpService: smtp, authDal }); + + // inject all services + server.decorate("services", { + login: loginService, + password: passwordService, + signup: signupService + } as FastifyZodProvider["services"]); + + server.decorate("store", { + user: authDal + } as FastifyZodProvider["store"]); + + // register routes for v1 + await server.register(registerV1Routes, { prefix: "/v1" }); + await server.register(registerV2Routes, { prefix: "/v2" }); + await server.register(registerV3Routes, { prefix: "/v3" }); +}; diff --git a/backend-pg/src/server/routes/v1/index.ts b/backend-pg/src/server/routes/v1/index.ts new file mode 100644 index 000000000..086fee790 --- /dev/null +++ b/backend-pg/src/server/routes/v1/index.ts @@ -0,0 +1,5 @@ +import { registerPasswordRouter } from "./password-router"; + +export const registerV1Routes = async (server: FastifyZodProvider) => { + await server.register(registerPasswordRouter, { prefix: "/password" }); +}; diff --git a/backend-pg/src/server/routes/v1/password-router.ts b/backend-pg/src/server/routes/v1/password-router.ts new file mode 100644 index 000000000..d506f9814 --- /dev/null +++ b/backend-pg/src/server/routes/v1/password-router.ts @@ -0,0 +1,115 @@ +import { z } from "zod"; + +import { BackupPrivateKeySchema } from "@app/db/schemas"; +import { getConfig } from "@app/lib/config/env"; + +export const registerPasswordRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "POST", + url: "/srp1", + schema: { + body: z.object({ + clientPublicKey: z.string().trim() + }), + response: { + 200: z.object({ + serverPublicKey: z.string(), + salt: z.string() + }) + } + }, + handler: async (req) => { + const { salt, serverPublicKey } = await server.services.password.generateServerPubKey( + req.auth.userId, + req.body.clientPublicKey + ); + return { salt, serverPublicKey }; + } + }); + + server.route({ + method: "POST", + url: "/change-password", + schema: { + body: z.object({ + clientProof: z.string().trim(), + protectedKey: z.string().trim(), + protectedKeyIV: z.string().trim(), + protectedKeyTag: z.string().trim(), + encryptedPrivateKey: z.string().trim(), + encryptedPrivateKeyIV: z.string().trim(), + encryptedPrivateKeyTag: z.string().trim(), + salt: z.string().trim(), + verifier: z.string().trim() + }), + response: { + 200: z.object({ + message: z.string() + }) + } + }, + handler: async (req, res) => { + const appCfg = getConfig(); + await server.services.password.changePassword({ ...req.body, userId: req.auth.userId }); + + res.cookie("jid", appCfg.COOKIE_SECRET_SIGN_KEY, { + httpOnly: true, + path: "/", + sameSite: "strict", + secure: appCfg.HTTPS_ENABLED + }); + return { message: "Successfully changed password" }; + } + }); + + server.route({ + method: "POST", + url: "/backup-private-key", + schema: { + body: z.object({ + clientProof: z.string().trim(), + encryptedPrivateKey: z.string().trim(), + iv: z.string().trim(), + tag: z.string().trim(), + salt: z.string().trim(), + verifier: z.string().trim() + }), + response: { + 200: z.object({ + message: z.string(), + backupPrivateKey: BackupPrivateKeySchema + }) + } + }, + handler: async (req) => { + const backupPrivateKey = await server.services.password.createBackupPrivateKey({ + ...req.body, + userId: req.auth.userId + }); + if (!backupPrivateKey) throw new Error("Failed to create backup key"); + + return { message: "Successfully updated backup private key", backupPrivateKey }; + } + }); + + server.route({ + method: "GET", + url: "/backup-private-key", + schema: { + response: { + 200: z.object({ + message: z.string(), + backupPrivateKey: BackupPrivateKeySchema + }) + } + }, + handler: async (req) => { + const backupPrivateKey = await server.services.password.getBackupPrivateKeyOfUser( + req.auth.userId + ); + if (!backupPrivateKey) throw new Error("Failed to find backup key"); + + return { message: "Successfully updated backup private key", backupPrivateKey }; + } + }); +}; diff --git a/backend-pg/src/server/routes/v2/index.ts b/backend-pg/src/server/routes/v2/index.ts new file mode 100644 index 000000000..66bd9d695 --- /dev/null +++ b/backend-pg/src/server/routes/v2/index.ts @@ -0,0 +1,5 @@ +import { registerMfaRouter } from "./mfa-router"; + +export const registerV2Routes = async (server: FastifyZodProvider) => { + await server.register(registerMfaRouter, { prefix: "/auth" }); +}; diff --git a/backend-pg/src/server/routes/v2/mfa-router.ts b/backend-pg/src/server/routes/v2/mfa-router.ts new file mode 100644 index 000000000..b5fbfadcb --- /dev/null +++ b/backend-pg/src/server/routes/v2/mfa-router.ts @@ -0,0 +1,89 @@ +import jwt, { JwtPayload } from "jsonwebtoken"; +import { z } from "zod"; + +import { getConfig } from "@app/lib/config/env"; +import { AuthTokenType } from "@app/services/auth/auth-signup-type"; + +export const registerMfaRouter = async (server: FastifyZodProvider) => { + const cfg = getConfig(); + + server.addHook("preParsing", async (req, res) => { + const authorizationHeader = req.headers.authorization; + + if (!authorizationHeader || !authorizationHeader.startsWith("Bearer ")) { + res.status(401).send({ error: "Missing bearer token" }); + return; + } + const token = authorizationHeader.split(" ")[1]; + if (!token) res.status(401).send({ error: "Missing bearer token" }); + + const decodedToken = jwt.verify(token, cfg.JWT_AUTH_SECRET) as JwtPayload; + if (decodedToken.authTokenType !== AuthTokenType.MFA_TOKEN) + throw new Error("Unauthorized access"); + + const user = await server.store.user.getUserById(decodedToken.userId); + if (!user) throw new Error("User not found"); + req.mfa.userId = user.id; + req.mfa.user = user; + }); + + server.route({ + url: "/mfa/send", + method: "POST", + schema: { + response: { + 200: z.object({ + message: z.string() + }) + } + }, + handler: async (req) => { + await server.services.login.resendMfaToken(req.mfa.userId); + return { message: "Successfully send new mfa code" }; + } + }); + + server.route({ + url: "/mfa/verify", + method: "POST", + schema: { + body: z.object({ + mfaToken: z.string().trim() + }), + response: { + 200: z.object({ + encryptionVersion: z.number().default(1).optional(), + protectedKey: z.string(), + protectedKeyIV: z.string(), + protectedKeyTag: z.string(), + publicKey: z.string(), + encryptedPrivateKey: z.string(), + iv: z.string(), + tag: z.string(), + token: z.string() + }) + } + }, + handler: async (req, res) => { + const userAgent = req.headers["user-agent"]; + if (!userAgent) throw new Error("user agent header is required"); + const appCfg = getConfig(); + + const { user, token } = await server.services.login.verifyMfaToken({ + userAgent, + ip: req.realIp, + userId: req.mfa.userId, + mfaToken: req.body.mfaToken + }); + + res.setCookie("jid", token.refresh, { + httpOnly: true, + path: "/", + sameSite: "strict", + secure: appCfg.HTTPS_ENABLED + }); + + return { token: token.access, ...user }; + } + }); +}; diff --git a/backend-pg/src/server/routes/v3/index.ts b/backend-pg/src/server/routes/v3/index.ts new file mode 100644 index 000000000..982dee111 --- /dev/null +++ b/backend-pg/src/server/routes/v3/index.ts @@ -0,0 +1,7 @@ +import { registerLoginRouter } from "./login-router"; +import { registerSignupRouter } from "./signup-router"; + +export const registerV3Routes = async (server: FastifyZodProvider) => { + await server.register(registerSignupRouter, { prefix: "/signup" }); + await server.register(registerLoginRouter, { prefix: "/auth" }); +}; diff --git a/backend-pg/src/server/routes/v3/login-router.ts b/backend-pg/src/server/routes/v3/login-router.ts new file mode 100644 index 000000000..83fa5f89e --- /dev/null +++ b/backend-pg/src/server/routes/v3/login-router.ts @@ -0,0 +1,97 @@ +import { z } from "zod"; + +import { getConfig } from "@app/lib/config/env"; + +export const registerLoginRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "POST", + url: "/login1", + schema: { + body: z.object({ + email: z.string().email().trim(), + providerAuthToken: z.string().trim().optional(), + clientPublicKey: z.string().trim() + }), + response: { + 200: z.object({ + serverPublicKey: z.string(), + salt: z.string() + }) + } + }, + handler: async (req) => { + const { serverPublicKey, salt } = await server.services.login.loginGenServerPublicKey({ + email: req.body.email, + clientPublicKey: req.body.clientPublicKey, + providerAuthToken: req.body.providerAuthToken + }); + + return { serverPublicKey, salt }; + } + }); + + server.route({ + method: "POST", + url: "/login2", + schema: { + body: z.object({ + email: z.string().email().trim(), + providerAuthToken: z.string().trim().optional(), + clientProof: z.string().trim() + }), + response: { + 200: z.discriminatedUnion("mfaEnabled", [ + z.object({ mfaEnabled: z.literal(true), token: z.string() }), + z.object({ + mfaEnabled: z.literal(false), + encryptionVersion: z.number().default(1).optional(), + protectedKey: z.string(), + protectedKeyIV: z.string(), + protectedKeyTag: z.string(), + publicKey: z.string(), + encryptedPrivateKey: z.string(), + iv: z.string(), + tag: z.string(), + token: z.string() + }) + ]) + } + }, + handler: async (req, res) => { + const userAgent = req.headers["user-agent"]; + if (!userAgent) throw new Error("user agent header is required"); + const appCfg = getConfig(); + + const data = await server.services.login.loginExchangeClientProof({ + email: req.body.email, + ip: req.realIp, + userAgent, + clientProof: req.body.clientProof + }); + + if (data.isMfaEnabled) { + return { mfaEnabled: true, token: data.token } as const; // for discriminated union + } + + res.setCookie("jid", data.token.refresh, { + httpOnly: true, + path: "/", + sameSite: "strict", + secure: appCfg.HTTPS_ENABLED + }); + + return { + mfaEnabled: false, + encryptionVersion: data.user.encryptionVersion, + token: data.token.access, + publicKey: data.user.publicKey, + encryptedPrivateKey: data.user.encryptedPrivateKey, + iv: data.user.iv, + tag: data.user.tag, + protectedKey: data.user.protectedKey, + protectedKeyIV: data.user.protectedKeyIV, + protectedKeyTag: data.user.protectedKeyTag + } as const; + } + }); +}; diff --git a/backend-pg/src/server/routes/v3/signup-router.ts b/backend-pg/src/server/routes/v3/signup-router.ts new file mode 100644 index 000000000..ff6ec2036 --- /dev/null +++ b/backend-pg/src/server/routes/v3/signup-router.ts @@ -0,0 +1,103 @@ +import { z } from "zod"; + +import { UserSchema } from "@app/db/schemas"; +import { getConfig } from "@app/lib/config/env"; + +export const registerSignupRouter = async (server: FastifyZodProvider) => { + server.route({ + url: "/email/signup", + method: "POST", + schema: { + body: z.object({ + email: z.string().email().trim() + }), + response: { + 200: z.object({ + message: z.string() + }) + } + }, + handler: async (req) => { + await server.services.signup.beginEmailSignupProcess(req.body.email); + return { message: `Sent an email verification code to ${req.body.email}` }; + } + }); + + server.route({ + url: "/email/verify", + method: "POST", + schema: { + body: z.object({ + email: z.string().email().trim(), + code: z.string().trim() + }), + response: { + 200: z.object({ + message: z.string(), + token: z.string(), + user: UserSchema + }) + } + }, + handler: async (req) => { + const { token, user } = await server.services.signup.verifyEmailSignup( + req.body.email, + req.body.code + ); + return { message: "Successfuly verified email", token, user }; + } + }); + + server.route({ + url: "/complete-account/signup", + method: "POST", + schema: { + body: z.object({ + email: z.string().email().trim(), + firstName: z.string().trim(), + lastName: z.string().trim().optional(), + protectedKey: z.string().trim(), + protectedKeyIV: z.string().trim(), + protectedKeyTag: z.string().trim(), + publicKey: z.string().trim(), + encryptedPrivateKey: z.string().trim(), + encryptedPrivateKeyIV: z.string().trim(), + encryptedPrivateKeyTag: z.string().trim(), + salt: z.string().trim(), + verifier: z.string().trim(), + organizationName: z.string().trim(), + providerAuthToken: z.string().trim().optional().nullish(), + attributionSource: z.string().trim().optional() + }), + response: { + 200: z.object({ + message: z.string(), + user: UserSchema, + token: z.string() + }) + } + }, + handler: async (req, res) => { + const userAgent = req.headers["user-agent"]; + if (!userAgent) throw new Error("user agent header is required"); + const appCfg = getConfig(); + + const { user, accessToken, refreshToken } = + await server.services.signup.completeEmailAccountSignup({ + ...req.body, + ip: req.realIp, + userAgent + }); + + res.setCookie("jid", refreshToken, { + httpOnly: true, + path: "/", + sameSite: "strict", + secure: appCfg.HTTPS_ENABLED + }); + // TODO(akhilmhdh-pg): add telemetry service + + return { message: "Successfully set up account", user, token: accessToken }; + } + }); +}; diff --git a/backend-pg/src/services/auth/auth-dal.ts b/backend-pg/src/services/auth/auth-dal.ts new file mode 100644 index 000000000..eb539f911 --- /dev/null +++ b/backend-pg/src/services/auth/auth-dal.ts @@ -0,0 +1,131 @@ +import { Knex } from "knex"; + +import { TDbClient } from "@app/db"; +import { TableName, TBackupPrivateKey, TUser, TUserEncryptionKey } from "@app/db/schemas"; + +export type TAuthDalFactory = ReturnType; + +export const authDalFactory = (db: TDbClient) => { + // getters + const getUserByEmail = async (email: string): Promise => + db(TableName.Users).where({ email }).select("*").first(); + + const getUserById = async (userId: string): Promise => + db(TableName.Users).where({ id: userId }).select("*").first(); + + const getUserEncKeyByEmail = async (email: string) => + db(TableName.Users) + .where({ email }) + .join( + TableName.UserEncryptionKey, + `${TableName.Users}.id`, + `${TableName.UserEncryptionKey}.userId` + ) + .first(); + + const getUserEncKeyByUserId = async (userId: string) => + db(TableName.Users) + .where({ id: userId }) + .join( + TableName.UserEncryptionKey, + `${TableName.Users}.id`, + `${TableName.UserEncryptionKey}.userId` + ) + .first(); + + const getBackupPrivateKeyByUserId = async (userId: string) => + db(TableName.BackupPrivateKey).where({ userId }).first("*"); + + // all inserts and updates + const createUser = async ( + email: string, + data: Partial = {} + ): Promise => { + const [user] = await db(TableName.Users) + .insert({ email, ...data }) + .returning("*"); + return user; + }; + + const updateUser = async ( + email: string, + data: Partial = {} + ): Promise => { + const [user] = await db(TableName.Users) + .where({ email }) + .update({ ...data }) + .returning("*"); + return user; + }; + + const updateUserById = async ( + id: string, + data: Partial = {}, + tx?: Knex + ): Promise => { + const [user] = await (tx ? tx(TableName.Users) : db(TableName.Users)) + .where({ id }) + .update({ ...data }) + .returning("*"); + return user; + }; + + const updateUserEncryptionByUserId = async ( + userId: string, + data: Partial = {}, + tx?: Knex + ): Promise => { + const [userEnc] = await (tx ? tx(TableName.UserEncryptionKey) : db(TableName.UserEncryptionKey)) + .where({ userId }) + .update({ ...data }) + .returning("*"); + return userEnc; + }; + + // all upserts + const upsertUserEncryptionKey = async ( + userId: string, + data: Partial, + tx?: Knex + ) => { + const [userEnc] = await (tx ? tx(TableName.UserEncryptionKey) : db(TableName.UserEncryptionKey)) + // if user insert make sure to pass all required data + .insert({ userId, ...data } as TUserEncryptionKey) + .onConflict("userId") + .merge() + .returning("*"); + return userEnc; + }; + + const upsertBackupKey = async ( + userId: string, + data: Partial, + tx?: Knex + ): Promise => { + const [backupKey] = await (tx ? tx(TableName.BackupPrivateKey) : db(TableName.BackupPrivateKey)) + .insert({ userId, ...data, updatedAt: new Date().toUTCString() } as TBackupPrivateKey) + .onConflict("userId") + .merge() + .returning("*"); + return backupKey; + }; + + return { + transaction: async (cb: (tx: Knex) => T) => + db.transaction(async (trx) => { + const res = await cb(trx); + return res; + }), + getUserByEmail, + getUserById, + getUserEncKeyByEmail, + getUserEncKeyByUserId, + getBackupPrivateKeyByUserId, + createUser, + updateUser, + updateUserById, + updateUserEncryptionByUserId, + upsertUserEncryptionKey, + upsertBackupKey + }; +}; diff --git a/backend-pg/src/services/auth/auth-login-service.ts b/backend-pg/src/services/auth/auth-login-service.ts new file mode 100644 index 000000000..b1850e789 --- /dev/null +++ b/backend-pg/src/services/auth/auth-login-service.ts @@ -0,0 +1,249 @@ +import jwt from "jsonwebtoken"; + +import { AuthMethod, TUser } from "@app/db/schemas"; +import { UserDeviceSchema } from "@app/db/schemas/user"; +import { getConfig } from "@app/lib/config/env"; +import { generateSrpServerKey, srpCheckClientProof } from "@app/lib/crypto"; + +import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service"; +import { TTokenServiceFactory } from "../token/token-service"; +import { TokenType } from "../token/token-types"; +import { TAuthDalFactory } from "./auth-dal"; +import { + TLoginClientProofDTO, + TLoginGenServerPublicKeyDTO, + TVerifyMfaTokenDTO +} from "./auth-login-type"; +import { AuthTokenType } from "./auth-signup-type"; + +const isValidProviderAuthToken = (email: string, jwtSecret: string, providerAuthToken?: string) => { + if (!providerAuthToken) return false; + const decodedToken = jwt.verify(providerAuthToken, jwtSecret) as jwt.JwtPayload; + + if (decodedToken.authTokenType !== AuthTokenType.PROVIDER_TOKEN) return false; + if (decodedToken.email !== email) return false; + return true; +}; + +type TAuthLoginServiceFactoryDep = { + authDal: TAuthDalFactory; + tokenService: TTokenServiceFactory; + smtpService: TSmtpService; +}; + +export type TAuthLoginFactory = ReturnType; +export const authLoginServiceFactory = ({ + authDal, + tokenService, + smtpService +}: TAuthLoginServiceFactoryDep) => { + /* + * Private + * Not exported. This is to update user device list + * If new device is found. Will be saved and a mail will be send + */ + const updateUserDeviceSession = async (user: TUser, ip: string, userAgent: string) => { + const devices = await UserDeviceSchema.parseAsync(JSON.parse(user.devices || "[]")); + const isDeviceSeen = devices.some( + (device) => device.ip === ip && device.userAgent === userAgent + ); + + if (!isDeviceSeen) { + const newDeviceList = devices.concat([{ ip, userAgent }]); + await authDal.updateUserById(user.id, { devices: JSON.stringify(newDeviceList) }); + await smtpService.sendMail({ + template: SmtpTemplates.NewDeviceJoin, + subjectLine: "Successful login from new device", + recipients: [user.email], + substitutions: { + email: user.email, + timestamp: new Date().toString(), + ip, + userAgent + } + }); + } + }; + + /* + * Private + * Send mfa code via email + * */ + const sendUserMfaCode = async (user: TUser) => { + const code = await tokenService.createTokenForUser({ + type: TokenType.TOKEN_EMAIL_MFA, + userId: user.id + }); + + await smtpService.sendMail({ + template: SmtpTemplates.EmailMfa, + subjectLine: "Infisical MFA code", + recipients: [user.email], + substitutions: { + code + } + }); + }; + + /* Private + * Check user device and send mail if new device + * generate the auth and refresh token. fn shared by mfa verification and login verification with mfa disabled + */ + const generateUserTokens = async (user: TUser, ip: string, userAgent: string) => { + const cfg = getConfig(); + await updateUserDeviceSession(user, ip, userAgent); + const tokenSession = await tokenService.getUserTokenSession({ + userAgent, + ip, + userId: user.id + }); + if (!tokenSession) throw new Error("Failed to create token"); + const accessToken = jwt.sign( + { + authTokenType: AuthTokenType.ACCESS_TOKEN, + userId: user.id, + tokenVersionId: tokenSession.id, + accessVersion: tokenSession.accessVersion + }, + cfg.JWT_AUTH_SECRET, + { expiresIn: cfg.JWT_AUTH_LIFETIME } + ); + + const refreshToken = jwt.sign( + { + authTokenType: AuthTokenType.REFRESH_TOKEN, + userId: user.id, + tokenVersionId: tokenSession.id, + refreshVersion: tokenSession.refreshVersion + }, + cfg.JWT_AUTH_SECRET, + { expiresIn: cfg.JWT_REFRESH_LIFETIME } + ); + + return { access: accessToken, refresh: refreshToken }; + }; + + /* + * Step 1 of login. To get server public key in exchange of client public key + */ + const loginGenServerPublicKey = async ({ + email, + providerAuthToken, + clientPublicKey + }: TLoginGenServerPublicKeyDTO) => { + const user = await authDal.getUserEncKeyByEmail(email); + if (!user || (user && !user.isAccepted)) { + throw new Error("Failed to find user"); + } + const cfg = getConfig(); + + if ( + !user.authMethods?.includes(AuthMethod.EMAIL) && + !isValidProviderAuthToken(email, cfg.JWT_AUTH_SECRET, providerAuthToken) + ) { + throw new Error("Invalid authorization request"); + } + const serverSrpKey = await generateSrpServerKey(user.salt, user.verifier); + const userEncKeys = await authDal.updateUserEncryptionByUserId(user.id, { + clientPublicKey, + serverPrivateKey: serverSrpKey.privateKey + }); + if (!userEncKeys) throw new Error("Failed to update encryption key"); + return { salt: userEncKeys.salt, serverPublicKey: serverSrpKey.pubKey }; + }; + + /* + * Step 2 of login. Pass the client proof and with multi factor setup handle the required steps + */ + const loginExchangeClientProof = async ({ + email, + clientProof, + providerAuthToken, + ip, + userAgent + }: TLoginClientProofDTO) => { + const user = await authDal.getUserEncKeyByEmail(email); + if (!user) throw new Error("Failed to find user"); + const cfg = getConfig(); + + if ( + !user.authMethods?.includes(AuthMethod.EMAIL) && + !isValidProviderAuthToken(email, cfg.JWT_AUTH_SECRET, providerAuthToken) + ) { + throw new Error("Invalid authorization request"); + } + + if (!user.serverPrivateKey || !user.clientPublicKey) + throw new Error("Failed to authenticate. Try again?"); + const isValidClientProof = await srpCheckClientProof( + user.salt, + user.verifier, + user.serverPrivateKey, + user.clientPublicKey, + clientProof + ); + if (!isValidClientProof) throw new Error("Failed to authenticate. Try again?"); + + await authDal.updateUserEncryptionByUserId(user.id, { + serverPrivateKey: null, + clientPublicKey: null + }); + // send multi factor auth token if they it enabled + if (user.isMfaEnabled) { + const mfaToken = jwt.sign( + { authTokenType: AuthTokenType.MFA_TOKEN, userId: user.id }, + cfg.JWT_AUTH_SECRET, + { expiresIn: cfg.JWT_MFA_LIFETIME } + ); + await sendUserMfaCode(user); + + return { isMfaEnabled: true, token: mfaToken } as const; + } + + const token = await generateUserTokens(user, ip, userAgent); + return { token, isMfaEnabled: false, user } as const; + }; + + /* + * Multi factor authentication re-send code, Get user id from token + * saved in frontend + */ + const resendMfaToken = async (userId: string) => { + const user = await authDal.getUserById(userId); + if (!user) return; + await sendUserMfaCode(user); + }; + + /* + * Multi factor authentication verification of code + * Third step of login in which user completes with mfa + * */ + const verifyMfaToken = async ({ userId, mfaToken, ip, userAgent }: TVerifyMfaTokenDTO) => { + await tokenService.validateTokenForUser({ + type: TokenType.TOKEN_EMAIL_MFA, + userId, + code: mfaToken + }); + const user = await authDal.getUserEncKeyByUserId(userId); + if (!user) throw new Error("Failed to authenticate user"); + + const token = await generateUserTokens(user, ip, userAgent); + return { token, user }; + }; + + /* + * logout user by incrementing the version by 1 meaning any old session will become invalid + * as there number is behind + * */ + const logout = async (userId: string, sessionId: string) => { + await tokenService.clearTokenSessionById(userId, sessionId); + }; + + return { + loginGenServerPublicKey, + loginExchangeClientProof, + logout, + resendMfaToken, + verifyMfaToken + }; +}; diff --git a/backend-pg/src/services/auth/auth-login-type.ts b/backend-pg/src/services/auth/auth-login-type.ts new file mode 100644 index 000000000..e17e98fe1 --- /dev/null +++ b/backend-pg/src/services/auth/auth-login-type.ts @@ -0,0 +1,20 @@ +export type TLoginGenServerPublicKeyDTO = { + email: string; + clientPublicKey: string; + providerAuthToken?: string; +}; + +export type TLoginClientProofDTO = { + email: string; + clientProof: string; + providerAuthToken?: string; + ip: string; + userAgent: string; +}; + +export type TVerifyMfaTokenDTO = { + userId: string; + mfaToken: string; + ip: string; + userAgent: string; +}; diff --git a/backend-pg/src/services/auth/auth-password-service.ts b/backend-pg/src/services/auth/auth-password-service.ts new file mode 100644 index 000000000..ea41198a6 --- /dev/null +++ b/backend-pg/src/services/auth/auth-password-service.ts @@ -0,0 +1,257 @@ +import jwt from "jsonwebtoken"; + +import { getConfig } from "@app/lib/config/env"; +import { generateSrpServerKey, srpCheckClientProof } from "@app/lib/crypto"; + +import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service"; +import { TTokenServiceFactory } from "../token/token-service"; +import { TokenType } from "../token/token-types"; +import { TAuthDalFactory } from "./auth-dal"; +import { + TChangePasswordDTO, + TCreateBackupPrivateKeyDTO, + TResetPasswordViaBackupKeyDTO +} from "./auth-password-type"; +import { AuthTokenType } from "./auth-signup-type"; + +type TAuthPasswordServiceFactoryDep = { + authDal: TAuthDalFactory; + tokenService: TTokenServiceFactory; + smtpService: TSmtpService; +}; + +export type TAuthPasswordFactory = ReturnType; +export const authPaswordServiceFactory = ({ + authDal, + tokenService, + smtpService +}: TAuthPasswordServiceFactoryDep) => { + /* + * Pre setup for pass change with srp protocol + * Gets srp server user salt and server public key + */ + const generateServerPubKey = async (userId: string, clientPublicKey: string) => { + const user = await authDal.getUserEncKeyByUserId(userId); + if (!user) throw new Error("Failed to find user"); + + const serverSrpKey = await generateSrpServerKey(user.salt, user.verifier); + const userEncKeys = await authDal.updateUserEncryptionByUserId(user.id, { + clientPublicKey, + serverPrivateKey: serverSrpKey.privateKey + }); + if (!userEncKeys) throw new Error("Failed to update encryption key"); + return { salt: userEncKeys.salt, serverPublicKey: serverSrpKey.pubKey }; + }; + + /* + * Change password to new pass + * */ + const changePassword = async ({ + userId, + clientProof, + protectedKey, + protectedKeyIV, + protectedKeyTag, + encryptedPrivateKey, + encryptedPrivateKeyIV, + encryptedPrivateKeyTag, + salt, + verifier, + tokenVersionId + }: TChangePasswordDTO) => { + const userEnc = await authDal.getUserEncKeyByUserId(userId); + if (!userEnc) throw new Error("Failed to find user"); + + await authDal.updateUserEncryptionByUserId(userEnc.userId, { + serverPrivateKey: null, + clientPublicKey: null + }); + if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) + throw new Error("Failed to authenticate. Try again?"); + const isValidClientProof = await srpCheckClientProof( + userEnc.salt, + userEnc.verifier, + userEnc.serverPrivateKey, + userEnc.clientPublicKey, + clientProof + ); + if (!isValidClientProof) throw new Error("Failed to authenticate. Try again?"); + + await authDal.updateUserEncryptionByUserId(userId, { + encryptionVersion: 2, + protectedKey, + protectedKeyIV, + protectedKeyTag, + encryptedPrivateKey, + iv: encryptedPrivateKeyIV, + tag: encryptedPrivateKeyTag, + salt, + verifier, + serverPrivateKey: null, + clientPublicKey: null + }); + + if (tokenVersionId) { + await tokenService.clearTokenSessionById(userEnc.userId, tokenVersionId); + } + }; + + /* + * Email password reset flow via email. Step 1 send email + */ + const sendPasswordResetEmail = async (email: string) => { + const user = await authDal.getUserByEmail(email); + // ignore as user is not found to avoid an outside entity to identify infisical registered accounts + if (!user || (user && !user.isAccepted)) return; + + const cfg = getConfig(); + const token = await tokenService.createTokenForUser({ + type: TokenType.TOKEN_EMAIL_PASSWORD_RESET, + userId: user.id + }); + + await smtpService.sendMail({ + template: SmtpTemplates.ResetPassword, + recipients: [email], + subjectLine: "Infisical password reset", + substitutions: { + email, + token, + callback_url: cfg.SITE_URL ? `${cfg.SITE_URL}/password-reset` : "" + } + }); + }; + + /* + * Step 2 of reset password. Verify the token and inject a temp token to reset password + * */ + const verifyPasswordResetEmail = async (email: string, code: string) => { + const cfg = getConfig(); + const user = await authDal.getUserByEmail(email); + // ignore as user is not found to avoid an outside entity to identify infisical registered accounts + if (!user || (user && !user.isAccepted)) { + throw new Error("Failed email verification for pass reset"); + } + + await tokenService.validateTokenForUser({ + type: TokenType.TOKEN_EMAIL_PASSWORD_RESET, + userId: user.id, + code + }); + + const token = jwt.sign( + { + authTokenType: AuthTokenType.SIGNUP_TOKEN, + userId: user.id + }, + cfg.JWT_AUTH_SECRET, + { expiresIn: cfg.JWT_SIGNUP_LIFETIME } + ); + + return { token, user }; + }; + /* + * Reset password of a user via backup key + * */ + const resetPasswordByBackupKey = async ( + userId: string, + { + encryptedPrivateKey, + protectedKeyTag, + protectedKey, + protectedKeyIV, + salt, + verifier, + encryptedPrivateKeyIV, + encryptedPrivateKeyTag + }: TResetPasswordViaBackupKeyDTO + ) => { + await authDal.updateUserEncryptionByUserId(userId, { + encryptionVersion: 2, + protectedKey, + protectedKeyIV, + protectedKeyTag, + encryptedPrivateKey, + iv: encryptedPrivateKeyIV, + tag: encryptedPrivateKeyTag, + salt, + verifier + }); + }; + + /* + * backup key creation to give user's their access back when lost their password + * this also needs to do the generateServerPubKey function to be executed first + * then only client proof can be verified + * */ + const createBackupPrivateKey = async ({ + clientProof, + encryptedPrivateKey, + salt, + verifier, + iv, + tag, + userId + }: TCreateBackupPrivateKeyDTO) => { + const user = await authDal.getUserEncKeyByUserId(userId); + if (!user || (user && !user.isAccepted)) { + throw new Error("Failed to find user"); + } + + if (!user.clientPublicKey || !user.serverPrivateKey) + throw new Error("failed to create backup key"); + const isValidClientProff = await srpCheckClientProof( + user.salt, + user.verifier, + user.serverPrivateKey, + user.clientPublicKey, + clientProof + ); + if (!isValidClientProff) throw new Error("failed to create backup key"); + const backup = await authDal.transaction(async (tx) => { + const backupKey = await authDal.upsertBackupKey(user.id, { + encryptedPrivateKey, + iv, + tag, + salt, + verifier + }); + + await authDal.updateUserEncryptionByUserId( + user.id, + { + serverPrivateKey: null, + clientPublicKey: null + }, + tx + ); + return backupKey; + }); + + return backup; + }; + + /* + * Return user back up + * */ + const getBackupPrivateKeyOfUser = async (userId: string) => { + const user = await authDal.getUserEncKeyByUserId(userId); + if (!user || (user && !user.isAccepted)) { + throw new Error("Failed to find user"); + } + const backupKey = await authDal.getBackupPrivateKeyByUserId(userId); + if (!backupKey) throw new Error("Failed to find user backup key"); + + return backupKey; + }; + + return { + generateServerPubKey, + changePassword, + resetPasswordByBackupKey, + sendPasswordResetEmail, + verifyPasswordResetEmail, + createBackupPrivateKey, + getBackupPrivateKeyOfUser + }; +}; diff --git a/backend-pg/src/services/auth/auth-password-type.ts b/backend-pg/src/services/auth/auth-password-type.ts new file mode 100644 index 000000000..cf2aac08d --- /dev/null +++ b/backend-pg/src/services/auth/auth-password-type.ts @@ -0,0 +1,35 @@ +export type TChangePasswordDTO = { + userId: string; + clientProof: string; + protectedKey: string; + protectedKeyIV: string; + protectedKeyTag: string; + encryptedPrivateKey: string; + encryptedPrivateKeyIV: string; + encryptedPrivateKeyTag: string; + salt: string; + verifier: string; + tokenVersionId?: string; +}; + +export type TResetPasswordViaBackupKeyDTO = { + userId: string; + protectedKey: string; + protectedKeyIV: string; + protectedKeyTag: string; + encryptedPrivateKey: string; + encryptedPrivateKeyIV: string; + encryptedPrivateKeyTag: string; + salt: string; + verifier: string; +}; + +export type TCreateBackupPrivateKeyDTO = { + userId: string; + clientProof: string; + encryptedPrivateKey: string; + salt: string; + iv: string; + tag: string; + verifier: string; +}; diff --git a/backend-pg/src/services/auth/auth-signup-service.ts b/backend-pg/src/services/auth/auth-signup-service.ts new file mode 100644 index 000000000..ef2fafa3b --- /dev/null +++ b/backend-pg/src/services/auth/auth-signup-service.ts @@ -0,0 +1,169 @@ +import { AuthMethod } from "@app/db/schemas"; +import { getConfig } from "@app/lib/config/env"; +import { isDisposableEmail } from "@app/lib/validator"; + +import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service"; +import { TTokenServiceFactory } from "../token/token-service"; +import { TokenType } from "../token/token-types"; +import { TAuthDalFactory } from "./auth-dal"; +import { AuthTokenType, TCompleteAccountSignupDTO } from "./auth-signup-type"; + +type TAuthSignupDep = { + authDal: TAuthDalFactory; + tokenService: TTokenServiceFactory; + smtpService: TSmtpService; +}; + +export type TAuthSignupFactory = ReturnType; +export const authSignupServiceFactory = ({ + authDal, + tokenService, + smtpService +}: TAuthSignupDep) => { + // first step of signup. create user and send email + const beginEmailSignupProcess = async (email: string) => { + const isEmailInvalid = await isDisposableEmail(email); + if (isEmailInvalid) { + throw new Error("Provided a disposable email"); + } + + let user = await authDal.getUserByEmail(email); + if (user && user.isAccepted) { + // TODO(akhilmhdh-pg): copy as old one. this needs to be changed due to security issues + throw new Error("Failed to send verification code for complete account"); + } + if (!user) { + user = await authDal.createUser(email, { authMethods: [AuthMethod.EMAIL] }); + } + if (!user) throw new Error("Failed to create user"); + + const token = await tokenService.createTokenForUser({ + type: TokenType.TOKEN_EMAIL_CONFIRMATION, + userId: user.id + }); + + await smtpService.sendMail({ + template: SmtpTemplates.EmailVerification, + subjectLine: "Infisical confirmation code", + recipients: [email], + substitutions: { + code: token + } + }); + }; + + const verifyEmailSignup = async (email: string, code: string) => { + const user = await authDal.getUserByEmail(email); + if (!user || (user && user.isAccepted)) { + // TODO(akhilmhdh): copy as old one. this needs to be changed due to security issues + throw new Error("Failed to send verification code for complete account"); + } + const appCfg = getConfig(); + await tokenService.validateTokenForUser({ + type: TokenType.TOKEN_EMAIL_CONFIRMATION, + userId: user.id, + code + }); + + // generate jwt token this is a temporary token + const jwtToken = tokenService.createJwtToken( + { + authTokenType: AuthTokenType.SIGNUP_TOKEN, + userId: user.id.toString() + }, + appCfg.JWT_AUTH_SECRET, + { expiresIn: appCfg.JWT_SIGNUP_LIFETIME } + ); + + return { user, token: jwtToken }; + }; + + const completeEmailAccountSignup = async ({ + email, + firstName, + lastName, + // providerAuthToken, + salt, + verifier, + publicKey, + protectedKey, + protectedKeyIV, + protectedKeyTag, + // organizationName, + // attributionSource, + encryptedPrivateKey, + encryptedPrivateKeyIV, + encryptedPrivateKeyTag, + ip, + userAgent + }: TCompleteAccountSignupDTO) => { + const user = await authDal.getUserByEmail(email); + if (!user || (user && user.isAccepted)) { + throw new Error("Failed to complete account for complete user"); + } + + const updateduser = await authDal.transaction(async (tx) => { + const us = await authDal.updateUserById( + user.id, + { firstName, lastName, isAccepted: true }, + tx + ); + if (!us) throw new Error("User not found"); + const userEncKey = await authDal.upsertUserEncryptionKey( + us.id, + { + salt, + verifier, + publicKey, + protectedKey, + protectedKeyIV, + protectedKeyTag, + encryptedPrivateKey, + iv: encryptedPrivateKeyIV, + tag: encryptedPrivateKeyTag + }, + tx + ); + return { info: us, key: userEncKey }; + }); + + // TODO(akhilmhdh-pg): add default org memberships + const tokenSession = await tokenService.getUserTokenSession({ + userAgent, + ip, + userId: updateduser.info.id + }); + if (!tokenSession) throw new Error("Failed to create token"); + const appCfg = getConfig(); + + const accessToken = tokenService.createJwtToken( + { + authTokenType: AuthTokenType.ACCESS_TOKEN, + userId: updateduser.info.id, + tokenVersionId: tokenSession.id, + accessVersion: tokenSession.accessVersion + }, + appCfg.JWT_AUTH_SECRET, + { expiresIn: appCfg.JWT_SIGNUP_LIFETIME } + ); + + const refreshToken = tokenService.createJwtToken( + { + authTokenType: AuthTokenType.REFRESH_TOKEN, + userId: updateduser.info.id, + tokenVersionId: tokenSession.id, + refreshVersion: tokenSession.refreshVersion + }, + appCfg.JWT_AUTH_SECRET, + { expiresIn: appCfg.JWT_SIGNUP_LIFETIME } + ); + + return { user: updateduser.info, accessToken, refreshToken }; + }; + + return { + beginEmailSignupProcess, + verifyEmailSignup, + completeEmailAccountSignup + }; +}; diff --git a/backend-pg/src/services/auth/auth-signup-type.ts b/backend-pg/src/services/auth/auth-signup-type.ts new file mode 100644 index 000000000..ddfa15336 --- /dev/null +++ b/backend-pg/src/services/auth/auth-signup-type.ts @@ -0,0 +1,38 @@ +export enum AuthTokenType { + ACCESS_TOKEN = "accessToken", + REFRESH_TOKEN = "refreshToken", + SIGNUP_TOKEN = "signupToken", // TODO: remove in favor of claim + MFA_TOKEN = "mfaToken", // TODO: remove in favor of claim + PROVIDER_TOKEN = "providerToken", // TODO: remove in favor of claim + API_KEY = "apiKey", + SERVICE_ACCESS_TOKEN = "serviceAccessToken", + SERVICE_REFRESH_TOKEN = "serviceRefreshToken" +} + +export enum AuthMode { + JWT = "jwt", + SERVICE_TOKEN = "serviceToken", + SERVICE_ACCESS_TOKEN = "serviceAccessToken", + API_KEY = "apiKey", + API_KEY_V2 = "apiKeyV2" +} + +export type TCompleteAccountSignupDTO = { + email: string; + firstName: string; + lastName?: string; + protectedKey: string; + protectedKeyIV: string; + protectedKeyTag: string; + publicKey: string; + encryptedPrivateKey: string; + encryptedPrivateKeyIV: string; + encryptedPrivateKeyTag: string; + salt: string; + verifier: string; + organizationName: string; + providerAuthToken?: string | null; + attributionSource?: string | undefined; + ip: string; + userAgent: string; +}; diff --git a/backend-pg/src/services/smtp/smtp-service.ts b/backend-pg/src/services/smtp/smtp-service.ts new file mode 100644 index 000000000..a433c2025 --- /dev/null +++ b/backend-pg/src/services/smtp/smtp-service.ts @@ -0,0 +1,78 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import handlebars from "handlebars"; +import { createTransport } from "nodemailer"; +import SMTPTransport from "nodemailer/lib/smtp-transport"; + +import { logger } from "@app/lib/logger"; + +export type TSmtpConfig = SMTPTransport.Options; +export type TSmtpSendMail = { + template: SmtpTemplates; + subjectLine: string; + recipients: string[]; + substitutions: unknown; +}; +export type TSmtpService = ReturnType; + +export enum SmtpTemplates { + EmailVerification = "emailVerification.handlebars", + EmailMfa = "emailMfa.handlebars", + HistoricalSecretList = "historicalSecretLeakIncident.handlebars", + NewDeviceJoin = "newDevice.handlebars", + OrgInvite = "organizationInvitation.handlebars", + ResetPassword = "passwordReset.handlebars", + SecretLeakIncident = "secretLeakIncident.handlebars", + WorkspaceInvite = "workspaceInvitation.handlebars" +} + +export enum SmtpHost { + Sendgrid = "smtp.sendgrid.net", + Mailgun = "smtp.mailgun.org", + SocketLabs = "smtp.sockerlabs.com", + Zohomail = "smtp.zoho.com", + Gmail = "smtp.gmail.com", + Office365 = "smtp.office365.com" +} + +const getTlsOption = (host?: SmtpHost | string, secure?: boolean) => { + if (!secure) return { secure: false }; + if (!host) return { secure: true }; + + if (host === SmtpHost.Sendgrid) { + return { requireTLS: true }; + } + if (host.includes("amazonaws.com")) { + return { tls: { ciphers: "TLSv1.2" } }; + } + return { requireTLS: true, tls: { ciphers: "TLSv1.2" } }; +}; + +export const smtpServiceFactory = (cfg: TSmtpConfig) => { + const smtp = createTransport({ ...cfg, ...getTlsOption(cfg.host, cfg.secure) }); + const isSmtpOn = Boolean(cfg.host); + + const sendMail = async ({ substitutions, recipients, template, subjectLine }: TSmtpSendMail) => { + const html = await fs.readFile(path.resolve(__dirname, "./templates/", template), "utf8"); + const temp = handlebars.compile(html); + const htmlToSend = temp(substitutions); + if (isSmtpOn) { + await smtp.sendMail({ + from: cfg.from, + to: recipients.join(", "), + subject: subjectLine, + html: htmlToSend + }); + } else { + logger.info("SMTP is not configured. Outputting it in terminal"); + logger.info({ + from: cfg.from, + to: recipients.join(", "), + subject: subjectLine, + html: htmlToSend + }); + } + }; + + return { sendMail }; +}; diff --git a/backend-pg/src/services/smtp/templates/emailMfa.handlebars b/backend-pg/src/services/smtp/templates/emailMfa.handlebars new file mode 100644 index 000000000..489c9dd30 --- /dev/null +++ b/backend-pg/src/services/smtp/templates/emailMfa.handlebars @@ -0,0 +1,19 @@ + + + + + + + MFA Code + + + +

Infisical

+

Sign in attempt requires further verification

+

Your MFA code is below — enter it where you started signing in to Infisical.

+

{{code}}

+

The MFA code will be valid for 2 minutes.

+

Not you? Contact Infisical or your administrator immediately.

+ + + \ No newline at end of file diff --git a/backend-pg/src/services/smtp/templates/emailVerification.handlebars b/backend-pg/src/services/smtp/templates/emailVerification.handlebars new file mode 100644 index 000000000..fc738d202 --- /dev/null +++ b/backend-pg/src/services/smtp/templates/emailVerification.handlebars @@ -0,0 +1,17 @@ + + + + + + + Code + + + +

Confirm your email address

+

Your confirmation code is below — enter it in the browser window where you've started signing up for Infisical.

+

{{code}}

+

Questions about setting up Infisical? Email us at support@infisical.com

+ + + \ No newline at end of file diff --git a/backend-pg/src/services/smtp/templates/historicalSecretLeakIncident.handlebars b/backend-pg/src/services/smtp/templates/historicalSecretLeakIncident.handlebars new file mode 100644 index 000000000..3cb517a57 --- /dev/null +++ b/backend-pg/src/services/smtp/templates/historicalSecretLeakIncident.handlebars @@ -0,0 +1,21 @@ + + + + + + + Incident alert: secrets potentially leaked + + + +

Infisical has uncovered {{numberOfSecrets}} secret(s) from historical commits to your repo

+

View leaked secrets

+ +

If these are production secrets, please rotate them immediately.

+ +

Once you have taken action, be sure to update the status of the risk in your Infisical + dashboard.

+ + + \ No newline at end of file diff --git a/backend-pg/src/services/smtp/templates/newDevice.handlebars b/backend-pg/src/services/smtp/templates/newDevice.handlebars new file mode 100644 index 000000000..654bb1ba3 --- /dev/null +++ b/backend-pg/src/services/smtp/templates/newDevice.handlebars @@ -0,0 +1,19 @@ + + + + + + + Successful login for {{email}} from new device + + + +

Infisical

+

We're verifying a recent login for {{email}}:

+

Timestamp: {{timestamp}}

+

IP address: {{ip}}

+

User agent: {{userAgent}}

+

If you believe that this login is suspicious, please contact Infisical or reset your password immediately.

+ + + \ No newline at end of file diff --git a/backend-pg/src/services/smtp/templates/organizationInvitation.handlebars b/backend-pg/src/services/smtp/templates/organizationInvitation.handlebars new file mode 100644 index 000000000..b281786f4 --- /dev/null +++ b/backend-pg/src/services/smtp/templates/organizationInvitation.handlebars @@ -0,0 +1,16 @@ + + + + + + + Organization Invitation + + +

Join your organization on Infisical

+

{{inviterFirstName}} ({{inviterEmail}}) has invited you to their Infisical organization — {{organizationName}}

+ Join now +

What is Infisical?

+

Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets and configs.

+ + \ No newline at end of file diff --git a/backend-pg/src/services/smtp/templates/passwordReset.handlebars b/backend-pg/src/services/smtp/templates/passwordReset.handlebars new file mode 100644 index 000000000..3b136e859 --- /dev/null +++ b/backend-pg/src/services/smtp/templates/passwordReset.handlebars @@ -0,0 +1,14 @@ + + + + + + Account Recovery + + +

Reset your password

+

Someone requested a password reset.

+ Reset password +

If you didn't initiate this request, please contact us immediately at team@infisical.com

+ + \ No newline at end of file diff --git a/backend-pg/src/services/smtp/templates/secretLeakIncident.handlebars b/backend-pg/src/services/smtp/templates/secretLeakIncident.handlebars new file mode 100644 index 000000000..1bf2d3175 --- /dev/null +++ b/backend-pg/src/services/smtp/templates/secretLeakIncident.handlebars @@ -0,0 +1,25 @@ + + + + + + + Incident alert: secret leaked + + + +

Infisical has uncovered {{numberOfSecrets}} secret(s) from your recent push

+

View leaked secrets

+

You are receiving this notification because one or more secret leaks have been detected in a recent commit pushed + by {{pusher_name}} ({{pusher_email}}). If + these are test secrets, please add `infisical-scan:ignore` at the end of the line containing the secret as comment + in the given programming. This will prevent future notifications from being sent out for those secret(s).

+ +

If these are production secrets, please rotate them immediately.

+ +

Once you have taken action, be sure to update the status of the risk in your Infisical + dashboard.

+ + + \ No newline at end of file diff --git a/backend-pg/src/services/smtp/templates/workspaceInvitation.handlebars b/backend-pg/src/services/smtp/templates/workspaceInvitation.handlebars new file mode 100644 index 000000000..60556555c --- /dev/null +++ b/backend-pg/src/services/smtp/templates/workspaceInvitation.handlebars @@ -0,0 +1,15 @@ + + + + + + Project Invitation + + +

Join your team on Infisical

+

{{inviterFirstName}} ({{inviterEmail}}) has invited you to their Infisical project — {{workspaceName}}

+ Join now +

What is Infisical?

+

Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets and configs.

+ + \ No newline at end of file diff --git a/backend-pg/src/services/token/token-dal.ts b/backend-pg/src/services/token/token-dal.ts new file mode 100644 index 000000000..823508610 --- /dev/null +++ b/backend-pg/src/services/token/token-dal.ts @@ -0,0 +1,98 @@ +import { TDbClient } from "@app/db"; +import { TableName, TToken } from "@app/db/schemas"; +import { TTokenSession } from "@app/db/schemas/token-session"; + +import { + TDeleteTokenForUserDalDTO, + TGetTokenForUserDalDTO, + TUpsertTokenForUserDalDTO +} from "./token-types"; + +export type TTokenDalConfig = {}; + +export type TTokenDalFactory = ReturnType; + +export const tokenDalFactory = (db: TDbClient) => { + const upsertTokenForUser = async ({ + tokenHash, + expiresAt, + userId, + type, + triesLeft + }: TUpsertTokenForUserDalDTO): Promise => { + const token = await db.transaction(async (tx) => { + await tx(TableName.AuthTokens).where({ userId, type }).delete().returning("*"); + const [newToken] = await tx(TableName.AuthTokens) + .insert({ tokenHash, expiresAt: expiresAt.toUTCString(), type, userId, triesLeft }) + .returning("*"); + return newToken; + }); + return token; + }; + + const getTokenForUser = async ({ + userId, + type + }: TGetTokenForUserDalDTO): Promise => + db(TableName.AuthTokens).where({ userId, type }).first(); + + const deleteTokenForUser = async ({ + userId, + type + }: TDeleteTokenForUserDalDTO): Promise => + db(TableName.AuthTokens).where({ userId, type }).delete().returning("*"); + + const decrementTriesField = async ({ + userId, + type + }: TDeleteTokenForUserDalDTO): Promise => { + await db(TableName.AuthTokens).where({ userId, type }).decrement("triesLeft", 1); + }; + + const getTokenSession = async ( + userId: string, + ip: string, + userAgent: string + ): Promise => + db(TableName.AuthTokenSession).where({ userId, ip, userAgent }).first(); + + const insertTokenSession = async ( + userId: string, + ip: string, + userAgent: string + ): Promise => { + const [session] = await db(TableName.AuthTokenSession) + .insert({ + userId, + ip, + userAgent, + accessVersion: 1, + refreshVersion: 1, + lastUsed: new Date().toUTCString() + }) + .returning("*"); + return session; + }; + + const incrementVersion = async ( + userId: string, + sessionId: string + ): Promise => { + const [session] = await db(TableName.AuthTokenSession) + .where({ userId, id: sessionId }) + .increment("accessVersion", 1) + .increment("refreshVersion", 1) + .returning("*"); + return session; + }; + + return { + upsertTokenForUser, + getTokenForUser, + deleteTokenForUser, + decrementTriesField, + getTokenSession, + insertTokenSession, + incrementVersion + }; +}; diff --git a/backend-pg/src/services/token/token-service.ts b/backend-pg/src/services/token/token-service.ts new file mode 100644 index 000000000..1b7c80c43 --- /dev/null +++ b/backend-pg/src/services/token/token-service.ts @@ -0,0 +1,134 @@ +import crypto from "node:crypto"; +import bcrypt from "bcrypt"; +import jwt, { SignOptions } from "jsonwebtoken"; + +import { TToken } from "@app/db/schemas"; +import { TTokenSession } from "@app/db/schemas/token-session"; +import { getConfig } from "@app/lib/config/env"; + +import { TTokenDalFactory } from "./token-dal"; +import { + TCreateTokenForUserDTO, + TIssueAuthTokenDTO, + TokenType, + TValidateTokenForUserDTO +} from "./token-types"; + +type TTokenServiceFactoryDep = { + tokenDal: TTokenDalFactory; + // adjust the expiry from env through here +}; +export type TTokenServiceFactory = ReturnType; + +export const getTokenConfig = (tokenType: TokenType) => { + // generate random token based on specified token use-case + // type [type] + switch (tokenType) { + case TokenType.TOKEN_EMAIL_CONFIRMATION: { + // generate random 6-digit code + const token = String(crypto.randomInt(10 ** 5, 10 ** 6 - 1)); + const expiresAt = new Date(new Date().getTime() + 86400000); + return { token, expiresAt }; + } + case TokenType.TOKEN_EMAIL_MFA: { + // generate random 6-digit code + const token = String(crypto.randomInt(10 ** 5, 10 ** 6 - 1)); + const triesLeft = 5; + const expiresAt = new Date(new Date().getTime() + 300000); + return { token, triesLeft, expiresAt }; + } + case TokenType.TOKEN_EMAIL_ORG_INVITATION: { + // generate random hex + const token = crypto.randomBytes(16).toString("hex"); + const expiresAt = new Date(new Date().getTime() + 259200000); + return { token, expiresAt }; + } + case TokenType.TOKEN_EMAIL_PASSWORD_RESET: { + // generate random hex + const token = crypto.randomBytes(16).toString("hex"); + const expiresAt = new Date(new Date().getTime() + 86400000); + return { token, expiresAt }; + } + default: { + const token = crypto.randomBytes(16).toString("hex"); + const expiresAt = new Date(); + return { token, expiresAt }; + } + } +}; + +export const tokenServiceFactory = ({ tokenDal }: TTokenServiceFactoryDep) => { + const createTokenForUser = async ({ type, userId }: TCreateTokenForUserDTO) => { + const { token, ...tkCfg } = getTokenConfig(type); + const appCfg = getConfig(); + const tokenHash = await bcrypt.hash(token, appCfg.SALT_ROUNDS); + await tokenDal.upsertTokenForUser({ + userId, + type, + expiresAt: tkCfg.expiresAt, + tokenHash, + triesLeft: tkCfg?.triesLeft + }); + return token; + }; + + const validateTokenForUser = async ({ + type, + userId, + code + }: TValidateTokenForUserDTO): Promise => { + const token = await tokenDal.getTokenForUser({ type, userId }); + // validate token + if (!token) throw new Error("Failed to find token"); + if (token?.expiresAt && new Date(token.expiresAt) < new Date()) { + await tokenDal.deleteTokenForUser({ type, userId }); + throw new Error("Token expired. Please try again"); + } + + const isValidToken = await bcrypt.compare(code, token.tokenHash); + if (!isValidToken) { + if (token?.triesLeft) { + if (token.triesLeft === 1) { + await tokenDal.deleteTokenForUser({ type, userId }); + } else { + await tokenDal.decrementTriesField({ type, userId }); + } + } + throw new Error("Invalid token"); + } + + const deletedToken = await tokenDal.deleteTokenForUser({ type, userId }); + return deletedToken?.[0]; + }; + + const getUserTokenSession = async ({ + userId, + ip, + userAgent + }: TIssueAuthTokenDTO): Promise => { + let session = await tokenDal.getTokenSession(userId, ip, userAgent); + if (!session) { + session = await tokenDal.insertTokenSession(userId, ip, userAgent); + } + return session; + }; + + const clearTokenSessionById = async ( + userId: string, + sessionId: string + ): Promise => tokenDal.incrementVersion(userId, sessionId); + + const createJwtToken = ( + payload: string | Buffer | object, + secret: string, + options?: SignOptions + ) => jwt.sign(payload, secret, options); + + return { + createTokenForUser, + validateTokenForUser, + createJwtToken, + getUserTokenSession, + clearTokenSessionById + }; +}; diff --git a/backend-pg/src/services/token/token-types.ts b/backend-pg/src/services/token/token-types.ts new file mode 100644 index 000000000..454dd7f76 --- /dev/null +++ b/backend-pg/src/services/token/token-types.ts @@ -0,0 +1,41 @@ +export enum TokenType { + TOKEN_EMAIL_CONFIRMATION = "emailConfirmation", + TOKEN_EMAIL_MFA = "emailMfa", + TOKEN_EMAIL_ORG_INVITATION = "organizationInvitation", + TOKEN_EMAIL_PASSWORD_RESET = "passwordReset" +} + +export type TCreateTokenForUserDTO = { + type: TokenType; + userId: string; +}; + +export type TValidateTokenForUserDTO = { + type: TokenType; + code: string; + userId: string; +}; + +export type TUpsertTokenForUserDalDTO = { + type: TokenType; + expiresAt: Date; + userId: string; + tokenHash: string; + triesLeft?: number; +}; + +export type TGetTokenForUserDalDTO = { + userId: string; + type: TokenType; +}; + +export type TDeleteTokenForUserDalDTO = { + userId: string; + type: TokenType; +}; + +export type TIssueAuthTokenDTO = { + userId: string; + ip: string; + userAgent: string; +}; diff --git a/docker-compose.pg.yml b/docker-compose.pg.yml new file mode 100644 index 000000000..8f8fe9cc4 --- /dev/null +++ b/docker-compose.pg.yml @@ -0,0 +1,58 @@ +version: "3.9" + +services: + nginx: + container_name: infisical-dev-nginx + image: nginx + restart: always + ports: + - 8080:80 + volumes: + - ./nginx/default.dev.conf:/etc/nginx/conf.d/default.conf:ro + depends_on: + - backend + - frontend + + db: + image: postgres:14-alpine + ports: + - "5432:5432" + volumes: + - postgres-data:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: infisical + POSTGRES_USER: infisical + POSTGRES_DB: infisical + + backend: + build: + context: ./backend-pg + dockerfile: Dockerfile.dev + depends_on: + - db + env_file: + - .env + environment: + - DB_CONNECTION_URI=postgres://infisical:infisical@db/infisical?sslmode=disable + volumes: + - ./backend-pg/src:/app/src + + frontend: + container_name: infisical-dev-frontend + restart: unless-stopped + depends_on: + - backend + build: + context: ./frontend + dockerfile: Dockerfile.dev + volumes: + - ./frontend/src:/app/src/ # mounted whole src to avoid missing reload on new files + - ./frontend/public:/app/public + env_file: .env + environment: + - NEXT_PUBLIC_ENV=development + - INFISICAL_TELEMETRY_ENABLED=false + +volumes: + postgres-data: + driver: local diff --git a/frontend/src/context/ServerConfigContext/ServerConfigContext.tsx b/frontend/src/context/ServerConfigContext/ServerConfigContext.tsx index 291765e3b..aab7e4c56 100644 --- a/frontend/src/context/ServerConfigContext/ServerConfigContext.tsx +++ b/frontend/src/context/ServerConfigContext/ServerConfigContext.tsx @@ -72,9 +72,9 @@ export const ServerConfigProvider = ({ children }: Props): JSX.Element => { export const useServerConfig = () => { const ctx = useContext(ServerConfigContext); - if (!ctx) { - throw new Error("useServerConfig has to be used within "); - } + // if (!ctx) { + // throw new Error("useServerConfig has to be used within "); + // } - return ctx; + return ctx || { config: { allowSignUp: true } }; }; diff --git a/frontend/src/hooks/api/auth/queries.tsx b/frontend/src/hooks/api/auth/queries.tsx index a26297730..697fe69eb 100644 --- a/frontend/src/hooks/api/auth/queries.tsx +++ b/frontend/src/hooks/api/auth/queries.tsx @@ -121,7 +121,7 @@ export const verifySignupInvite = async (details: VerifySignupInviteDTO) => { export const useSendVerificationEmail = () => { return useMutation({ mutationFn: async ({ email }: { email: string }) => { - const { data } = await apiRequest.post("/api/v1/signup/email/signup", { + const { data } = await apiRequest.post("/api/v3/signup/email/signup", { email }); @@ -133,7 +133,7 @@ export const useSendVerificationEmail = () => { export const useVerifyEmailVerificationCode = () => { return useMutation({ mutationFn: async ({ email, code }: { email: string; code: string }) => { - const { data } = await apiRequest.post("/api/v1/signup/email/verify", { + const { data } = await apiRequest.post("/api/v3/signup/email/verify", { email, code }); diff --git a/frontend/src/pages/_app.tsx b/frontend/src/pages/_app.tsx index 82829e410..715e7b9c0 100644 --- a/frontend/src/pages/_app.tsx +++ b/frontend/src/pages/_app.tsx @@ -82,14 +82,13 @@ const App = ({ Component, pageProps, ...appProps }: NextAppProp): JSX.Element => publicPaths.includes(`/${appProps.router.pathname.split("/")[1]}`) || !Component.requireAuth ) { + // TODO(akhilmhdh): bring back server config later return ( - - - - - + + + ); From f3b37de3f3d608d1286848c1eb3375cb72c45ab6 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Tue, 5 Dec 2023 14:53:45 +0530 Subject: [PATCH 004/185] feat(infisical-pg): auth injection completed and validation in password router --- backend-pg/.eslintrc.js | 1 + backend-pg/package.json | 1 + backend-pg/scripts/create-backend-file.ts | 24 - backend-pg/scripts/generate-schema-types.ts | 163 ++++++ backend-pg/src/@types/fastify.d.ts | 9 + backend-pg/src/@types/knex.d.ts | 62 +- .../src/db/migrations/20231128072457_user.ts | 2 +- .../20231128092347_user-encryption-key.ts | 4 +- .../migrations/20231129072939_auth-token.ts | 1 + .../20231130072734_auth-token-session.ts | 2 +- .../migrations/20231201151432_backup-key.ts | 2 +- .../migrations/20231204092737_organization.ts | 24 + .../20231204092747_org-membership.ts | 30 + .../src/db/schemas/auth-token-sessions.ts | 24 + backend-pg/src/db/schemas/auth-tokens.ts | 24 + .../src/db/schemas/backup-private-key.ts | 17 +- backend-pg/src/db/schemas/index.ts | 23 +- backend-pg/src/db/schemas/models.ts | 25 +- .../db/schemas/organization-memberships.ts | 23 + backend-pg/src/db/schemas/organizations.ts | 20 + backend-pg/src/db/schemas/token-session.ts | 17 - backend-pg/src/db/schemas/token.ts | 19 - .../src/db/schemas/user-encryption-key.ts | 26 - .../src/db/schemas/user-encryption-keys.ts | 29 + backend-pg/src/db/schemas/user.ts | 38 -- backend-pg/src/db/schemas/users.ts | 27 + backend-pg/src/lib/errors/index.ts | 2 +- backend-pg/src/lib/knex/index.ts | 10 + backend-pg/src/lib/zod/index.ts | 4 +- .../server/plugins/auth/inject-identity.ts | 75 +++ .../src/server/plugins/auth/verify-auth.ts | 17 + backend-pg/src/server/routes/index.ts | 3 + .../src/server/routes/v1/password-router.ts | 6 + backend-pg/src/server/routes/v2/mfa-router.ts | 15 +- .../src/server/routes/v3/login-router.ts | 2 +- .../src/server/routes/v3/signup-router.ts | 6 +- backend-pg/src/services/auth/auth-dal.ts | 36 +- .../src/services/auth/auth-login-service.ts | 15 +- .../services/auth/auth-password-service.ts | 6 +- .../src/services/auth/auth-signup-service.ts | 16 +- .../src/services/auth/auth-signup-type.ts | 19 - backend-pg/src/services/auth/auth-type.ts | 35 ++ backend-pg/src/services/token/token-dal.ts | 33 +- .../src/services/token/token-service.ts | 29 +- backend/src/utils/authn/helpers/index.ts | 145 +++-- .../AddTagPopoverContent.tsx | 2 +- .../components/basic/dialog/UpgradePlan.tsx | 2 +- .../basic/table/ProjectUsersTable.tsx | 2 +- .../src/components/dashboard/AddTagsMenu.tsx | 2 +- frontend/src/components/dashboard/KeyPair.tsx | 4 +- .../src/components/navigation/NavHeader.tsx | 2 +- .../src/components/signup/UserInfoStep.tsx | 4 +- .../tags/CreateTagModal/CreateTagModal.tsx | 2 +- .../src/components/utilities/config/index.ts | 4 +- .../components/utilities/intercom/intercom.ts | 6 +- .../v2/UpgradePlanModal/UpgradePlanModal.tsx | 4 +- .../OrgPermissionContext.tsx | 2 +- .../OrganizationContext.tsx | 2 +- .../ProjectPermissionContext.tsx | 2 +- .../SubscriptionContext.tsx | 2 +- .../WorkspaceContext/WorkspaceContext.tsx | 2 +- frontend/src/hooks/api/apiKeys/types.ts | 2 +- frontend/src/hooks/api/bots/types.ts | 2 +- .../src/hooks/api/incidentContacts/types.ts | 2 +- .../src/hooks/api/integrationAuth/types.ts | 2 +- frontend/src/hooks/api/integrations/types.ts | 2 +- frontend/src/hooks/api/keys/types.ts | 4 +- frontend/src/hooks/api/organization/types.ts | 10 +- frontend/src/hooks/api/roles/types.ts | 2 +- .../src/hooks/api/secretApproval/types.ts | 2 +- .../api/secretApprovalRequest/queries.tsx | 2 +- .../hooks/api/secretApprovalRequest/types.ts | 6 +- .../src/hooks/api/secretImports/queries.tsx | 2 +- frontend/src/hooks/api/secretImports/types.ts | 2 +- .../src/hooks/api/secretRotation/types.ts | 2 +- .../src/hooks/api/secretSnapshots/queries.tsx | 2 +- .../src/hooks/api/secretSnapshots/types.ts | 2 +- frontend/src/hooks/api/secrets/queries.tsx | 6 +- frontend/src/hooks/api/secrets/types.ts | 6 +- frontend/src/hooks/api/subscriptions/types.ts | 2 +- frontend/src/hooks/api/tags/types.ts | 10 +- frontend/src/hooks/api/trustedIps/types.ts | 2 +- frontend/src/hooks/api/webhooks/types.ts | 2 +- frontend/src/hooks/api/workspace/types.ts | 6 +- .../src/layouts/AdminLayout/AdminLayout.tsx | 4 +- .../AppLayout/components/NavBar/NavBar.tsx | 8 +- .../secret-scanning/getRisksByOrganization.ts | 2 +- frontend/src/pages/dashboard.tsx | 2 +- .../aws-parameter-store/authorize.tsx | 2 +- .../aws-parameter-store/create.tsx | 4 +- .../aws-secret-manager/authorize.tsx | 2 +- .../aws-secret-manager/create.tsx | 4 +- .../integrations/azure-key-vault/create.tsx | 4 +- .../azure-key-vault/oauth2/callback.tsx | 2 +- .../pages/integrations/bitbucket/create.tsx | 4 +- .../bitbucket/oauth2/callback.tsx | 2 +- .../pages/integrations/checkly/authorize.tsx | 2 +- .../src/pages/integrations/checkly/create.tsx | 4 +- .../pages/integrations/circleci/authorize.tsx | 2 +- .../pages/integrations/circleci/create.tsx | 4 +- .../pages/integrations/cloud-66/authorize.tsx | 2 +- .../pages/integrations/cloud-66/create.tsx | 4 +- .../cloudflare-pages/authorize.tsx | 2 +- .../integrations/cloudflare-pages/create.tsx | 4 +- .../cloudflare-workers/authorize.tsx | 2 +- .../cloudflare-workers/create.tsx | 4 +- .../integrations/codefresh/authorize.tsx | 2 +- .../pages/integrations/codefresh/create.tsx | 4 +- .../digital-ocean-app-platform/authorize.tsx | 2 +- .../digital-ocean-app-platform/create.tsx | 4 +- .../pages/integrations/flyio/authorize.tsx | 2 +- .../src/pages/integrations/flyio/create.tsx | 4 +- .../gcp-secret-manager/authorize.tsx | 4 +- .../gcp-secret-manager/create.tsx | 4 +- .../gcp-secret-manager/oauth2/callback.tsx | 2 +- .../src/pages/integrations/github/create.tsx | 4 +- .../integrations/github/oauth2/callback.tsx | 2 +- .../pages/integrations/gitlab/authorize.tsx | 2 +- .../src/pages/integrations/gitlab/create.tsx | 4 +- .../integrations/gitlab/oauth2/callback.tsx | 2 +- .../hashicorp-vault/authorize.tsx | 2 +- .../integrations/hashicorp-vault/create.tsx | 4 +- .../integrations/hasura-cloud/authorize.tsx | 2 +- .../integrations/hasura-cloud/create.tsx | 4 +- .../src/pages/integrations/heroku/create.tsx | 4 +- .../integrations/heroku/oauth2/callback.tsx | 2 +- .../integrations/laravel-forge/authorize.tsx | 2 +- .../integrations/laravel-forge/create.tsx | 4 +- .../src/pages/integrations/netlify/create.tsx | 4 +- .../integrations/netlify/oauth2/callback.tsx | 2 +- .../integrations/northflank/authorize.tsx | 2 +- .../pages/integrations/northflank/create.tsx | 4 +- .../pages/integrations/qovery/authorize.tsx | 2 +- .../src/pages/integrations/qovery/create.tsx | 4 +- .../pages/integrations/railway/authorize.tsx | 2 +- .../src/pages/integrations/railway/create.tsx | 4 +- .../pages/integrations/render/authorize.tsx | 2 +- .../src/pages/integrations/render/create.tsx | 4 +- .../pages/integrations/supabase/authorize.tsx | 2 +- .../pages/integrations/supabase/create.tsx | 4 +- .../pages/integrations/teamcity/authorize.tsx | 2 +- .../pages/integrations/teamcity/create.tsx | 4 +- .../terraform-cloud/authorize.tsx | 2 +- .../integrations/terraform-cloud/create.tsx | 4 +- .../pages/integrations/travisci/authorize.tsx | 2 +- .../pages/integrations/travisci/create.tsx | 4 +- .../src/pages/integrations/vercel/create.tsx | 4 +- .../integrations/vercel/oauth2/callback.tsx | 2 +- .../pages/integrations/windmill/authorize.tsx | 2 +- .../pages/integrations/windmill/create.tsx | 4 +- .../pages/org/[id]/secret-scanning/index.tsx | 6 +- frontend/src/pages/signup/index.tsx | 4 +- frontend/src/pages/signupinvite.tsx | 4 +- .../IntegrationPage.utils.tsx | 10 +- .../IntegrationsPage/IntegrationsPage.tsx | 19 +- .../IntegrationsSection.tsx | 2 +- frontend/src/views/Login/Login.utils.tsx | 2 +- .../components/IPAllowlistModal.tsx | 6 +- .../components/IPAllowlistSection.tsx | 4 +- .../components/IPAllowlistTable.tsx | 10 +- .../AddServiceTokenModal.tsx | 6 +- .../ServiceTokenSection/ServiceTokenTable.tsx | 8 +- .../AddServiceTokenV3Modal.tsx | 539 ++++++++++++++++++ .../ServiceTokenV3Table.tsx | 218 +++++++ .../SecretApprovalPage/SecretApprovalPage.tsx | 2 +- .../SecretApprovalPolicyList.tsx | 4 +- .../SecretApprovalRequestChangeItem.tsx | 14 +- .../views/SecretMainPage/SecretMainPage.tsx | 2 +- .../components/ActionBar/ActionBar.tsx | 10 +- .../components/PitDrawer/PitDrawer.tsx | 12 +- .../SecretDropzone/CopySecretsFromBoard.tsx | 6 +- .../SecretImportListView.tsx | 6 +- .../SecretListView/SecretDetaiSidebar.tsx | 16 +- .../components/SecretListView/SecretItem.tsx | 14 +- .../SecretListView/SecretListView.utils.ts | 2 +- .../components/SnapshotView/SecretItem.tsx | 8 +- .../components/SnapshotView/SnapshotView.tsx | 4 +- .../SecretOverviewPage/SecretOverviewPage.tsx | 4 +- .../ProjectIndexSecretsSection.tsx | 10 +- .../SecretOverviewTableRow.tsx | 2 +- .../SecretRotationPage/SecretRotationPage.tsx | 18 +- .../steps/RotationOutputForm.tsx | 10 +- .../components/SecretScanningLogsTable.tsx | 2 +- .../BillingCloudTab/CurrentPlanSection.tsx | 2 +- .../BillingCloudTab/ManagePlansTable.tsx | 6 +- .../BillingCloudTab/PreviewSection.tsx | 8 +- .../BillingSelfHostedTab/LicensesSection.tsx | 6 +- .../components/OrgAuthTab/OrgSSOSection.tsx | 10 +- .../components/OrgAuthTab/SSOModal.tsx | 8 +- .../OrgDeleteSection/OrgDeleteSection.tsx | 4 +- .../AddOrgIncidentContactModal.tsx | 4 +- .../OrgIncidentContactsTable.tsx | 6 +- .../OrgNameChangeSection.tsx | 4 +- .../APIKeyV2Section/APIKeyV2Table.tsx | 8 +- .../UserInfoSSOStep/UserInfoSSOStep.tsx | 4 +- .../admin/DashboardPage/DashboardPage.tsx | 4 +- 196 files changed, 1871 insertions(+), 624 deletions(-) create mode 100644 backend-pg/scripts/generate-schema-types.ts create mode 100644 backend-pg/src/db/migrations/20231204092737_organization.ts create mode 100644 backend-pg/src/db/migrations/20231204092747_org-membership.ts create mode 100644 backend-pg/src/db/schemas/auth-token-sessions.ts create mode 100644 backend-pg/src/db/schemas/auth-tokens.ts create mode 100644 backend-pg/src/db/schemas/organization-memberships.ts create mode 100644 backend-pg/src/db/schemas/organizations.ts delete mode 100644 backend-pg/src/db/schemas/token-session.ts delete mode 100644 backend-pg/src/db/schemas/token.ts delete mode 100644 backend-pg/src/db/schemas/user-encryption-key.ts create mode 100644 backend-pg/src/db/schemas/user-encryption-keys.ts delete mode 100644 backend-pg/src/db/schemas/user.ts create mode 100644 backend-pg/src/db/schemas/users.ts create mode 100644 backend-pg/src/lib/knex/index.ts create mode 100644 backend-pg/src/server/plugins/auth/inject-identity.ts create mode 100644 backend-pg/src/server/plugins/auth/verify-auth.ts create mode 100644 backend-pg/src/services/auth/auth-type.ts create mode 100644 frontend/src/views/Project/MembersPage/components/ServiceTokenTab/components/ServiceTokenV3Section/AddServiceTokenV3Modal.tsx create mode 100644 frontend/src/views/Project/MembersPage/components/ServiceTokenTab/components/ServiceTokenV3Section/ServiceTokenV3Table.tsx diff --git a/backend-pg/.eslintrc.js b/backend-pg/.eslintrc.js index 5d564d416..6d6217634 100644 --- a/backend-pg/.eslintrc.js +++ b/backend-pg/.eslintrc.js @@ -18,6 +18,7 @@ module.exports = { "import/first": "error", "import/newline-after-import": "error", "import/no-duplicates": "error", + "consistent-return": "off", "simple-import-sort/imports": [ "warn", { diff --git a/backend-pg/package.json b/backend-pg/package.json index 6499ab5e9..93e94eac3 100644 --- a/backend-pg/package.json +++ b/backend-pg/package.json @@ -11,6 +11,7 @@ "lint:fix": "eslint --fix 'src/**/*.ts'", "lint": "eslint 'src/**/*.ts'", "generate:component": "tsx ./scripts/create-backend-file.ts", + "generate:schema": "tsx ./scripts/generate-schema-types.ts", "migration:new": "tsx ./scripts/create-migration.ts", "migration:up": "knex --knexfile ./src/db/knexfile.ts --client pg migrate:up", "migration:down": "knex --knexfile ./src/db/knexfile.ts --client pg migrate:down", diff --git a/backend-pg/scripts/create-backend-file.ts b/backend-pg/scripts/create-backend-file.ts index 2ea0a773a..3b1cb96c8 100644 --- a/backend-pg/scripts/create-backend-file.ts +++ b/backend-pg/scripts/create-backend-file.ts @@ -10,7 +10,6 @@ console.log(` Component List -------------- 1. Service component -2. Schema file `); const componentType = parseInt(prompt("Select a component: "), 10); @@ -55,27 +54,4 @@ export const ${serviceName} = ({ ${componentName}Dal }: ${serviceTypeName}Dep) = ` ); writeFileSync(path.join(dir, `${componentName}-types.ts`), ""); -} else if (componentType === 2) { - const componentName = prompt("Type component name in lowercase with space seperated: "); - const dashcase = componentName.split(" ").join("-"); - const pascalCase = componentName - .split(" ") - .reduce( - (prev, curr) => prev + `${curr.at(0)?.toUpperCase()}${curr.slice(1).toLowerCase()}`, - "" - ); - writeFileSync( - path.join(__dirname, "../src/db/schemas", `${dashcase}.ts`), - ` -import { z } from "zod"; - -import { TImmutableDBKeys } from "./models"; - -export const ${pascalCase}Schema = z.object({}); - -export type T${pascalCase} = z.infer; -export type T${pascalCase}Insert = Omit; -export type T${pascalCase}Update = Partial>; -` - ); } diff --git a/backend-pg/scripts/generate-schema-types.ts b/backend-pg/scripts/generate-schema-types.ts new file mode 100644 index 000000000..5c279f7f3 --- /dev/null +++ b/backend-pg/scripts/generate-schema-types.ts @@ -0,0 +1,163 @@ +import dotenv from "dotenv"; +import path from "path"; +import knex from "knex"; +import { appendFileSync, readFileSync, writeFileSync } from "fs"; +import promptSync from "prompt-sync"; + +const prompt = promptSync(); + +dotenv.config({ + path: path.join(__dirname, "../.env"), + debug: true +}); + +const db = knex({ + client: "pg", + connection: process.env.DB_CONNECTION_URI +}); + +const getZodPrimitiveType = (type: string) => { + switch (type) { + case "uuid": + return "z.string().uuid()"; + case "character varying": + return "z.string()"; + case "ARRAY": + return "z.string().array()"; + case "boolean": + return "z.boolean()"; + case "jsonb": + return "z.string()"; + case "json": + return "z.string()"; + case "timestamp with time zone": + return "z.string().datetime()"; + case "integer": + return "z.number()"; + case "text": + return "z.string()"; + default: + throw new Error(`Invalid type: ${type}`); + } +}; + +const getZodDefaultValue = (type: unknown, value: string | number | boolean | Object) => { + if (!value || value === "null") return; + switch (type) { + case "uuid": + return; + case "character varying": { + if (typeof value === "string" && value.includes("::")) { + return `.default(${value.split("::")[0]})`; + } + return `.default(${value})`; + } + case "ARRAY": + return `.default(${value})`; + case "boolean": + return `.default(${value})`; + case "jsonb": + return "z.string()"; + case "json": + return "z.string()"; + case "timestamp with time zone": { + if (value === "CURRENT_TIMESTAMP") return; + return "z.string().datetime()"; + } + case "integer": { + if ((value as string).includes("nextval")) return; + return `.default(${value})`; + } + case "text": + if (typeof value === "string" && value.includes("::")) { + return `.default(${value.split("::")[0]})`; + } + return `.default(${value})`; + default: + throw new Error(`Invalid type: ${type}`); + } +}; + +const main = async () => { + const tables = ( + await db("information_schema.tables") + .whereRaw("table_schema = current_schema()") + .select<{ tableName: string }[]>("table_name as tableName") + .orderBy("table_name") + ).filter( + (el) => el.tableName !== "infisical_migrations_lock" && el.tableName !== "infisical_migrations" + ); + + console.log("Select a table to generate schema"); + console.table(tables); + console.log("all: all tables"); + const selectedTables = prompt("Type table numbers comma seperated: "); + const tableNumbers = + selectedTables !== "all" ? selectedTables.split(",").map((el) => Number(el)) : []; + + for (let i = 0; i < tables.length; i++) { + // skip if not desired table + if (selectedTables !== "all" && !tableNumbers.includes(i)) continue; + + const tableName = tables[i].tableName; + const columns = await db(tableName).columnInfo(); + const columnNames = Object.keys(columns); + + let schema = ""; + for (let colNum = 0; colNum < columnNames.length; colNum++) { + const columnName = columnNames[colNum]; + const colInfo = columns[columnName]; + let ztype = getZodPrimitiveType(colInfo.type); + if (colInfo.defaultValue) { + const defaultValue = colInfo.defaultValue; + const zSchema = getZodDefaultValue(colInfo.type, defaultValue); + if (zSchema) { + ztype = ztype.concat(zSchema); + } + } + if (colInfo.nullable) { + ztype = ztype.concat(".nullable().optional()"); + } + schema = schema.concat(`${!schema ? "\n" : ""} ${columnName}: ${ztype},\n`); + } + + const dashcase = tableName.split("_").join("-"); + const pascalCase = tableName + .split("_") + .reduce( + (prev, curr) => prev + `${curr.at(0)?.toUpperCase()}${curr.slice(1).toLowerCase()}`, + "" + ); + writeFileSync( + path.join(__dirname, "../src/db/schemas", `${dashcase}.ts`), + `// Code generated by automation script, DO NOT EDIT. +// Automated by pulling database and generating zod schema +// To update. Just run npm run generate:schema +// Written by akhilmhdh. + +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const ${pascalCase}Schema = z.object({${schema}}); + +export type T${pascalCase} = z.infer; +export type T${pascalCase}Insert = Omit; +export type T${pascalCase}Update = Partial>; +` + ); + + // const file = readFileSync(path.join(__dirname, "../src/db/schemas/index.ts"), "utf8"); + // if (!file.includes(`export * from "./${dashcase};"`)) { + // appendFileSync( + // path.join(__dirname, "../src/db/schemas/index.ts"), + // `\nexport * from "./${dashcase}";`, + // "utf8" + // ); + // } + } + + process.exit(0); +}; + +main(); diff --git a/backend-pg/src/@types/fastify.d.ts b/backend-pg/src/@types/fastify.d.ts index 33b744166..01833e08f 100644 --- a/backend-pg/src/@types/fastify.d.ts +++ b/backend-pg/src/@types/fastify.d.ts @@ -3,6 +3,8 @@ import { TAuthDalFactory } from "@app/services/auth/auth-dal"; import { TAuthLoginFactory } from "@app/services/auth/auth-login-service"; import { TAuthPasswordFactory } from "@app/services/auth/auth-password-service"; import { TAuthSignupFactory } from "@app/services/auth/auth-signup-service"; +import { AuthMode } from "@app/services/auth/auth-signup-type"; +import { TAuthTokenServiceFactory } from "@app/services/token/token-service"; import "fastify"; @@ -14,6 +16,12 @@ declare module "fastify" { userId: string; user: TUser; }; + // identity injection. depending on which kinda of token the information is filled in auth + auth: { + authMode: AuthMode.JWT | AuthMode.API_KEY_V2 | AuthMode.API_KEY; + userId: string; + user: TUser; + }; } interface FastifyInstance { @@ -21,6 +29,7 @@ declare module "fastify" { login: TAuthLoginFactory; password: TAuthPasswordFactory; signup: TAuthSignupFactory; + authToken: TAuthTokenServiceFactory; }; // this is exclusive use for middlewares in which we need to inject data diff --git a/backend-pg/src/@types/knex.d.ts b/backend-pg/src/@types/knex.d.ts index 8b3776fe3..09e8935f5 100644 --- a/backend-pg/src/@types/knex.d.ts +++ b/backend-pg/src/@types/knex.d.ts @@ -2,42 +2,58 @@ import { Knex } from "knex"; import { TableName, + TAuthTokens, + TAuthTokenSessions, + TAuthTokenSessionsInsert, + TAuthTokenSessionsUpdate, + TAuthTokensUpdate, TBackupPrivateKey, TBackupPrivateKeyInsert, - TToken, - TTokenInsert, - TTokenUpdate, - TUser, - TUserEncryptionKey, - TUserEncryptionKeyInsert, - TUserEncryptionKeyUpdate, - TUserInsert, - TUserUpdate + TBackupPrivateKeyUpdate, + TOrganizationMemberships, + TOrganizations, + TOrganizationsInsert, + TOrganizationsUpdate, + TUserEncryptionKeys, + TUserEncryptionKeysInsert, + TUserEncryptionKeysUpdate, + TUsers, + TUsersInsert, + TUsersUpdate } from "@app/db/schemas"; -import { - TTokenSession, - TTokenSessionInsert, - TTokenSessionUpdate -} from "@app/db/schemas/token-session"; declare module "knex/types/tables" { interface Tables extends { [key in TableName]: Knex.CompositeTableType } { - [TableName.Users]: Knex.CompositeTableType; + [TableName.Users]: Knex.CompositeTableType; [TableName.UserEncryptionKey]: Knex.CompositeTableType< - TUserEncryptionKey, - TUserEncryptionKeyInsert, - TUserEncryptionKeyUpdate + TUserEncryptionKeys, + TUserEncryptionKeysInsert, + TUserEncryptionKeysUpdate + >; + [TableName.AuthTokens]: Knex.CompositeTableType< + TAuthTokens, + TAuthTokensInsert, + TAuthTokensUpdate >; - [TableName.AuthTokens]: Knex.CompositeTableType; [TableName.AuthTokenSession]: Knex.CompositeTableType< - TTokenSession, - TTokenSessionInsert, - TTokenSessionUpdate + TAuthTokenSessions, + TAuthTokenSessionsInsert, + TAuthTokenSessionsUpdate >; [TableName.BackupPrivateKey]: Knex.CompositeTableType< TBackupPrivateKey, TBackupPrivateKeyInsert, - TTokenSessionUpdate + TBackupPrivateKeyUpdate + >; + [TableName.Organization]: Knex.CompositeTableType< + TOrganizations, + TOrganizationsInsert, + TOrganizationsUpdate + >; + [TableName.OrgMembership]: Knex.CompositeTableType< + TOrganizationMemberships, + TOrganizationsInsert, + TOrganizationsUpdate >; } } diff --git a/backend-pg/src/db/migrations/20231128072457_user.ts b/backend-pg/src/db/migrations/20231128072457_user.ts index 9fd26031c..f0572824e 100644 --- a/backend-pg/src/db/migrations/20231128072457_user.ts +++ b/backend-pg/src/db/migrations/20231128072457_user.ts @@ -12,7 +12,7 @@ export async function up(knex: Knex): Promise { const isTablePresent = await knex.schema.hasTable(TableName.Users); if (!isTablePresent) { await knex.schema.createTable(TableName.Users, (t) => { - t.uuid("id").primary().defaultTo(knex.fn.uuid()); + t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.string("email").notNullable(); t.specificType("authMethods", "text[]"); t.boolean("superAdmin").defaultTo(false); diff --git a/backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts b/backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts index b9b312456..153aeb077 100644 --- a/backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts +++ b/backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts @@ -6,10 +6,10 @@ export async function up(knex: Knex): Promise { const isTablePresent = await knex.schema.hasTable(TableName.UserEncryptionKey); if (!isTablePresent) { await knex.schema.createTable(TableName.UserEncryptionKey, (t) => { - t.increments().primary(); + t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.text("clientPublicKey"); t.text("serverPrivateKey"); - t.text("encryptionVersion").defaultTo(1); + t.integer("encryptionVersion").defaultTo(1); t.text("protectedKey").notNullable(); t.text("protectedKeyIV").notNullable(); t.text("protectedKeyTag").notNullable(); diff --git a/backend-pg/src/db/migrations/20231129072939_auth-token.ts b/backend-pg/src/db/migrations/20231129072939_auth-token.ts index 0b186b8b0..ed23ebe9d 100644 --- a/backend-pg/src/db/migrations/20231129072939_auth-token.ts +++ b/backend-pg/src/db/migrations/20231129072939_auth-token.ts @@ -6,6 +6,7 @@ export async function up(knex: Knex): Promise { const isTablePresent = await knex.schema.hasTable(TableName.AuthTokens); if (!isTablePresent) { await knex.schema.createTable(TableName.AuthTokens, (t) => { + t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.string("type").notNullable(); t.string("phoneNumber"); t.string("tokenHash").notNullable(); diff --git a/backend-pg/src/db/migrations/20231130072734_auth-token-session.ts b/backend-pg/src/db/migrations/20231130072734_auth-token-session.ts index 4acde142f..9d5b98910 100644 --- a/backend-pg/src/db/migrations/20231130072734_auth-token-session.ts +++ b/backend-pg/src/db/migrations/20231130072734_auth-token-session.ts @@ -7,7 +7,7 @@ export async function up(knex: Knex): Promise { const isTablePresent = await knex.schema.hasTable(TableName.AuthTokenSession); if (!isTablePresent) { await knex.schema.createTable(TableName.AuthTokenSession, (t) => { - t.increments(); + t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.string("ip").notNullable(); t.string("userAgent"); t.integer("refreshVersion").notNullable().defaultTo(1); diff --git a/backend-pg/src/db/migrations/20231201151432_backup-key.ts b/backend-pg/src/db/migrations/20231201151432_backup-key.ts index 2f7ff9665..3672fface 100644 --- a/backend-pg/src/db/migrations/20231201151432_backup-key.ts +++ b/backend-pg/src/db/migrations/20231201151432_backup-key.ts @@ -6,7 +6,7 @@ export async function up(knex: Knex): Promise { const doesTableExist = await knex.schema.hasTable(TableName.BackupPrivateKey); if (!doesTableExist) { await knex.schema.createTable(TableName.BackupPrivateKey, (t) => { - t.increments(); + t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.string("encryptedPrivateKey").notNullable(); t.string("iv").notNullable(); t.string("tag").notNullable(); diff --git a/backend-pg/src/db/migrations/20231204092737_organization.ts b/backend-pg/src/db/migrations/20231204092737_organization.ts new file mode 100644 index 000000000..45badacb9 --- /dev/null +++ b/backend-pg/src/db/migrations/20231204092737_organization.ts @@ -0,0 +1,24 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; +import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils"; + +export async function up(knex: Knex): Promise { + const isTablePresent = await knex.schema.hasTable(TableName.Organization); + if (!isTablePresent) { + await knex.schema.createTable(TableName.Organization, (t) => { + t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); + t.string("name").notNullable(); + t.string("customerId"); + // does not need update trigger we will do it manually + t.timestamps(true, true, true); + }); + } + // this is a one time function + await createOnUpdateTrigger(knex, TableName.Organization); +} + +export async function down(knex: Knex): Promise { + await knex.schema.dropTableIfExists(TableName.Organization); + await dropOnUpdateTrigger(knex, TableName.Organization); +} diff --git a/backend-pg/src/db/migrations/20231204092747_org-membership.ts b/backend-pg/src/db/migrations/20231204092747_org-membership.ts new file mode 100644 index 000000000..20e6e2fef --- /dev/null +++ b/backend-pg/src/db/migrations/20231204092747_org-membership.ts @@ -0,0 +1,30 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; +import { OrgMembershipStatus } from "../schemas/models"; +import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils"; + +export async function up(knex: Knex): Promise { + const isTablePresent = await knex.schema.hasTable(TableName.OrgMembership); + if (!isTablePresent) { + await knex.schema.createTable(TableName.OrgMembership, (t) => { + t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); + t.string("role").notNullable(); + t.string("status").notNullable().defaultTo(OrgMembershipStatus.Invited); + t.string("inviteEmail"); + // does not need update trigger we will do it manually + t.timestamps(true, true, true); + t.uuid("userId").notNullable(); + t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE"); + t.uuid("orgId").notNullable(); + t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE"); + }); + } + // this is a one time function + await createOnUpdateTrigger(knex, TableName.OrgMembership); +} + +export async function down(knex: Knex): Promise { + await knex.schema.dropTableIfExists(TableName.OrgMembership); + await dropOnUpdateTrigger(knex, TableName.OrgMembership); +} diff --git a/backend-pg/src/db/schemas/auth-token-sessions.ts b/backend-pg/src/db/schemas/auth-token-sessions.ts new file mode 100644 index 000000000..dd4fd9416 --- /dev/null +++ b/backend-pg/src/db/schemas/auth-token-sessions.ts @@ -0,0 +1,24 @@ +// Code generated by automation script, DO NOT EDIT. +// Automated by pulling database and generating zod schema +// To update. Just run npm run generate:schema +// Written by akhilmhdh. + +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const AuthTokenSessionsSchema = z.object({ + id: z.string().uuid(), + ip: z.string(), + userAgent: z.string().nullable().optional(), + refreshVersion: z.number().default(1), + accessVersion: z.number().default(1), + lastUsed: z.string().datetime(), + createdAt: z.string().datetime(), + updatedAt: z.string().datetime(), + userId: z.string().uuid(), +}); + +export type TAuthTokenSessions = z.infer; +export type TAuthTokenSessionsInsert = Omit; +export type TAuthTokenSessionsUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/auth-tokens.ts b/backend-pg/src/db/schemas/auth-tokens.ts new file mode 100644 index 000000000..a47146170 --- /dev/null +++ b/backend-pg/src/db/schemas/auth-tokens.ts @@ -0,0 +1,24 @@ +// Code generated by automation script, DO NOT EDIT. +// Automated by pulling database and generating zod schema +// To update. Just run npm run generate:schema +// Written by akhilmhdh. + +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const AuthTokensSchema = z.object({ + id: z.string().uuid(), + type: z.string(), + phoneNumber: z.string().nullable().optional(), + tokenHash: z.string(), + triesLeft: z.number().nullable().optional(), + expiresAt: z.string().datetime(), + createdAt: z.string().datetime(), + updatedAt: z.string().datetime(), + userId: z.string().uuid().nullable().optional(), +}); + +export type TAuthTokens = z.infer; +export type TAuthTokensInsert = Omit; +export type TAuthTokensUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/backup-private-key.ts b/backend-pg/src/db/schemas/backup-private-key.ts index 73bcc59a1..bb2b8a048 100644 --- a/backend-pg/src/db/schemas/backup-private-key.ts +++ b/backend-pg/src/db/schemas/backup-private-key.ts @@ -1,19 +1,24 @@ +// Code generated by automation script, DO NOT EDIT. +// Automated by pulling database and generating zod schema +// To update. Just run npm run generate:schema +// Written by akhilmhdh. + import { z } from "zod"; -import { SecretEncryptionAlgo, SecretKeyEncoding, TImmutableDBKeys } from "./models"; +import { TImmutableDBKeys } from "./models"; export const BackupPrivateKeySchema = z.object({ - id: z.string(), - userId: z.string(), + id: z.string().uuid(), encryptedPrivateKey: z.string(), iv: z.string(), tag: z.string(), - algorithm: z.nativeEnum(SecretEncryptionAlgo), - keyEncoding: z.nativeEnum(SecretKeyEncoding), + algorithm: z.string(), + keyEncoding: z.string(), salt: z.string(), verifier: z.string(), createdAt: z.string().datetime(), - updatedAt: z.string().datetime() + updatedAt: z.string().datetime(), + userId: z.string().uuid(), }); export type TBackupPrivateKey = z.infer; diff --git a/backend-pg/src/db/schemas/index.ts b/backend-pg/src/db/schemas/index.ts index 33c7fea0f..b63b35e14 100644 --- a/backend-pg/src/db/schemas/index.ts +++ b/backend-pg/src/db/schemas/index.ts @@ -1,15 +1,8 @@ -export { - BackupPrivateKeySchema, - TBackupPrivateKey, - TBackupPrivateKeyInsert, - TBackupPrivateKeyUpdate -} from "./backup-private-key"; -export { TableName } from "./models"; -export { TokenSchema, TToken, TTokenInsert, TTokenUpdate } from "./token"; -export { AuthMethod, TUser, TUserInsert, TUserUpdate, UserSchema } from "./user"; -export { - TUserEncryptionKey, - TUserEncryptionKeyInsert, - TUserEncryptionKeyUpdate, - UserEncryptionKey -} from "./user-encryption-key"; +export * from "./auth-token-sessions"; +export * from "./auth-tokens"; +export * from "./backup-private-key"; +export * from "./models"; +export * from "./organization-memberships"; +export * from "./organizations"; +export * from "./user-encryption-keys"; +export * from "./users"; diff --git a/backend-pg/src/db/schemas/models.ts b/backend-pg/src/db/schemas/models.ts index 8c9cc0daa..9be605cd2 100644 --- a/backend-pg/src/db/schemas/models.ts +++ b/backend-pg/src/db/schemas/models.ts @@ -1,13 +1,36 @@ +import { z } from "zod"; + export enum TableName { Users = "users", UserEncryptionKey = "user_encryption_keys", AuthTokens = "auth_tokens", AuthTokenSession = "auth_token_sessions", - BackupPrivateKey = "backup_private_key" + BackupPrivateKey = "backup_private_key", + Organization = "organizations", + OrgMembership = "organization_memberships" } export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt"; +export const UserDeviceSchema = z + .object({ + ip: z.string(), + userAgent: z.string() + }) + .array() + .default([]); + +export enum OrgMembershipRole { + Admin = "admin", + Member = "member", + Custom = "custom" +} + +export enum OrgMembershipStatus { + Invited = "invited", + Accepted = "accepted" +} + export enum SecretEncryptionAlgo { AES_256_GCM = "aes-256-gcm" } diff --git a/backend-pg/src/db/schemas/organization-memberships.ts b/backend-pg/src/db/schemas/organization-memberships.ts new file mode 100644 index 000000000..97cf01dbd --- /dev/null +++ b/backend-pg/src/db/schemas/organization-memberships.ts @@ -0,0 +1,23 @@ +// Code generated by automation script, DO NOT EDIT. +// Automated by pulling database and generating zod schema +// To update. Just run npm run generate:schema +// Written by akhilmhdh. + +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const OrganizationMembershipsSchema = z.object({ + id: z.string().uuid(), + role: z.string(), + status: z.string().default('invited'), + inviteEmail: z.string().nullable().optional(), + createdAt: z.string().datetime(), + updatedAt: z.string().datetime(), + userId: z.string().uuid(), + orgId: z.string().uuid(), +}); + +export type TOrganizationMemberships = z.infer; +export type TOrganizationMembershipsInsert = Omit; +export type TOrganizationMembershipsUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/organizations.ts b/backend-pg/src/db/schemas/organizations.ts new file mode 100644 index 000000000..a79b7c57b --- /dev/null +++ b/backend-pg/src/db/schemas/organizations.ts @@ -0,0 +1,20 @@ +// Code generated by automation script, DO NOT EDIT. +// Automated by pulling database and generating zod schema +// To update. Just run npm run generate:schema +// Written by akhilmhdh. + +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const OrganizationsSchema = z.object({ + id: z.string().uuid(), + name: z.string(), + customerId: z.string().nullable().optional(), + createdAt: z.string().datetime(), + updatedAt: z.string().datetime(), +}); + +export type TOrganizations = z.infer; +export type TOrganizationsInsert = Omit; +export type TOrganizationsUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/token-session.ts b/backend-pg/src/db/schemas/token-session.ts deleted file mode 100644 index 196871aa0..000000000 --- a/backend-pg/src/db/schemas/token-session.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from "zod"; - -import { TImmutableDBKeys } from "./models"; - -export const TokenSessionSchema = z.object({ - id: z.string(), - userId: z.string(), - ip: z.string(), - userAgent: z.string(), - refreshVersion: z.number().default(1), - accessVersion: z.number().default(1), - lastUsed: z.string().datetime() -}); - -export type TTokenSession = z.infer; -export type TTokenSessionInsert = Omit; -export type TTokenSessionUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/token.ts b/backend-pg/src/db/schemas/token.ts deleted file mode 100644 index 401d5db87..000000000 --- a/backend-pg/src/db/schemas/token.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { z } from "zod"; - -import { TImmutableDBKeys } from "./models"; - -export const TokenSchema = z.object({ - id: z.number(), - type: z.enum(["emailConfirmation", "emailMfa", "organizationInvitation", "passwordReset"]), - phoneNumber: z.string().optional(), - tokenHash: z.string(), - triesLeft: z.number().optional(), - expiresAt: z.string().datetime().optional(), - createdAt: z.string().datetime(), - updatedAt: z.string().datetime(), - userId: z.string().optional() -}); - -export type TToken = z.infer; -export type TTokenInsert = Omit; -export type TTokenUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/user-encryption-key.ts b/backend-pg/src/db/schemas/user-encryption-key.ts deleted file mode 100644 index 103ee5bd2..000000000 --- a/backend-pg/src/db/schemas/user-encryption-key.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { z } from "zod"; - -import { PickRequired } from "@app/lib/types"; - -import { TImmutableDBKeys } from "./models"; - -export const UserEncryptionKey = z.object({ - id: z.number(), - userId: z.string(), - serverPrivateKey: z.string().optional().nullable(), - clientPublicKey: z.string().optional().nullable(), - encryptionVersion: z.number().default(1).optional(), - protectedKey: z.string(), - protectedKeyIV: z.string(), - protectedKeyTag: z.string(), - publicKey: z.string(), - encryptedPrivateKey: z.string(), - iv: z.string(), - tag: z.string(), - salt: z.string(), - verifier: z.string() -}); - -export type TUserEncryptionKey = z.infer; -export type TUserEncryptionKeyInsert = Omit, TImmutableDBKeys>; -export type TUserEncryptionKeyUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/user-encryption-keys.ts b/backend-pg/src/db/schemas/user-encryption-keys.ts new file mode 100644 index 000000000..5d71c7f57 --- /dev/null +++ b/backend-pg/src/db/schemas/user-encryption-keys.ts @@ -0,0 +1,29 @@ +// Code generated by automation script, DO NOT EDIT. +// Automated by pulling database and generating zod schema +// To update. Just run npm run generate:schema +// Written by akhilmhdh. + +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const UserEncryptionKeysSchema = z.object({ + id: z.string().uuid(), + clientPublicKey: z.string().nullable().optional(), + serverPrivateKey: z.string().nullable().optional(), + encryptionVersion: z.number().default(1).nullable().optional(), + protectedKey: z.string(), + protectedKeyIV: z.string(), + protectedKeyTag: z.string(), + publicKey: z.string(), + encryptedPrivateKey: z.string(), + iv: z.string(), + tag: z.string(), + salt: z.string(), + verifier: z.string(), + userId: z.string().uuid(), +}); + +export type TUserEncryptionKeys = z.infer; +export type TUserEncryptionKeysInsert = Omit; +export type TUserEncryptionKeysUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/user.ts b/backend-pg/src/db/schemas/user.ts deleted file mode 100644 index 59428f08d..000000000 --- a/backend-pg/src/db/schemas/user.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { z } from "zod"; - -import { TImmutableDBKeys } from "./models"; - -export enum AuthMethod { - EMAIL = "email", - GOOGLE = "google", - GITHUB = "github", - GITLAB = "gitlab", - OKTA_SAML = "okta-saml", - AZURE_SAML = "azure-saml", - JUMPCLOUD_SAML = "jumpcloud-saml" -} - -export const UserSchema = z.object({ - id: z.string(), - authMethods: z.nativeEnum(AuthMethod).array().default([AuthMethod.EMAIL]).optional().nullable(), - email: z.string(), - isSuperAdmin: z.boolean().default(false).optional(), - firstName: z.string().optional().nullable(), - lastName: z.string().optional().nullable(), - isMfaEnabled: z.boolean().default(false).optional(), - mfaMethods: z.string().array().default([]).optional().nullable(), - isAccepted: z.boolean().default(false).optional(), - devices: z.string().nullable().optional() -}); - -export const UserDeviceSchema = z - .object({ - ip: z.string(), - userAgent: z.string() - }) - .array() - .default([]); - -export type TUser = z.infer; -export type TUserInsert = Omit; -export type TUserUpdate = Partial>; diff --git a/backend-pg/src/db/schemas/users.ts b/backend-pg/src/db/schemas/users.ts new file mode 100644 index 000000000..7e12344e1 --- /dev/null +++ b/backend-pg/src/db/schemas/users.ts @@ -0,0 +1,27 @@ +// Code generated by automation script, DO NOT EDIT. +// Automated by pulling database and generating zod schema +// To update. Just run npm run generate:schema +// Written by akhilmhdh. + +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const UsersSchema = z.object({ + id: z.string().uuid(), + email: z.string(), + authMethods: z.string().array().nullable().optional(), + superAdmin: z.boolean().default(false).nullable().optional(), + firstName: z.string().nullable().optional(), + lastName: z.string().nullable().optional(), + isAccepted: z.boolean().default(false).nullable().optional(), + isMfaEnabled: z.boolean().default(false).nullable().optional(), + mfaMethods: z.string().array().nullable().optional(), + devices: z.string().nullable().optional(), + createdAt: z.string().datetime(), + updatedAt: z.string().datetime(), +}); + +export type TUsers = z.infer; +export type TUsersInsert = Omit; +export type TUsersUpdate = Partial>; diff --git a/backend-pg/src/lib/errors/index.ts b/backend-pg/src/lib/errors/index.ts index ab090fa46..2786194e9 100644 --- a/backend-pg/src/lib/errors/index.ts +++ b/backend-pg/src/lib/errors/index.ts @@ -16,7 +16,7 @@ export class UnauthorizedError extends Error { error: unknown; - constructor({ name, error, message }: { message?: string; name: string; error: unknown }) { + constructor({ name, error, message }: { message?: string; name: string; error?: unknown }) { super(message ?? "You are not allowed to access this resourve"); this.name = name; this.error = error; diff --git a/backend-pg/src/lib/knex/index.ts b/backend-pg/src/lib/knex/index.ts new file mode 100644 index 000000000..d480f7301 --- /dev/null +++ b/backend-pg/src/lib/knex/index.ts @@ -0,0 +1,10 @@ +import { Knex } from "knex"; + +export const withTransaction = (db: Knex, dal: K) => ({ + transaction: async (cb: (tx: Knex) => T) => + db.transaction(async (trx) => { + const res = await cb(trx); + return res; + }), + ...dal +}); diff --git a/backend-pg/src/lib/zod/index.ts b/backend-pg/src/lib/zod/index.ts index 3b04f033e..331a5fbb6 100644 --- a/backend-pg/src/lib/zod/index.ts +++ b/backend-pg/src/lib/zod/index.ts @@ -1,7 +1,7 @@ -import { z } from "zod"; +import { z,ZodTypeAny } from "zod"; // this is a patched zod string to remove empty string to undefined -export const zpStr = ( +export const zpStr = ( schema: T, opt: { stripNull: boolean } = { stripNull: true } ) => diff --git a/backend-pg/src/server/plugins/auth/inject-identity.ts b/backend-pg/src/server/plugins/auth/inject-identity.ts new file mode 100644 index 000000000..6fcff596e --- /dev/null +++ b/backend-pg/src/server/plugins/auth/inject-identity.ts @@ -0,0 +1,75 @@ +import { FastifyRequest } from "fastify"; +import jwt, { JwtPayload } from "jsonwebtoken"; + +import { getConfig } from "@app/lib/config/env"; +import { UnauthorizedError } from "@app/lib/errors"; +import { AuthMode, AuthModeJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type"; + +const extractAuth = async (req: FastifyRequest, jwtSecret: string) => { + const apiKey = req.headers?.["x-api-key"]; + if (apiKey) { + return { authMode: AuthMode.API_KEY, token: apiKey }; + } + const authHeader = req.headers?.authorization; + if (!authHeader) return { authMode: null, token: null }; + + const authTokenValue = authHeader.slice(7); // slice of after Bearer + if (authTokenValue.startsWith("st.")) { + return { authMode: AuthMode.SERVICE_TOKEN, token: authTokenValue } as const; + } + + const decodedToken = jwt.verify(authTokenValue, jwtSecret) as JwtPayload; + switch (decodedToken.authTokenType) { + case AuthTokenType.ACCESS_TOKEN: + return { authMode: AuthMode.JWT, token: decodedToken as AuthModeJwtTokenPayload } as const; + case AuthTokenType.API_KEY: + return { authMode: AuthMode.API_KEY_V2, token: decodedToken } as const; + case AuthMode.SERVICE_ACCESS_TOKEN: + return { authMode: AuthMode.SERVICE_ACCESS_TOKEN, token: decodedToken } as const; + default: + throw new UnauthorizedError({ name: "Invalid token type" }); + } +}; + +const getJwtIdentity = async (server: FastifyZodProvider, token: AuthModeJwtTokenPayload) => { + const session = await server.services.authToken.getUserTokenSessionById( + token.tokenVersionId, + token.userId + ); + + if (!session) throw new UnauthorizedError({ name: "Session not found" }); + if (token.accessVersion !== session.accessVersion) + throw new UnauthorizedError({ name: "Stale session" }); + + const user = await server.store.user.getUserById(session.userId); + if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" }); + + return user; +}; + +export const injectIdentity = (server: FastifyZodProvider) => { + server.decorateRequest("auth", null); + server.addHook("onRequest", async (req) => { + const appCfg = getConfig(); + const { authMode, token } = await extractAuth(req, appCfg.JWT_AUTH_SECRET); + if (!authMode) return; + // TODO(akhilmhdh-pg): fill in rest of auth mode logic + switch (authMode) { + case AuthMode.JWT: { + const user = await getJwtIdentity(server, token as AuthModeJwtTokenPayload); + req.auth = { authMode: AuthMode.JWT, user, userId: user.id }; + break; + } + case AuthMode.SERVICE_TOKEN: + break; + case AuthMode.SERVICE_ACCESS_TOKEN: + break; + case AuthMode.API_KEY: + break; + case AuthMode.API_KEY_V2: + break; + default: + throw new UnauthorizedError({ name: "Unknown token strategy" }); + } + }); +}; diff --git a/backend-pg/src/server/plugins/auth/verify-auth.ts b/backend-pg/src/server/plugins/auth/verify-auth.ts new file mode 100644 index 000000000..90432e380 --- /dev/null +++ b/backend-pg/src/server/plugins/auth/verify-auth.ts @@ -0,0 +1,17 @@ +import { FastifyRequest } from "fastify"; + +import { UnauthorizedError } from "@app/lib/errors"; +import { AuthMode } from "@app/services/auth/auth-type"; + +export const verifyAuth = + (authStrats: AuthMode[]) => + (req: T) => { + if (!Array.isArray(authStrats)) throw new Error("Auth strategy must be array"); + if (!req.auth) + throw new UnauthorizedError({ name: "Unauthorized access", message: "Token missing" }); + + const isAccessAllowed = authStrats.some((strat) => strat === req.auth.authMode); + if (!isAccessAllowed) { + throw new UnauthorizedError({ name: `${req.url} Unauthorized Access` }); + } + }; diff --git a/backend-pg/src/server/routes/index.ts b/backend-pg/src/server/routes/index.ts index 3488843ad..8d81b238a 100644 --- a/backend-pg/src/server/routes/index.ts +++ b/backend-pg/src/server/routes/index.ts @@ -11,6 +11,7 @@ import { tokenServiceFactory } from "@app/services/token/token-service"; import { registerV1Routes } from "./v1"; import { registerV2Routes } from "./v2"; import { registerV3Routes } from "./v3"; +import { injectIdentity } from "../plugins/auth/inject-identity"; export const registerRoutes = async ( server: FastifyZodProvider, @@ -37,6 +38,8 @@ export const registerRoutes = async ( user: authDal } as FastifyZodProvider["store"]); + await server.register(injectIdentity); + // register routes for v1 await server.register(registerV1Routes, { prefix: "/v1" }); await server.register(registerV2Routes, { prefix: "/v2" }); diff --git a/backend-pg/src/server/routes/v1/password-router.ts b/backend-pg/src/server/routes/v1/password-router.ts index d506f9814..92da5eeea 100644 --- a/backend-pg/src/server/routes/v1/password-router.ts +++ b/backend-pg/src/server/routes/v1/password-router.ts @@ -2,6 +2,8 @@ import { z } from "zod"; import { BackupPrivateKeySchema } from "@app/db/schemas"; import { getConfig } from "@app/lib/config/env"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { AuthMode } from "@app/services/auth/auth-type"; export const registerPasswordRouter = async (server: FastifyZodProvider) => { server.route({ @@ -18,6 +20,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { }) } }, + onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { const { salt, serverPublicKey } = await server.services.password.generateServerPubKey( req.auth.userId, @@ -48,6 +51,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { }) } }, + onRequest: verifyAuth([AuthMode.JWT]), handler: async (req, res) => { const appCfg = getConfig(); await server.services.password.changePassword({ ...req.body, userId: req.auth.userId }); @@ -65,6 +69,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", url: "/backup-private-key", + onRequest: verifyAuth([AuthMode.JWT]), schema: { body: z.object({ clientProof: z.string().trim(), @@ -95,6 +100,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", url: "/backup-private-key", + onRequest: verifyAuth([AuthMode.JWT]), schema: { response: { 200: z.object({ diff --git a/backend-pg/src/server/routes/v2/mfa-router.ts b/backend-pg/src/server/routes/v2/mfa-router.ts index b5fbfadcb..71f841ad7 100644 --- a/backend-pg/src/server/routes/v2/mfa-router.ts +++ b/backend-pg/src/server/routes/v2/mfa-router.ts @@ -2,20 +2,24 @@ import jwt, { JwtPayload } from "jsonwebtoken"; import { z } from "zod"; import { getConfig } from "@app/lib/config/env"; -import { AuthTokenType } from "@app/services/auth/auth-signup-type"; +import { AuthTokenType } from "@app/services/auth/auth-type"; export const registerMfaRouter = async (server: FastifyZodProvider) => { const cfg = getConfig(); + server.decorateRequest("mfa", null); server.addHook("preParsing", async (req, res) => { const authorizationHeader = req.headers.authorization; if (!authorizationHeader || !authorizationHeader.startsWith("Bearer ")) { res.status(401).send({ error: "Missing bearer token" }); - return; + return res; } const token = authorizationHeader.split(" ")[1]; - if (!token) res.status(401).send({ error: "Missing bearer token" }); + if (!token) { + res.status(401).send({ error: "Missing bearer token" }); + return res; + } const decodedToken = jwt.verify(token, cfg.JWT_AUTH_SECRET) as JwtPayload; if (decodedToken.authTokenType !== AuthTokenType.MFA_TOKEN) @@ -23,8 +27,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => { const user = await server.store.user.getUserById(decodedToken.userId); if (!user) throw new Error("User not found"); - req.mfa.userId = user.id; - req.mfa.user = user; + req.mfa = { userId: user.id, user }; }); server.route({ @@ -52,7 +55,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => { }), response: { 200: z.object({ - encryptionVersion: z.number().default(1).optional(), + encryptionVersion: z.number().default(1).nullable().optional(), protectedKey: z.string(), protectedKeyIV: z.string(), protectedKeyTag: z.string(), diff --git a/backend-pg/src/server/routes/v3/login-router.ts b/backend-pg/src/server/routes/v3/login-router.ts index 83fa5f89e..5af1ba448 100644 --- a/backend-pg/src/server/routes/v3/login-router.ts +++ b/backend-pg/src/server/routes/v3/login-router.ts @@ -44,7 +44,7 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => { z.object({ mfaEnabled: z.literal(true), token: z.string() }), z.object({ mfaEnabled: z.literal(false), - encryptionVersion: z.number().default(1).optional(), + encryptionVersion: z.number().default(1).nullable().optional(), protectedKey: z.string(), protectedKeyIV: z.string(), protectedKeyTag: z.string(), diff --git a/backend-pg/src/server/routes/v3/signup-router.ts b/backend-pg/src/server/routes/v3/signup-router.ts index ff6ec2036..731b79548 100644 --- a/backend-pg/src/server/routes/v3/signup-router.ts +++ b/backend-pg/src/server/routes/v3/signup-router.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { UserSchema } from "@app/db/schemas"; +import { UsersSchema } from "@app/db/schemas"; import { getConfig } from "@app/lib/config/env"; export const registerSignupRouter = async (server: FastifyZodProvider) => { @@ -35,7 +35,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => { 200: z.object({ message: z.string(), token: z.string(), - user: UserSchema + user: UsersSchema }) } }, @@ -72,7 +72,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => { response: { 200: z.object({ message: z.string(), - user: UserSchema, + user: UsersSchema, token: z.string() }) } diff --git a/backend-pg/src/services/auth/auth-dal.ts b/backend-pg/src/services/auth/auth-dal.ts index eb539f911..004cde5b4 100644 --- a/backend-pg/src/services/auth/auth-dal.ts +++ b/backend-pg/src/services/auth/auth-dal.ts @@ -1,16 +1,17 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName, TBackupPrivateKey, TUser, TUserEncryptionKey } from "@app/db/schemas"; +import { TableName, TBackupPrivateKey, TUserEncryptionKeys, TUsers } from "@app/db/schemas"; +import { withTransaction } from "@app/lib/knex"; export type TAuthDalFactory = ReturnType; export const authDalFactory = (db: TDbClient) => { // getters - const getUserByEmail = async (email: string): Promise => + const getUserByEmail = async (email: string): Promise => db(TableName.Users).where({ email }).select("*").first(); - const getUserById = async (userId: string): Promise => + const getUserById = async (userId: string): Promise => db(TableName.Users).where({ id: userId }).select("*").first(); const getUserEncKeyByEmail = async (email: string) => @@ -39,8 +40,8 @@ export const authDalFactory = (db: TDbClient) => { // all inserts and updates const createUser = async ( email: string, - data: Partial = {} - ): Promise => { + data: Partial = {} + ): Promise => { const [user] = await db(TableName.Users) .insert({ email, ...data }) .returning("*"); @@ -49,8 +50,8 @@ export const authDalFactory = (db: TDbClient) => { const updateUser = async ( email: string, - data: Partial = {} - ): Promise => { + data: Partial = {} + ): Promise => { const [user] = await db(TableName.Users) .where({ email }) .update({ ...data }) @@ -60,9 +61,9 @@ export const authDalFactory = (db: TDbClient) => { const updateUserById = async ( id: string, - data: Partial = {}, + data: Partial = {}, tx?: Knex - ): Promise => { + ): Promise => { const [user] = await (tx ? tx(TableName.Users) : db(TableName.Users)) .where({ id }) .update({ ...data }) @@ -72,9 +73,9 @@ export const authDalFactory = (db: TDbClient) => { const updateUserEncryptionByUserId = async ( userId: string, - data: Partial = {}, + data: Partial = {}, tx?: Knex - ): Promise => { + ): Promise => { const [userEnc] = await (tx ? tx(TableName.UserEncryptionKey) : db(TableName.UserEncryptionKey)) .where({ userId }) .update({ ...data }) @@ -85,12 +86,12 @@ export const authDalFactory = (db: TDbClient) => { // all upserts const upsertUserEncryptionKey = async ( userId: string, - data: Partial, + data: Partial, tx?: Knex ) => { const [userEnc] = await (tx ? tx(TableName.UserEncryptionKey) : db(TableName.UserEncryptionKey)) // if user insert make sure to pass all required data - .insert({ userId, ...data } as TUserEncryptionKey) + .insert({ userId, ...data } as TUserEncryptionKeys) .onConflict("userId") .merge() .returning("*"); @@ -110,12 +111,7 @@ export const authDalFactory = (db: TDbClient) => { return backupKey; }; - return { - transaction: async (cb: (tx: Knex) => T) => - db.transaction(async (trx) => { - const res = await cb(trx); - return res; - }), + return withTransaction(db, { getUserByEmail, getUserById, getUserEncKeyByEmail, @@ -127,5 +123,5 @@ export const authDalFactory = (db: TDbClient) => { updateUserEncryptionByUserId, upsertUserEncryptionKey, upsertBackupKey - }; + }); }; diff --git a/backend-pg/src/services/auth/auth-login-service.ts b/backend-pg/src/services/auth/auth-login-service.ts index b1850e789..4b44adcc6 100644 --- a/backend-pg/src/services/auth/auth-login-service.ts +++ b/backend-pg/src/services/auth/auth-login-service.ts @@ -1,12 +1,11 @@ import jwt from "jsonwebtoken"; -import { AuthMethod, TUser } from "@app/db/schemas"; -import { UserDeviceSchema } from "@app/db/schemas/user"; +import { TUsers, UserDeviceSchema } from "@app/db/schemas"; import { getConfig } from "@app/lib/config/env"; import { generateSrpServerKey, srpCheckClientProof } from "@app/lib/crypto"; import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service"; -import { TTokenServiceFactory } from "../token/token-service"; +import { TAuthTokenServiceFactory } from "../token/token-service"; import { TokenType } from "../token/token-types"; import { TAuthDalFactory } from "./auth-dal"; import { @@ -14,7 +13,7 @@ import { TLoginGenServerPublicKeyDTO, TVerifyMfaTokenDTO } from "./auth-login-type"; -import { AuthTokenType } from "./auth-signup-type"; +import { AuthMethod, AuthTokenType } from "./auth-type"; const isValidProviderAuthToken = (email: string, jwtSecret: string, providerAuthToken?: string) => { if (!providerAuthToken) return false; @@ -27,7 +26,7 @@ const isValidProviderAuthToken = (email: string, jwtSecret: string, providerAuth type TAuthLoginServiceFactoryDep = { authDal: TAuthDalFactory; - tokenService: TTokenServiceFactory; + tokenService: TAuthTokenServiceFactory; smtpService: TSmtpService; }; @@ -42,7 +41,7 @@ export const authLoginServiceFactory = ({ * Not exported. This is to update user device list * If new device is found. Will be saved and a mail will be send */ - const updateUserDeviceSession = async (user: TUser, ip: string, userAgent: string) => { + const updateUserDeviceSession = async (user: TUsers, ip: string, userAgent: string) => { const devices = await UserDeviceSchema.parseAsync(JSON.parse(user.devices || "[]")); const isDeviceSeen = devices.some( (device) => device.ip === ip && device.userAgent === userAgent @@ -69,7 +68,7 @@ export const authLoginServiceFactory = ({ * Private * Send mfa code via email * */ - const sendUserMfaCode = async (user: TUser) => { + const sendUserMfaCode = async (user: TUsers) => { const code = await tokenService.createTokenForUser({ type: TokenType.TOKEN_EMAIL_MFA, userId: user.id @@ -89,7 +88,7 @@ export const authLoginServiceFactory = ({ * Check user device and send mail if new device * generate the auth and refresh token. fn shared by mfa verification and login verification with mfa disabled */ - const generateUserTokens = async (user: TUser, ip: string, userAgent: string) => { + const generateUserTokens = async (user: TUsers, ip: string, userAgent: string) => { const cfg = getConfig(); await updateUserDeviceSession(user, ip, userAgent); const tokenSession = await tokenService.getUserTokenSession({ diff --git a/backend-pg/src/services/auth/auth-password-service.ts b/backend-pg/src/services/auth/auth-password-service.ts index ea41198a6..cf748958e 100644 --- a/backend-pg/src/services/auth/auth-password-service.ts +++ b/backend-pg/src/services/auth/auth-password-service.ts @@ -4,7 +4,7 @@ import { getConfig } from "@app/lib/config/env"; import { generateSrpServerKey, srpCheckClientProof } from "@app/lib/crypto"; import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service"; -import { TTokenServiceFactory } from "../token/token-service"; +import { TAuthTokenServiceFactory } from "../token/token-service"; import { TokenType } from "../token/token-types"; import { TAuthDalFactory } from "./auth-dal"; import { @@ -12,11 +12,11 @@ import { TCreateBackupPrivateKeyDTO, TResetPasswordViaBackupKeyDTO } from "./auth-password-type"; -import { AuthTokenType } from "./auth-signup-type"; +import { AuthTokenType } from "./auth-type"; type TAuthPasswordServiceFactoryDep = { authDal: TAuthDalFactory; - tokenService: TTokenServiceFactory; + tokenService: TAuthTokenServiceFactory; smtpService: TSmtpService; }; diff --git a/backend-pg/src/services/auth/auth-signup-service.ts b/backend-pg/src/services/auth/auth-signup-service.ts index ef2fafa3b..adefb385a 100644 --- a/backend-pg/src/services/auth/auth-signup-service.ts +++ b/backend-pg/src/services/auth/auth-signup-service.ts @@ -1,16 +1,18 @@ -import { AuthMethod } from "@app/db/schemas"; +import jwt from "jsonwebtoken"; + import { getConfig } from "@app/lib/config/env"; import { isDisposableEmail } from "@app/lib/validator"; import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service"; -import { TTokenServiceFactory } from "../token/token-service"; +import { TAuthTokenServiceFactory } from "../token/token-service"; import { TokenType } from "../token/token-types"; import { TAuthDalFactory } from "./auth-dal"; -import { AuthTokenType, TCompleteAccountSignupDTO } from "./auth-signup-type"; +import { TCompleteAccountSignupDTO } from "./auth-signup-type"; +import { AuthMethod, AuthTokenType } from "./auth-type"; type TAuthSignupDep = { authDal: TAuthDalFactory; - tokenService: TTokenServiceFactory; + tokenService: TAuthTokenServiceFactory; smtpService: TSmtpService; }; @@ -66,7 +68,7 @@ export const authSignupServiceFactory = ({ }); // generate jwt token this is a temporary token - const jwtToken = tokenService.createJwtToken( + const jwtToken = jwt.sign( { authTokenType: AuthTokenType.SIGNUP_TOKEN, userId: user.id.toString() @@ -136,7 +138,7 @@ export const authSignupServiceFactory = ({ if (!tokenSession) throw new Error("Failed to create token"); const appCfg = getConfig(); - const accessToken = tokenService.createJwtToken( + const accessToken = jwt.sign( { authTokenType: AuthTokenType.ACCESS_TOKEN, userId: updateduser.info.id, @@ -147,7 +149,7 @@ export const authSignupServiceFactory = ({ { expiresIn: appCfg.JWT_SIGNUP_LIFETIME } ); - const refreshToken = tokenService.createJwtToken( + const refreshToken = jwt.sign( { authTokenType: AuthTokenType.REFRESH_TOKEN, userId: updateduser.info.id, diff --git a/backend-pg/src/services/auth/auth-signup-type.ts b/backend-pg/src/services/auth/auth-signup-type.ts index ddfa15336..2d1310a24 100644 --- a/backend-pg/src/services/auth/auth-signup-type.ts +++ b/backend-pg/src/services/auth/auth-signup-type.ts @@ -1,22 +1,3 @@ -export enum AuthTokenType { - ACCESS_TOKEN = "accessToken", - REFRESH_TOKEN = "refreshToken", - SIGNUP_TOKEN = "signupToken", // TODO: remove in favor of claim - MFA_TOKEN = "mfaToken", // TODO: remove in favor of claim - PROVIDER_TOKEN = "providerToken", // TODO: remove in favor of claim - API_KEY = "apiKey", - SERVICE_ACCESS_TOKEN = "serviceAccessToken", - SERVICE_REFRESH_TOKEN = "serviceRefreshToken" -} - -export enum AuthMode { - JWT = "jwt", - SERVICE_TOKEN = "serviceToken", - SERVICE_ACCESS_TOKEN = "serviceAccessToken", - API_KEY = "apiKey", - API_KEY_V2 = "apiKeyV2" -} - export type TCompleteAccountSignupDTO = { email: string; firstName: string; diff --git a/backend-pg/src/services/auth/auth-type.ts b/backend-pg/src/services/auth/auth-type.ts new file mode 100644 index 000000000..b80cb6d42 --- /dev/null +++ b/backend-pg/src/services/auth/auth-type.ts @@ -0,0 +1,35 @@ +export enum AuthMethod { + EMAIL = "email", + GOOGLE = "google", + GITHUB = "github", + GITLAB = "gitlab", + OKTA_SAML = "okta-saml", + AZURE_SAML = "azure-saml", + JUMPCLOUD_SAML = "jumpcloud-saml" +} + +export enum AuthTokenType { + ACCESS_TOKEN = "accessToken", + REFRESH_TOKEN = "refreshToken", + SIGNUP_TOKEN = "signupToken", // TODO: remove in favor of claim + MFA_TOKEN = "mfaToken", // TODO: remove in favor of claim + PROVIDER_TOKEN = "providerToken", // TODO: remove in favor of claim + API_KEY = "apiKey", + SERVICE_ACCESS_TOKEN = "serviceAccessToken", + SERVICE_REFRESH_TOKEN = "serviceRefreshToken" +} + +export enum AuthMode { + JWT = "jwt", + SERVICE_TOKEN = "serviceToken", + SERVICE_ACCESS_TOKEN = "serviceAccessToken", + API_KEY = "apiKey", + API_KEY_V2 = "apiKeyV2" +} + +export type AuthModeJwtTokenPayload = { + authTokenType: AuthTokenType.ACCESS_TOKEN; + userId: string; + tokenVersionId: string; + accessVersion: number; +}; diff --git a/backend-pg/src/services/token/token-dal.ts b/backend-pg/src/services/token/token-dal.ts index 823508610..16db26468 100644 --- a/backend-pg/src/services/token/token-dal.ts +++ b/backend-pg/src/services/token/token-dal.ts @@ -1,6 +1,5 @@ import { TDbClient } from "@app/db"; -import { TableName, TToken } from "@app/db/schemas"; -import { TTokenSession } from "@app/db/schemas/token-session"; +import { TableName, TAuthTokens, TAuthTokenSessions } from "@app/db/schemas"; import { TDeleteTokenForUserDalDTO, @@ -19,7 +18,7 @@ export const tokenDalFactory = (db: TDbClient) => { userId, type, triesLeft - }: TUpsertTokenForUserDalDTO): Promise => { + }: TUpsertTokenForUserDalDTO): Promise => { const token = await db.transaction(async (tx) => { await tx(TableName.AuthTokens).where({ userId, type }).delete().returning("*"); const [newToken] = await tx(TableName.AuthTokens) @@ -33,13 +32,23 @@ export const tokenDalFactory = (db: TDbClient) => { const getTokenForUser = async ({ userId, type - }: TGetTokenForUserDalDTO): Promise => + }: TGetTokenForUserDalDTO): Promise => db(TableName.AuthTokens).where({ userId, type }).first(); + const getTokenSession = async ( + userId: string, + ip: string, + userAgent: string + ): Promise => + db(TableName.AuthTokenSession).where({ userId, ip, userAgent }).first(); + + const getTokenSessionById = async (id: string, userId: string) => + db(TableName.AuthTokenSession).where({ id, userId }).first(); + const deleteTokenForUser = async ({ userId, type - }: TDeleteTokenForUserDalDTO): Promise => + }: TDeleteTokenForUserDalDTO): Promise => db(TableName.AuthTokens).where({ userId, type }).delete().returning("*"); const decrementTriesField = async ({ @@ -49,18 +58,11 @@ export const tokenDalFactory = (db: TDbClient) => { await db(TableName.AuthTokens).where({ userId, type }).decrement("triesLeft", 1); }; - const getTokenSession = async ( - userId: string, - ip: string, - userAgent: string - ): Promise => - db(TableName.AuthTokenSession).where({ userId, ip, userAgent }).first(); - const insertTokenSession = async ( userId: string, ip: string, userAgent: string - ): Promise => { + ): Promise => { const [session] = await db(TableName.AuthTokenSession) .insert({ userId, @@ -77,7 +79,7 @@ export const tokenDalFactory = (db: TDbClient) => { const incrementVersion = async ( userId: string, sessionId: string - ): Promise => { + ): Promise => { const [session] = await db(TableName.AuthTokenSession) .where({ userId, id: sessionId }) .increment("accessVersion", 1) @@ -87,8 +89,9 @@ export const tokenDalFactory = (db: TDbClient) => { }; return { - upsertTokenForUser, getTokenForUser, + getTokenSessionById, + upsertTokenForUser, deleteTokenForUser, decrementTriesField, getTokenSession, diff --git a/backend-pg/src/services/token/token-service.ts b/backend-pg/src/services/token/token-service.ts index 1b7c80c43..37f577a7d 100644 --- a/backend-pg/src/services/token/token-service.ts +++ b/backend-pg/src/services/token/token-service.ts @@ -1,9 +1,7 @@ import crypto from "node:crypto"; import bcrypt from "bcrypt"; -import jwt, { SignOptions } from "jsonwebtoken"; -import { TToken } from "@app/db/schemas"; -import { TTokenSession } from "@app/db/schemas/token-session"; +import { TAuthTokens, TAuthTokenSessions } from "@app/db/schemas"; import { getConfig } from "@app/lib/config/env"; import { TTokenDalFactory } from "./token-dal"; @@ -14,11 +12,11 @@ import { TValidateTokenForUserDTO } from "./token-types"; -type TTokenServiceFactoryDep = { +type TAuthTokenServiceFactoryDep = { tokenDal: TTokenDalFactory; // adjust the expiry from env through here }; -export type TTokenServiceFactory = ReturnType; +export type TAuthTokenServiceFactory = ReturnType; export const getTokenConfig = (tokenType: TokenType) => { // generate random token based on specified token use-case @@ -57,7 +55,7 @@ export const getTokenConfig = (tokenType: TokenType) => { } }; -export const tokenServiceFactory = ({ tokenDal }: TTokenServiceFactoryDep) => { +export const tokenServiceFactory = ({ tokenDal }: TAuthTokenServiceFactoryDep) => { const createTokenForUser = async ({ type, userId }: TCreateTokenForUserDTO) => { const { token, ...tkCfg } = getTokenConfig(type); const appCfg = getConfig(); @@ -76,7 +74,7 @@ export const tokenServiceFactory = ({ tokenDal }: TTokenServiceFactoryDep) => { type, userId, code - }: TValidateTokenForUserDTO): Promise => { + }: TValidateTokenForUserDTO): Promise => { const token = await tokenDal.getTokenForUser({ type, userId }); // validate token if (!token) throw new Error("Failed to find token"); @@ -105,7 +103,7 @@ export const tokenServiceFactory = ({ tokenDal }: TTokenServiceFactoryDep) => { userId, ip, userAgent - }: TIssueAuthTokenDTO): Promise => { + }: TIssueAuthTokenDTO): Promise => { let session = await tokenDal.getTokenSession(userId, ip, userAgent); if (!session) { session = await tokenDal.insertTokenSession(userId, ip, userAgent); @@ -113,22 +111,19 @@ export const tokenServiceFactory = ({ tokenDal }: TTokenServiceFactoryDep) => { return session; }; + const getUserTokenSessionById = async (id: string, userId: string) => + tokenDal.getTokenSessionById(id, userId); + const clearTokenSessionById = async ( userId: string, sessionId: string - ): Promise => tokenDal.incrementVersion(userId, sessionId); - - const createJwtToken = ( - payload: string | Buffer | object, - secret: string, - options?: SignOptions - ) => jwt.sign(payload, secret, options); + ): Promise => tokenDal.incrementVersion(userId, sessionId); return { createTokenForUser, validateTokenForUser, - createJwtToken, getUserTokenSession, - clearTokenSessionById + clearTokenSessionById, + getUserTokenSessionById }; }; diff --git a/backend/src/utils/authn/helpers/index.ts b/backend/src/utils/authn/helpers/index.ts index 7f3998e57..45849c989 100644 --- a/backend/src/utils/authn/helpers/index.ts +++ b/backend/src/utils/authn/helpers/index.ts @@ -16,19 +16,19 @@ import { getUserAgentType } from "../../posthog"; export * from "./authDataExtractors"; interface ExtractAuthModeParams { - headers: { [key: string]: string | string[] | undefined } + headers: { [key: string]: string | string[] | undefined }; } interface ExtractAuthModeReturn { - authMode: AuthMode; - authTokenValue: string; + authMode: AuthMode; + authTokenValue: string; } interface GetAuthDataParams { - authMode: AuthMode; - authTokenValue: string; - ipAddress: string; - userAgent: string; + authMode: AuthMode; + authTokenValue: string; + ipAddress: string; + userAgent: string; } /** @@ -44,33 +44,30 @@ interface GetAuthDataParams { * @throws {UnauthorizedError} Throws an error if no applicable authMode is found. */ export const extractAuthMode = async ({ - headers + headers }: ExtractAuthModeParams): Promise => { + const apiKey = headers["x-api-key"] as string; + const authHeader = headers["authorization"] as string; - const apiKey = headers["x-api-key"] as string; - const authHeader = headers["authorization"] as string; - - if (apiKey) { - return { authMode: AuthMode.API_KEY, authTokenValue: apiKey }; - } - - if (!authHeader) throw UnauthorizedRequestError({ - message: "Failed to authenticate unknown authentication method" + if (apiKey) { + return { authMode: AuthMode.API_KEY, authTokenValue: apiKey }; + } + + if (!authHeader) + throw UnauthorizedRequestError({ + message: "Failed to authenticate unknown authentication method" }); - if (!authHeader.startsWith("Bearer ")) throw UnauthorizedRequestError({ - message: "Failed to authenticate unknown authentication method" + if (!authHeader.startsWith("Bearer ")) + throw UnauthorizedRequestError({ + message: "Failed to authenticate unknown authentication method" }); - const authTokenValue = authHeader.slice(7); - - if (authTokenValue.startsWith("st.")) { - return { authMode: AuthMode.SERVICE_TOKEN, authTokenValue }; - } + const authTokenValue = authHeader.slice(7); - const decodedToken = ( - jwt.verify(authTokenValue, await getAuthSecret()) - ); + if (authTokenValue.startsWith("st.")) { + return { authMode: AuthMode.SERVICE_TOKEN, authTokenValue }; + } switch (decodedToken.authTokenType) { case AuthTokenType.ACCESS_TOKEN: @@ -87,13 +84,18 @@ export const extractAuthMode = async ({ } export const getAuthData = async ({ - authMode, - authTokenValue, - ipAddress, - userAgent + authMode, + authTokenValue, + ipAddress, + userAgent }: GetAuthDataParams): Promise => { + const userAgentType = getUserAgentType(userAgent); - const userAgentType = getUserAgentType(userAgent); + switch (authMode) { + case AuthMode.SERVICE_TOKEN: { + const serviceTokenData = await validateServiceTokenV2({ + authTokenValue + }); switch (authMode) { case AuthMode.SERVICE_TOKEN: { @@ -193,4 +195,81 @@ export const getAuthData = async ({ } } } -} \ No newline at end of file + case AuthMode.SERVICE_ACCESS_TOKEN: { + const serviceTokenData = await validateServiceTokenV3({ + authTokenValue + }); + + return { + actor: { + type: ActorType.SERVICE_V3, + metadata: { + serviceId: serviceTokenData._id.toString(), + name: serviceTokenData.name + } + }, + authPayload: serviceTokenData, + ipAddress, + userAgent, + userAgentType + }; + } + case AuthMode.API_KEY: { + const user = await validateAPIKey({ + authTokenValue + }); + + return { + actor: { + type: ActorType.USER, + metadata: { + userId: user._id.toString(), + email: user.email + } + }, + authPayload: user, + ipAddress, + userAgent, + userAgentType + }; + } + case AuthMode.API_KEY_V2: { + const user = await validateAPIKeyV2({ + authTokenValue + }); + + return { + actor: { + type: ActorType.USER, + metadata: { + userId: user._id.toString(), + email: user.email + } + }, + authPayload: user, + ipAddress, + userAgent, + userAgentType + }; + } + case AuthMode.JWT: { + const user = await validateJWT({ + authTokenValue + }); + + return { + actor: { + type: ActorType.USER, + metadata: { + userId: user._id.toString(), + email: user.email + } + }, + authPayload: user, + ipAddress, + userAgent, + userAgentType + }; + } + } +}; diff --git a/frontend/src/components/AddTagPopoverContent/AddTagPopoverContent.tsx b/frontend/src/components/AddTagPopoverContent/AddTagPopoverContent.tsx index 77ca8c24f..d69cc76c8 100644 --- a/frontend/src/components/AddTagPopoverContent/AddTagPopoverContent.tsx +++ b/frontend/src/components/AddTagPopoverContent/AddTagPopoverContent.tsx @@ -41,7 +41,7 @@ const AddTagPopoverContent = ({
{wsTags?.map((wsTag: WsTag) => (
handleSelectTag(wsTag)} onMouseEnter={() => handleTagOnMouseEnter(wsTag)} diff --git a/frontend/src/components/basic/dialog/UpgradePlan.tsx b/frontend/src/components/basic/dialog/UpgradePlan.tsx index 0fd9af404..517d5a233 100644 --- a/frontend/src/components/basic/dialog/UpgradePlan.tsx +++ b/frontend/src/components/basic/dialog/UpgradePlan.tsx @@ -64,7 +64,7 @@ const UpgradePlanModal = ({ diff --git a/frontend/src/components/basic/table/ProjectUsersTable.tsx b/frontend/src/components/basic/table/ProjectUsersTable.tsx index 5838aaf41..a00eb6543 100644 --- a/frontend/src/components/basic/table/ProjectUsersTable.tsx +++ b/frontend/src/components/basic/table/ProjectUsersTable.tsx @@ -41,7 +41,7 @@ type EnvironmentProps = { const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoading }: Props) => { const { currentWorkspace } = useWorkspace(); const { subscription } = useSubscription(); - const { data: wsKey } = useGetUserWsKey(currentWorkspace?._id ?? ""); + const { data: wsKey } = useGetUserWsKey(currentWorkspace?.id ?? ""); const { mutateAsync: deleteUserFromWorkspaceMutateAsync } = useDeleteUserFromWorkspace(); const { mutateAsync: uploadWsKeyMutateAsync } = useUploadWsKey(); diff --git a/frontend/src/components/dashboard/AddTagsMenu.tsx b/frontend/src/components/dashboard/AddTagsMenu.tsx index e97c979a9..dfa902b87 100644 --- a/frontend/src/components/dashboard/AddTagsMenu.tsx +++ b/frontend/src/components/dashboard/AddTagsMenu.tsx @@ -37,7 +37,7 @@ const AddTagsMenu = ({ allTags, currentTags, modifyTags, id }: { allTags: Tag[]; > {allTags?.map((tag) => { return ( - + +
+ ( + + + + )} + /> +
+ ( + onChange(isChecked)} + isChecked={value} + > + Refresh Token Rotation + + )} + /> +

When enabled, as a result of exchanging a refresh token, a new refresh token will be issued and the existing token will be invalidated.

+
+
+ + +
+ + +
+ + ) : ( +
+

{newServiceTokenJSON}

+ + + + Click to copy + + +
+ )} + handlePopUpToggle("upgradePlan", isOpen)} + text="You can use IP allowlisting if you switch to Infisical's Pro plan." + /> + + + ); +} \ No newline at end of file diff --git a/frontend/src/views/Project/MembersPage/components/ServiceTokenTab/components/ServiceTokenV3Section/ServiceTokenV3Table.tsx b/frontend/src/views/Project/MembersPage/components/ServiceTokenTab/components/ServiceTokenV3Section/ServiceTokenV3Table.tsx new file mode 100644 index 000000000..43fb841e3 --- /dev/null +++ b/frontend/src/views/Project/MembersPage/components/ServiceTokenTab/components/ServiceTokenV3Section/ServiceTokenV3Table.tsx @@ -0,0 +1,218 @@ +import { faKey, faPencil,faXmark } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { format } from "date-fns"; + +import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; +import { ProjectPermissionCan } from "@app/components/permissions"; +import { + EmptyState, + IconButton, + Switch, + Table, + TableContainer, + TableSkeleton, + TBody, + Td, + Th, + THead, + Tr +} from "@app/components/v2"; +import { ProjectPermissionActions, ProjectPermissionSub , useWorkspace } from "@app/context"; +import { + useGetWorkspaceServiceTokenDataV3, + useUpdateServiceTokenV3 +} from "@app/hooks/api"; +import { ServiceTokenV3TrustedIp } from "@app/hooks/api/serviceTokens/types" +import { UsePopUpState } from "@app/hooks/usePopUp"; + +type Props = { + handlePopUpOpen: ( + popUpName: keyof UsePopUpState<["deleteServiceTokenV3", "serviceTokenV3"]>, + data?: { + serviceTokenDataId?: string; + name?: string; + role?: string; + customRole?: { + name: string; + slug: string; + }; + trustedIps?: ServiceTokenV3TrustedIp[]; + accessTokenTTL?: number; + isRefreshTokenRotationEnabled?: boolean; + } + ) => void; + }; + +export const ServiceTokenV3Table = ({ + handlePopUpOpen +}: Props) => { + const { createNotification } = useNotificationContext(); + const { currentWorkspace } = useWorkspace(); + const { data, isLoading } = useGetWorkspaceServiceTokenDataV3(currentWorkspace?.id || ""); + const { mutateAsync: updateMutateAsync } = useUpdateServiceTokenV3(); + + const handleToggleServiceTokenDataStatus = async ({ + serviceTokenDataId, + isActive + }: { + serviceTokenDataId: string; + isActive: boolean; + }) => { + try { + await updateMutateAsync({ + serviceTokenDataId, + isActive + }); + + createNotification({ + text: `Successfully ${isActive ? "enabled" : "disabled"} service token v3`, + type: "success" + }); + } catch (err) { + console.log(err); + createNotification({ + text: `Failed to ${isActive ? "enable" : "disable"} service token v3`, + type: "error" + }); + } + } + + return ( + + + + + + + + + + + + + + + {isLoading && } + {!isLoading && + data && + data.length > 0 && + data.map(({ + id, + name, + isActive, + role, + customRole, + trustedIps, + createdAt, + expiresAt, + accessTokenTTL, + isRefreshTokenRotationEnabled + }) => { + return ( + + + + + + + + + + + ); + })} + {!isLoading && data && data?.length === 0 && ( + + + + )} + +
NameStatusRoleTrusted IPsAccess Token TTLCreated AtValid Until +
{name} + + {(isAllowed) => ( + handleToggleServiceTokenDataStatus({ + serviceTokenDataId: id, + isActive: value + })} + isChecked={isActive} + isDisabled={!isAllowed} + > +

{isActive ? "Active" : "Inactive"}

+
+ )} +
+
{customRole?.slug ?? role} + {trustedIps.map(({ + id: trustedIpId, + ipAddress, + prefix + }) => { + return ( +

+ {`${ipAddress}${prefix !== undefined ? `/${prefix}` : ""}`} +

+ ); + })} +
{accessTokenTTL}{format(new Date(createdAt), "yyyy-MM-dd")}{expiresAt ? format(new Date(expiresAt), "yyyy-MM-dd") : "-"} + + {(isAllowed) => ( + { + handlePopUpOpen("serviceTokenV3", { + serviceTokenDataId: id, + name, + role, + customRole, + trustedIps, + accessTokenTTL, + isRefreshTokenRotationEnabled + }); + }} + size="lg" + colorSchema="primary" + variant="plain" + ariaLabel="update" + isDisabled={!isAllowed} + > + + + )} + + + {(isAllowed) => ( + { + handlePopUpOpen("deleteServiceTokenV3", { + serviceTokenDataId: id, + name + }); + }} + size="lg" + colorSchema="danger" + variant="plain" + ariaLabel="update" + className="ml-4" + isDisabled={!isAllowed} + > + + + )} + +
+ +
+
+ ); +} \ No newline at end of file diff --git a/frontend/src/views/SecretApprovalPage/SecretApprovalPage.tsx b/frontend/src/views/SecretApprovalPage/SecretApprovalPage.tsx index eee81608c..5a9649897 100644 --- a/frontend/src/views/SecretApprovalPage/SecretApprovalPage.tsx +++ b/frontend/src/views/SecretApprovalPage/SecretApprovalPage.tsx @@ -15,7 +15,7 @@ enum TabSection { export const SecretApprovalPage = () => { const { currentWorkspace } = useWorkspace(); - const workspaceId = currentWorkspace?._id || ""; + const workspaceId = currentWorkspace?.id || ""; return (
diff --git a/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx b/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx index 0eb0a849d..2ea6a67f8 100644 --- a/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx +++ b/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx @@ -59,7 +59,7 @@ export const SecretApprovalPolicyList = ({ workspaceId }: Props) => { const { mutateAsync: deleteSecretApprovalPolicy } = useDeleteSecretApprovalPolicy(); const handleDeletePolicy = async () => { - const { _id: id } = popUp.deletePolicy.data as TSecretApprovalPolicy; + const { id: id } = popUp.deletePolicy.data as TSecretApprovalPolicy; try { await deleteSecretApprovalPolicy({ workspaceId, @@ -138,7 +138,7 @@ export const SecretApprovalPolicyList = ({ workspaceId }: Props) => { handlePopUpOpen("secretPolicyForm", policy)} onDelete={() => handlePopUpOpen("deletePolicy", policy)} diff --git a/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx b/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx index d921f9975..99d06c9c1 100644 --- a/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx +++ b/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx @@ -54,7 +54,7 @@ export const SecretApprovalRequestChangeItem = ({ // meaning request has changed const isStale = (secretVersion?.version || 1) < presentSecretVersionNumber; const itemConflict = - hasMerged && conflicts.find((el) => el.op === op && el.secretId === newVersion?._id); + hasMerged && conflicts.find((el) => el.op === op && el.secretId === newVersion?.id); const hasConflict = Boolean(itemConflict); return ( @@ -97,10 +97,10 @@ export const SecretApprovalRequestChangeItem = ({ {secretVersion?.comment} - {secretVersion?.tags?.map(({ name, _id: tagId, tagColor }) => ( + {secretVersion?.tags?.map(({ name, id: tagId, tagColor }) => (
{newVersion?.secretComment} - {newVersion?.tags?.map(({ name, _id: tagId, tagColor }) => ( + {newVersion?.tags?.map(({ name, id: tagId, tagColor }) => (
{(op === CommitType.CREATE ? newVersion?.tags : secretVersion?.tags)?.map( - ({ name, _id: tagId, tagColor }) => ( + ({ name, id: tagId, tagColor }) => (
{ // env slug const environment = router.query.env as string; - const workspaceId = currentWorkspace?._id || ""; + const workspaceId = currentWorkspace?.id || ""; const secretPath = (router.query.secretPath as string) || "/"; const canReadSecret = permission.can( ProjectPermissionActions.Read, diff --git a/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx b/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx index be511486d..e530ea68f 100644 --- a/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx +++ b/frontend/src/views/SecretMainPage/components/ActionBar/ActionBar.tsx @@ -163,7 +163,7 @@ export const ActionBar = ({ }; const handleSecretBulkDelete = async () => { - const bulkDeletedSecrets = secrets.filter(({ _id }) => Boolean(selectedSecrets?.[_id])); + const bulkDeletedSecrets = secrets.filter(({ id }) => Boolean(selectedSecrets?.[id])); try { await deleteBatchSecretV3({ secretPath, @@ -233,14 +233,14 @@ export const ActionBar = ({ Apply tags to filter secrets - {tags.map(({ _id, name, tagColor }) => ( + {tags.map(({ id, name, tagColor }) => ( { evt.preventDefault(); - onToggleTagFilter(_id); + onToggleTagFilter(id); }} - key={_id} - icon={filter?.tags[_id] && } + key={id} + icon={filter?.tags[id] && } iconPos="right" >
diff --git a/frontend/src/views/SecretMainPage/components/PitDrawer/PitDrawer.tsx b/frontend/src/views/SecretMainPage/components/PitDrawer/PitDrawer.tsx index 73a0028b9..9b844887a 100644 --- a/frontend/src/views/SecretMainPage/components/PitDrawer/PitDrawer.tsx +++ b/frontend/src/views/SecretMainPage/components/PitDrawer/PitDrawer.tsx @@ -41,26 +41,26 @@ export const PitDrawer = ({
{secretSnaphots?.pages?.map((group, i) => ( - {group.map(({ _id, createdAt }, index) => ( + {group.map(({ id, createdAt }, index) => ( ))} diff --git a/frontend/src/views/SecretMainPage/components/SecretDropzone/CopySecretsFromBoard.tsx b/frontend/src/views/SecretMainPage/components/SecretDropzone/CopySecretsFromBoard.tsx index 12eaf840c..9606f8141 100644 --- a/frontend/src/views/SecretMainPage/components/SecretDropzone/CopySecretsFromBoard.tsx +++ b/frontend/src/views/SecretMainPage/components/SecretDropzone/CopySecretsFromBoard.tsx @@ -240,14 +240,14 @@ export const CopySecretsFromBoard = ({ {secrets ?.filter(({ key }) => key.toLowerCase().includes(searchFilter.toLowerCase())) - ?.map(({ _id, key, value: secVal }) => ( + ?.map(({ id, key, value: secVal }) => ( ( onChange(isChecked ? secVal : "")} > diff --git a/frontend/src/views/SecretMainPage/components/SecretImportListView/SecretImportListView.tsx b/frontend/src/views/SecretMainPage/components/SecretImportListView/SecretImportListView.tsx index 3b8f91235..6b216b8f8 100644 --- a/frontend/src/views/SecretMainPage/components/SecretImportListView/SecretImportListView.tsx +++ b/frontend/src/views/SecretMainPage/components/SecretImportListView/SecretImportListView.tsx @@ -132,12 +132,12 @@ export const SecretImportListView = ({ const { environment: importEnv, secretPath: impSecPath } = popUp.deleteSecretImport ?.data as TDeleteSecretImport; try { - if (secretImports?._id) { + if (secretImports?.id) { await deleteSecretImport({ workspaceId, environment, directory: secretPath, - id: secretImports?._id, + id: secretImports?.id, secretImportEnv: importEnv, secretImportPath: impSecPath }); @@ -166,7 +166,7 @@ export const SecretImportListView = ({ workspaceId, environment, directory: secretPath, - id: secretImports?._id || "", + id: secretImports?.id || "", secretImports: newImportOrder }); } diff --git a/frontend/src/views/SecretMainPage/components/SecretListView/SecretDetaiSidebar.tsx b/frontend/src/views/SecretMainPage/components/SecretListView/SecretDetaiSidebar.tsx index 0a9f38bc4..1c8063f43 100644 --- a/frontend/src/views/SecretMainPage/components/SecretListView/SecretDetaiSidebar.tsx +++ b/frontend/src/views/SecretMainPage/components/SecretListView/SecretDetaiSidebar.tsx @@ -49,7 +49,7 @@ type Props = { onDeleteSecret: () => void; onSaveSecret: ( orgSec: DecryptedSecret, - modSec: Omit & { tags: { _id: string }[] }, + modSec: Omit & { tags: { id: string }[] }, cb?: () => void ) => Promise; tags: WsTag[]; @@ -98,7 +98,7 @@ export const SecretDetailSidebar = ({ }); const selectedTags = watch("tags", []); const selectedTagsGroupById = selectedTags.reduce>( - (prev, curr) => ({ ...prev, [curr._id]: true }), + (prev, curr) => ({ ...prev, [curr.id]: true }), {} ); @@ -109,7 +109,7 @@ export const SecretDetailSidebar = ({ const { data: secretVersion } = useGetSecretVersion({ limit: 10, offset: 0, - secretId: secret?._id, + secretId: secret?.id, decryptFileKey }); @@ -133,8 +133,8 @@ export const SecretDetailSidebar = ({ }; const handleTagSelect = (tag: WsTag) => { - if (selectedTagsGroupById?.[tag._id]) { - const tagPos = selectedTags.findIndex(({ _id }) => _id === tag._id); + if (selectedTagsGroupById?.[tag.id]) { + const tagPos = selectedTags.findIndex(({ id }) => id === tag.id); if (tagPos !== -1) { remove(tagPos); } @@ -227,7 +227,7 @@ export const SecretDetailSidebar = ({ )}
- {fields.map(({ tagColor, id: formId, name, _id }) => ( + {fields.map(({ tagColor, id: formId, name, id }) => ( id === _id); + const tag = tags?.find(({ id: id }) => id === id); if (tag) handleTagSelect(tag); }} > @@ -269,7 +269,7 @@ export const SecretDetailSidebar = ({ Apply tags to this secrets {tags.map((tag) => { - const { _id: tagId, name, tagColor } = tag; + const { id: tagId, name, tagColor } = tag; const isSelected = selectedTagsGroupById?.[tagId]; return ( diff --git a/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx b/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx index 9fdd1e3f8..1050923b3 100644 --- a/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx +++ b/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx @@ -56,7 +56,7 @@ type Props = { secret: DecryptedSecret; onSaveSecret: ( orgSec: DecryptedSecret, - modSec: Omit & { tags: { _id: string }[] }, + modSec: Omit & { tags: { id: string }[] }, cb?: () => void ) => Promise; onDeleteSecret: (sec: DecryptedSecret) => void; @@ -117,7 +117,7 @@ export const SecretItem = memo( const selectedTags = watch("tags", []); const selectedTagsGroupById = selectedTags.reduce>( - (prev, curr) => ({ ...prev, [curr._id]: true }), + (prev, curr) => ({ ...prev, [curr.id]: true }), {} ); const { fields, append, remove } = useFieldArray({ @@ -168,8 +168,8 @@ export const SecretItem = memo( }; const handleTagSelect = (tag: WsTag) => { - if (selectedTagsGroupById?.[tag._id]) { - const tagPos = selectedTags.findIndex(({ _id }) => _id === tag._id); + if (selectedTagsGroupById?.[tag.id]) { + const tagPos = selectedTags.findIndex(({ id }) => id === tag.id); if (tagPos !== -1) { remove(tagPos); } @@ -217,9 +217,9 @@ export const SecretItem = memo( )} > onToggleSecretSelect(secret._id)} + onCheckedChange={() => onToggleSecretSelect(secret.id)} className={twMerge("ml-3 hidden group-hover:flex", isSelected && "flex")} /> Apply tags to this secrets {tags.map((tag) => { - const { _id: tagId, name, tagColor } = tag; + const { id: tagId, name, tagColor } = tag; const isTagSelected = selectedTagsGroupById?.[tagId]; return ( diff --git a/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.utils.ts b/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.utils.ts index 6dcf6110a..fc8a745d5 100644 --- a/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.utils.ts +++ b/frontend/src/views/SecretMainPage/components/SecretListView/SecretListView.utils.ts @@ -31,7 +31,7 @@ export const formSchema = z.object({ tags: z .object({ - _id: z.string(), + id: z.string(), name: z.string(), slug: z.string(), tagColor: z.string().optional() diff --git a/frontend/src/views/SecretMainPage/components/SnapshotView/SecretItem.tsx b/frontend/src/views/SecretMainPage/components/SnapshotView/SecretItem.tsx index 8b661415e..2b0110ee7 100644 --- a/frontend/src/views/SecretMainPage/components/SnapshotView/SecretItem.tsx +++ b/frontend/src/views/SecretMainPage/components/SnapshotView/SecretItem.tsx @@ -151,10 +151,10 @@ export const SecretItem = ({ mode, preSecret, postSecret }: Props) => { Tags {isModified && ( - {preSecret?.tags?.map(({ name, _id: tagId, tagColor }) => ( + {preSecret?.tags?.map(({ name, id: tagId, tagColor }) => (
{ )} - {postSecret?.tags?.map(({ name, _id: tagId, tagColor }) => ( + {postSecret?.tags?.map(({ name, id: tagId, tagColor }) => (
{ const secretGroupById = secrets.reduce>( - (prev, curr) => ({ ...prev, [curr._id]: curr }), + (prev, curr) => ({ ...prev, [curr.id]: curr }), {} ); const diffView: Array> = []; rollingSecrets.forEach((rollSecret) => { - const { _id: id } = rollSecret; + const { id: id } = rollSecret; const doesExist = Boolean(secretGroupById?.[id]); if (doesExist) { diffView.push({ diff --git a/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx b/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx index f63350ca7..99c167890 100644 --- a/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx +++ b/frontend/src/views/SecretOverviewPage/SecretOverviewPage.tsx @@ -74,14 +74,14 @@ export const SecretOverviewPage = () => { const { currentWorkspace, isLoading: isWorkspaceLoading } = useWorkspace(); const { currentOrg } = useOrganization(); - const workspaceId = currentWorkspace?._id as string; + const workspaceId = currentWorkspace?.id as string; const { data: latestFileKey } = useGetUserWsKey(workspaceId); const [searchFilter, setSearchFilter] = useState(""); const secretPath = (router.query?.secretPath as string) || "/"; useEffect(() => { if (!isWorkspaceLoading && !workspaceId && router.isReady) { - router.push(`/org/${currentOrg?._id}/overview`); + router.push(`/org/${currentOrg?.id}/overview`); } }, [isWorkspaceLoading, workspaceId, router.isReady]); diff --git a/frontend/src/views/SecretOverviewPage/components/ProjectIndexSecretsSection/ProjectIndexSecretsSection.tsx b/frontend/src/views/SecretOverviewPage/components/ProjectIndexSecretsSection/ProjectIndexSecretsSection.tsx index af2edb0ce..bdb63e021 100644 --- a/frontend/src/views/SecretOverviewPage/components/ProjectIndexSecretsSection/ProjectIndexSecretsSection.tsx +++ b/frontend/src/views/SecretOverviewPage/components/ProjectIndexSecretsSection/ProjectIndexSecretsSection.tsx @@ -19,16 +19,16 @@ type Props = { export const ProjectIndexSecretsSection = ({ decryptFileKey }: Props) => { const { currentWorkspace } = useWorkspace(); const { data: isBlindIndexed, isLoading: isBlindIndexedLoading } = useGetWorkspaceIndexStatus( - currentWorkspace?._id ?? "" + currentWorkspace?.id ?? "" ); const [isIndexing, setIsIndexing] = useToggle(); const nameWorkspaceSecrets = useNameWorkspaceSecrets(); const onEnableBlindIndices = async () => { - if (!currentWorkspace?._id) return; + if (!currentWorkspace?.id) return; setIsIndexing.on(); try { - const encryptedSecrets = await fetchWorkspaceSecrets(currentWorkspace._id); + const encryptedSecrets = await fetchWorkspaceSecrets(currentWorkspace.id); const key = decryptAssymmetric({ ciphertext: decryptFileKey.encryptedKey, @@ -47,11 +47,11 @@ export const ProjectIndexSecretsSection = ({ decryptFileKey }: Props) => { return { secretName, - _id: encryptedSecret._id + id: encryptedSecret.id }; }); await nameWorkspaceSecrets.mutateAsync({ - workspaceId: currentWorkspace._id, + workspaceId: currentWorkspace.id, secretsToUpdate }); } catch (err) { diff --git a/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretOverviewTableRow.tsx b/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretOverviewTableRow.tsx index 8671d2da9..08774535b 100644 --- a/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretOverviewTableRow.tsx +++ b/frontend/src/views/SecretOverviewPage/components/SecretOverviewTableRow/SecretOverviewTableRow.tsx @@ -149,7 +149,7 @@ export const SecretOverviewTableRow = ({ isVisible={isSecretVisible} secretName={secretKey} defaultValue={secret?.value} - secretId={secret?._id} + secretId={secret?.id} isCreatable={isCreatable} onSecretDelete={onSecretDelete} onSecretCreate={onSecretCreate} diff --git a/frontend/src/views/SecretRotationPage/SecretRotationPage.tsx b/frontend/src/views/SecretRotationPage/SecretRotationPage.tsx index 3a502a35d..cdce4f0b1 100644 --- a/frontend/src/views/SecretRotationPage/SecretRotationPage.tsx +++ b/frontend/src/views/SecretRotationPage/SecretRotationPage.tsx @@ -70,7 +70,7 @@ export const SecretRotationPage = withProjectPermission( "deleteRotation", "upgradePlan" ] as const); - const workspaceId = currentWorkspace?._id || ""; + const workspaceId = currentWorkspace?.id || ""; const canCreateRotation = permission.can( ProjectPermissionActions.Create, ProjectPermissionSub.SecretRotation @@ -145,11 +145,11 @@ export const SecretRotationPage = withProjectPermission( const handleUserAcceptBotCondition = async () => { const provider = popUp.activeBot?.data as TSecretRotationProvider; try { - if (bot?._id) { + if (bot?.id) { const botKey = generateBotKey(bot.publicKey, userWsKey!); await updateBotActiveStatus({ isActive: true, - botId: bot._id, + botId: bot.id, workspaceId, botKey }); @@ -232,16 +232,16 @@ export const SecretRotationPage = withProjectPermission( secretPath, outputs, provider, - _id, + id, lastRotatedAt, status, statusMessage }) => { - const isDeleting = deleteSecretRotationVars?.id === _id && isDeletingRotation; + const isDeleting = deleteSecretRotationVars?.id === id && isDeletingRotation; const isRestarting = - restartSecretRotationVar?.id === _id && isRestartingRotation; + restartSecretRotationVar?.id === id && isRestartingRotation; return ( - + {outputs .map(({ key }) => key) @@ -291,7 +291,7 @@ export const SecretRotationPage = withProjectPermission( colorSchema="danger" ariaLabel="delete-rotation" isDisabled={isDeleting || !isAllowed} - onClick={() => handleRestartRotation(_id)} + onClick={() => handleRestartRotation(id)} > {isRestarting ? ( @@ -313,7 +313,7 @@ export const SecretRotationPage = withProjectPermission( colorSchema="danger" ariaLabel="delete-rotation" isDisabled={isDeleting || !isAllowed} - onClick={() => handlePopUpOpen("deleteRotation", { id: _id })} + onClick={() => handlePopUpOpen("deleteRotation", { id: id })} > {isDeleting ? ( diff --git a/frontend/src/views/SecretRotationPage/components/CreateRotationForm/steps/RotationOutputForm.tsx b/frontend/src/views/SecretRotationPage/components/CreateRotationForm/steps/RotationOutputForm.tsx index e11038f7c..e41bac258 100644 --- a/frontend/src/views/SecretRotationPage/components/CreateRotationForm/steps/RotationOutputForm.tsx +++ b/frontend/src/views/SecretRotationPage/components/CreateRotationForm/steps/RotationOutputForm.tsx @@ -23,7 +23,7 @@ type Props = { export const RotationOutputForm = ({ onSubmit, onCancel, outputSchema = {} }: Props) => { const { currentWorkspace } = useWorkspace(); const environments = currentWorkspace?.environments || []; - const workspaceId = currentWorkspace?._id || ""; + const workspaceId = currentWorkspace?.id || ""; const { control, handleSubmit, @@ -117,11 +117,11 @@ export const RotationOutputForm = ({ onSubmit, onCancel, outputSchema = {} }: Pr {!isSecretsLoading && secrets ?.filter( - ({ _id }) => - value === _id || !Object.values(selectedSecrets || {}).includes(_id) + ({ id }) => + value === id || !Object.values(selectedSecrets || {}).includes(id) ) - ?.map(({ key, _id }) => ( - + ?.map(({ key, id }) => ( + {key} ))} diff --git a/frontend/src/views/SecretScanning/components/SecretScanningLogsTable.tsx b/frontend/src/views/SecretScanning/components/SecretScanningLogsTable.tsx index 4add11835..ad60f9a7f 100644 --- a/frontend/src/views/SecretScanning/components/SecretScanningLogsTable.tsx +++ b/frontend/src/views/SecretScanning/components/SecretScanningLogsTable.tsx @@ -83,7 +83,7 @@ export const SecretScanningLogsTable = () => { {risk.isResolved ? "Resolved" : "Needs Attention"} - + ); diff --git a/frontend/src/views/Settings/BillingSettingsPage/components/BillingCloudTab/CurrentPlanSection.tsx b/frontend/src/views/Settings/BillingSettingsPage/components/BillingCloudTab/CurrentPlanSection.tsx index 75fdf2f99..a3135d85f 100644 --- a/frontend/src/views/Settings/BillingSettingsPage/components/BillingCloudTab/CurrentPlanSection.tsx +++ b/frontend/src/views/Settings/BillingSettingsPage/components/BillingCloudTab/CurrentPlanSection.tsx @@ -17,7 +17,7 @@ import { useGetOrgPlanTable } from "@app/hooks/api"; export const CurrentPlanSection = () => { const { currentOrg } = useOrganization(); - const { data, isLoading } = useGetOrgPlanTable(currentOrg?._id ?? ""); + const { data, isLoading } = useGetOrgPlanTable(currentOrg?.id ?? ""); const displayCell = (value: null | number | string | boolean) => { if (value === null) return "-"; diff --git a/frontend/src/views/Settings/BillingSettingsPage/components/BillingCloudTab/ManagePlansTable.tsx b/frontend/src/views/Settings/BillingSettingsPage/components/BillingCloudTab/ManagePlansTable.tsx index f057f7ff0..2aa552f52 100644 --- a/frontend/src/views/Settings/BillingSettingsPage/components/BillingCloudTab/ManagePlansTable.tsx +++ b/frontend/src/views/Settings/BillingSettingsPage/components/BillingCloudTab/ManagePlansTable.tsx @@ -24,7 +24,7 @@ export const ManagePlansTable = ({ billingCycle }: Props) => { const { currentOrg } = useOrganization(); const { subscription } = useSubscription(); const { data: tableData, isLoading: isTableDataLoading } = useGetOrgPlansTable({ - organizationId: currentOrg?._id ?? "", + organizationId: currentOrg?.id ?? "", billingCycle }); const createCustomerPortalSession = useCreateCustomerPortalSession(); @@ -110,11 +110,11 @@ export const ManagePlansTable = ({ billingCycle }: Props) => {
diff --git a/frontend/src/components/dashboard/AddTagsMenu.tsx b/frontend/src/components/dashboard/AddTagsMenu.tsx index dfa902b87..3a54f77ab 100644 --- a/frontend/src/components/dashboard/AddTagsMenu.tsx +++ b/frontend/src/components/dashboard/AddTagsMenu.tsx @@ -13,17 +13,27 @@ import { Tag } from "public/data/frequentInterfaces"; * @param {function} obj.modifyTags - modify tags for a certain secret * @param {Tag[]} obj.position - currently selected tags for a certain secret */ -const AddTagsMenu = ({ allTags, currentTags, modifyTags, id }: { allTags: Tag[]; currentTags: Tag[]; modifyTags: (value: Tag[], id: string) => void; id: string; }) => { +const AddTagsMenu = ({ + allTags, + currentTags, + modifyTags, + id +}: { + allTags: Tag[]; + currentTags: Tag[]; + modifyTags: (value: Tag[], id: string) => void; + id: string; +}) => { const router = useRouter(); return ( - + -
- - {currentTags?.length > 2 && {currentTags.length - 2}} +
+ + {currentTags?.length > 2 && {currentTags.length - 2}}
- - {allTags?.map((tag) => { return ( - - - - )})} + + {allTags?.map((tag) => { + return ( + + + + ); + })} diff --git a/frontend/src/components/dashboard/KeyPair.tsx b/frontend/src/components/dashboard/KeyPair.tsx index b46c6c07c..d9d0360ae 100644 --- a/frontend/src/components/dashboard/KeyPair.tsx +++ b/frontend/src/components/dashboard/KeyPair.tsx @@ -38,8 +38,7 @@ const colors = [ "bg-[#6F1AB6]/40", "bg-[#C40B13]/40", "bg-[#332FD0]/40" -] - +]; const colorsText = [ "text-[#fcf0c3]/70", @@ -50,7 +49,7 @@ const colorsText = [ "text-[#FFE5F1]/70", "text-[#FFDEDE]/70", "text-[#DFF6FF]/70" -] +]; /** * This component represent a single row for an environemnt variable on the dashboard @@ -83,117 +82,160 @@ const KeyPair = ({ toggleSidebar, sidebarSecretId, isCapitalized, - isSnapshot, + isSnapshot, deleteRow, togglePITSidebar, tags }: KeyPairProps) => { - const tagData = (tags.map((tag, index) => {return { - ...tag, - color: colors[index%colors.length], - colorText: colorsText[index%colorsText.length] - }})); + const tagData = tags.map((tag, index) => { + return { + ...tag, + color: colors[index % colors.length], + colorText: colorsText[index % colorsText.length] + }; + }); return ( -
-
-
-
{keyPair.pos + 1}
-
- +
+
+
+ {keyPair.pos + 1} +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ {keyPair.tags?.map( + (tag, index) => + index < 2 && ( +
tagDp.id === tag.id)[0]?.color + } rounded-sm text-sm ${ + tagData.filter((tagDp) => tagDp.id === tag.id)[0]?.colorText + } flex items-center`} + > + {tag.name} + + modifyTags( + keyPair.tags.filter((ttag) => ttag.id !== tag.id), + keyPair.id + ) + } + /> +
+ ) + )} + +
-
-
-
- -
-
-
-
- -
-
-
-
- {keyPair.tags?.map((tag, index) => ( - index < 2 &&
tagDp.id === tag.id)[0]?.color} rounded-sm text-sm ${tagData.filter(tagDp => tagDp.id === tag.id)[0]?.colorText} flex items-center`}> - {tag.name} - modifyTags(keyPair.tags.filter(ttag => ttag.id !== tag.id), keyPair.id)}/> -
- ))} - - -
-
-
null} - role="button" - tabIndex={0} - onClick={() => { - if (togglePITSidebar) { - togglePITSidebar(false); - } - toggleSidebar(keyPair.id) - }} - className={`cursor-pointer w-[1.5rem] h-[2.35rem] ml-auto group-hover:bg-mineshaft-700 z-50 rounded-md invisible group-hover:visible flex flex-row justify-center items-center ${isSnapshot ?? "invisible"}`} - > - -
-
- {keyPair.key || keyPair.value - ? { if (deleteRow) { - deleteRow({ ids: [keyPair.id], secretName: keyPair?.key }) - }}} - isPlain - /> - :
null} role="button" tabIndex={0} - onClick={() => { if (deleteRow) { - deleteRow({ ids: [keyPair.id], secretName: keyPair?.key }) - }}} - className="invisible group-hover:visible" + onClick={() => { + if (togglePITSidebar) { + togglePITSidebar(false); + } + toggleSidebar(keyPair.id); + }} + className={`invisible z-50 ml-auto flex h-[2.35rem] w-[1.5rem] cursor-pointer flex-row items-center justify-center rounded-md group-hover:visible group-hover:bg-mineshaft-700 ${ + isSnapshot ?? "invisible" + }`} > - + +
+
+ {keyPair.key || keyPair.value ? ( + { + if (deleteRow) { + deleteRow({ ids: [keyPair.id], secretName: keyPair?.key }); + } + }} + isPlain + /> + ) : ( +
+
null} + role="button" + tabIndex={0} + onClick={() => { + if (deleteRow) { + deleteRow({ ids: [keyPair.id], secretName: keyPair?.key }); + } + }} + className="invisible group-hover:visible" + > + +
+
+ )}
-
}
-
-)}; + ); +}; export default KeyPair; diff --git a/frontend/src/components/navigation/NavHeader.tsx b/frontend/src/components/navigation/NavHeader.tsx index b8ebee59c..2bf596915 100644 --- a/frontend/src/components/navigation/NavHeader.tsx +++ b/frontend/src/components/navigation/NavHeader.tsx @@ -157,7 +157,7 @@ export default function NavHeader({ })} {isProtectedBranch && ( - + )}
diff --git a/frontend/src/components/tags/CreateTagModal/CreateTagModal.tsx b/frontend/src/components/tags/CreateTagModal/CreateTagModal.tsx index 8f9fd4ccc..cfe685ae2 100644 --- a/frontend/src/components/tags/CreateTagModal/CreateTagModal.tsx +++ b/frontend/src/components/tags/CreateTagModal/CreateTagModal.tsx @@ -119,9 +119,9 @@ export const CreateTagModal = ({ isOpen, onToggle }: Props): JSX.Element => { const [showHexInput, setShowHexInput] = useState(false); const selectedTagColor = watch("color", secretTagsColors[0].hex); - useEffect(()=>{ - if(!isOpen) reset(); - },[isOpen]) + useEffect(() => { + if (!isOpen) reset(); + }, [isOpen]); const onFormSubmit = async ({ name, color }: FormData) => { try { @@ -168,21 +168,21 @@ export const CreateTagModal = ({ isOpen, onToggle }: Props): JSX.Element => { Tag Color
-
+
-
+
{!showHexInput ? ( -
+
{secretTagsColors.map(($tagColor: TagColor) => { return (
setValue("color", $tagColor.hex)} @@ -200,18 +200,18 @@ export const CreateTagModal = ({ isOpen, onToggle }: Props): JSX.Element => { })}
) : ( -
-
+
+
{isValidHexColor(selectedTagColor) && (
)} {!isValidHexColor(selectedTagColor) && ( -
+
)}
@@ -225,10 +225,10 @@ export const CreateTagModal = ({ isOpen, onToggle }: Props): JSX.Element => {
)} -
-
+
+
setShowHexInput((prev) => !prev)} diff --git a/frontend/src/components/utilities/config/index.ts b/frontend/src/components/utilities/config/index.ts index 8804765a3..10d4856c0 100644 --- a/frontend/src/components/utilities/config/index.ts +++ b/frontend/src/components/utilities/config/index.ts @@ -1,12 +1,6 @@ const ENV = process.env.NEXT_PUBLIC_ENV! || "development"; // investigate const POSTHOG_API_KEY = process.env.NEXT_PUBLIC_POSTHOG_API_KEY!; -const POSTHOG_HOST = - process.env.NEXT_PUBLIC_POSTHOG_HOST! || "https://app.posthog.com"; +const POSTHOG_HOST = process.env.NEXT_PUBLIC_POSTHOG_HOST! || "https://app.posthog.com"; const INTERCOMid = process.env.NEXT_PUBLIC_INTERCOMid!; -export { - ENV, - INTERCOMid, - POSTHOG_API_KEY, - POSTHOG_HOST -}; \ No newline at end of file +export { ENV, INTERCOMid, POSTHOG_API_KEY, POSTHOG_HOST }; diff --git a/frontend/src/components/utilities/intercom/intercom.ts b/frontend/src/components/utilities/intercom/intercom.ts index fb531c4a4..56b374107 100644 --- a/frontend/src/components/utilities/intercom/intercom.ts +++ b/frontend/src/components/utilities/intercom/intercom.ts @@ -54,11 +54,9 @@ export const load = () => { // Initializes Intercom export const boot = (options = {}) => { - window && - window.Intercom && - window.Intercom("boot", { appid: APPid, ...options }); + window && window.Intercom && window.Intercom("boot", { appid: APPid, ...options }); }; export const update = () => { window && window.Intercom && window.Intercom("update"); -}; \ No newline at end of file +}; diff --git a/frontend/src/context/OrgPermissionContext/OrgPermissionContext.tsx b/frontend/src/context/OrgPermissionContext/OrgPermissionContext.tsx index 932e33e9b..1f3cd1de4 100644 --- a/frontend/src/context/OrgPermissionContext/OrgPermissionContext.tsx +++ b/frontend/src/context/OrgPermissionContext/OrgPermissionContext.tsx @@ -22,7 +22,7 @@ export const OrgPermissionProvider = ({ children }: Props): JSX.Element => { if (isLoading) { return ( -
+
{ if (!permission) { return ( -
+
Failed to load user permissions
); diff --git a/frontend/src/context/OrganizationContext/OrganizationContext.tsx b/frontend/src/context/OrganizationContext/OrganizationContext.tsx index 93c82b923..a4562ef82 100644 --- a/frontend/src/context/OrganizationContext/OrganizationContext.tsx +++ b/frontend/src/context/OrganizationContext/OrganizationContext.tsx @@ -3,7 +3,6 @@ import { createContext, ReactNode, useContext, useMemo } from "react"; import { useGetOrganizations } from "@app/hooks/api"; import { Organization } from "@app/hooks/api/types"; - type TOrgContext = { orgs?: Organization[]; currentOrg?: Organization; @@ -18,7 +17,7 @@ type Props = { export const OrgProvider = ({ children }: Props): JSX.Element => { const { data: userOrgs, isLoading } = useGetOrganizations(); - + // const currentWsOrgID = currentWorkspace?.organization; const currentWsOrgID = localStorage.getItem("orgData.id"); diff --git a/frontend/src/context/ProjectPermissionContext/ProjectPermissionContext.tsx b/frontend/src/context/ProjectPermissionContext/ProjectPermissionContext.tsx index 3b7a8af2f..b596cda5b 100644 --- a/frontend/src/context/ProjectPermissionContext/ProjectPermissionContext.tsx +++ b/frontend/src/context/ProjectPermissionContext/ProjectPermissionContext.tsx @@ -18,7 +18,7 @@ export const ProjectPermissionProvider = ({ children }: Props): JSX.Element => { if ((isLoading && currentWorkspace) || isWsLoading) { return ( -
+
{ if (!permission && currentWorkspace) { return ( -
+
Failed to load user permissions
); diff --git a/frontend/src/context/ServerConfigContext/ServerConfigContext.tsx b/frontend/src/context/ServerConfigContext/ServerConfigContext.tsx index aab7e4c56..291765e3b 100644 --- a/frontend/src/context/ServerConfigContext/ServerConfigContext.tsx +++ b/frontend/src/context/ServerConfigContext/ServerConfigContext.tsx @@ -72,9 +72,9 @@ export const ServerConfigProvider = ({ children }: Props): JSX.Element => { export const useServerConfig = () => { const ctx = useContext(ServerConfigContext); - // if (!ctx) { - // throw new Error("useServerConfig has to be used within "); - // } + if (!ctx) { + throw new Error("useServerConfig has to be used within "); + } - return ctx || { config: { allowSignUp: true } }; + return ctx; }; diff --git a/frontend/src/context/UserContext/UserContext.tsx b/frontend/src/context/UserContext/UserContext.tsx index 5dbe3e0e7..433fc3959 100644 --- a/frontend/src/context/UserContext/UserContext.tsx +++ b/frontend/src/context/UserContext/UserContext.tsx @@ -1,10 +1,10 @@ import { createContext, ReactNode, useContext, useMemo } from "react"; import { useGetUser } from "@app/hooks/api"; -import { User } from "@app/hooks/api/types"; +import { User, UserEnc } from "@app/hooks/api/types"; type TUserContext = { - user: User; + user: User & UserEnc; isLoading: boolean; }; diff --git a/frontend/src/context/WorkspaceContext/WorkspaceContext.tsx b/frontend/src/context/WorkspaceContext/WorkspaceContext.tsx index 1e0a01c7e..4cf8c585f 100644 --- a/frontend/src/context/WorkspaceContext/WorkspaceContext.tsx +++ b/frontend/src/context/WorkspaceContext/WorkspaceContext.tsx @@ -26,7 +26,7 @@ export const WorkspaceProvider = ({ children }: Props): JSX.Element => { const wsId = workspaceId || localStorage.getItem("projectData.id"); return { workspaces: ws || [], - currentWorkspace: (ws || []).find(({ id: id }) => id === wsId), + currentWorkspace: (ws || []).find(({ id }) => id === wsId), isLoading }; }, [ws, workspaceId, isLoading]); diff --git a/frontend/src/helpers/project.ts b/frontend/src/helpers/project.ts index 13352c586..21f73e4c6 100644 --- a/frontend/src/helpers/project.ts +++ b/frontend/src/helpers/project.ts @@ -112,8 +112,8 @@ const initProjectHelper = async ({ }); await uploadWsKey({ - workspaceId: workspace._id, - userId: user._id, + workspaceId: workspace.id, + userId: user.id, encryptedKey: ciphertext, nonce }); @@ -121,13 +121,13 @@ const initProjectHelper = async ({ // encrypt and upload secrets to new project const secrets = await encryptSecrets({ secretsToEncrypt: secretsToBeAdded, - workspaceId: workspace._id, + workspaceId: workspace.id, env: "dev" }); secrets?.forEach((secret) => { createSecret({ - workspaceId: workspace._id, + workspaceId: workspace.id, environment: secret.environment, type: secret.type, secretKey: secret.secretName, diff --git a/frontend/src/hooks/api/apiKeys/types.ts b/frontend/src/hooks/api/apiKeys/types.ts index bc5ff3a56..b05bd5981 100644 --- a/frontend/src/hooks/api/apiKeys/types.ts +++ b/frontend/src/hooks/api/apiKeys/types.ts @@ -1,27 +1,27 @@ export type APIKeyDataV2 = { - id: string; - name: string; - user: string; - lastUsed?: string; - usageCount: number; - createdAt: string; - updatedAt: string; - }; + id: string; + name: string; + user: string; + lastUsed?: string; + usageCount: number; + createdAt: string; + updatedAt: string; +}; export type CreateAPIKeyDataV2DTO = { - name: string; -} + name: string; +}; export type CreateServiceTokenDataV3Res = { - apiKeyData: APIKeyDataV2; - apiKey: string; -} + apiKeyData: APIKeyDataV2; + apiKey: string; +}; export type UpdateAPIKeyDataV2DTO = { - apiKeyDataId: string; - name: string; -} + apiKeyDataId: string; + name: string; +}; export type DeleteAPIKeyDataV2DTO = { - apiKeyDataId: string; -} \ No newline at end of file + apiKeyDataId: string; +}; diff --git a/frontend/src/hooks/api/auditLogs/types.tsx b/frontend/src/hooks/api/auditLogs/types.tsx index 54f4882b3..92611c814 100644 --- a/frontend/src/hooks/api/auditLogs/types.tsx +++ b/frontend/src/hooks/api/auditLogs/types.tsx @@ -194,7 +194,8 @@ interface DeleteServiceTokenEvent { }; } -interface CreateIdentityEvent { // note: currently not logging org-role +interface CreateIdentityEvent { + // note: currently not logging org-role type: EventType.CREATE_IDENTITY; metadata: { identityId: string; @@ -218,7 +219,7 @@ interface DeleteIdentityEvent { } interface LoginIdentityUniversalAuthEvent { - type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH ; + type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH; metadata: { identityId: string; identityUniversalAuthId: string; @@ -259,7 +260,7 @@ interface GetIdentityUniversalAuthEvent { } interface CreateIdentityUniversalAuthClientSecretEvent { - type: EventType.CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET ; + type: EventType.CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET; metadata: { identityId: string; clientSecretId: string; @@ -273,9 +274,8 @@ interface GetIdentityUniversalAuthClientSecretsEvent { }; } - interface RevokeIdentityUniversalAuthClientSecretEvent { - type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET ; + type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET; metadata: { identityId: string; clientSecretId: string; @@ -507,7 +507,7 @@ export type Event = | UpdateUserDeniedPermissions; export type AuditLog = { - _id: string; + id: string; actor: Actor; organization: string; workspace: string; diff --git a/frontend/src/hooks/api/integrationAuth/types.ts b/frontend/src/hooks/api/integrationAuth/types.ts index 7a6ff6d53..1711436a8 100644 --- a/frontend/src/hooks/api/integrationAuth/types.ts +++ b/frontend/src/hooks/api/integrationAuth/types.ts @@ -55,14 +55,14 @@ export type BitBucketWorkspace = { uuid: string; name: string; slug: string; -} +}; export type NorthflankSecretGroup = { name: string; groupId: string; -} +}; export type TeamCityBuildConfig = { name: string; buildConfigId: string; -} \ No newline at end of file +}; diff --git a/frontend/src/hooks/api/integrations/types.ts b/frontend/src/hooks/api/integrations/types.ts index 3c814e80b..716f4604c 100644 --- a/frontend/src/hooks/api/integrations/types.ts +++ b/frontend/src/hooks/api/integrations/types.ts @@ -32,9 +32,9 @@ export type TIntegration = { __v: number; metadata?: { secretSuffix?: string; - scope: string; + scope: string; org: string; project: string; environment: string; - } + }; }; diff --git a/frontend/src/hooks/api/organization/types.ts b/frontend/src/hooks/api/organization/types.ts index c2468d8c2..3bfbd7419 100644 --- a/frontend/src/hooks/api/organization/types.ts +++ b/frontend/src/hooks/api/organization/types.ts @@ -13,7 +13,7 @@ export type RenameOrgDTO = { export type BillingDetails = { name: string; email: string; -} +}; export type PlanBillingInfo = { amount: number; @@ -22,7 +22,7 @@ export type PlanBillingInfo = { interval: "month" | "year"; intervalCount: number; quantity: number; -} +}; export type Invoice = { id: string; @@ -31,23 +31,23 @@ export type Invoice = { number: string; paid: boolean; total: number; -} +}; export type PmtMethod = { id: string; brand: string; - exp_month: number; + exp_month: number; exp_year: number; funding: string; last4: string; -} +}; export type TaxID = { id: string; country: string; type: string; value: string; -} +}; export type License = { id: string; @@ -58,22 +58,22 @@ export type License = { expiresAt: string; createdAt: string; updatedAt: string; -} +}; export type OrgPlanTableHead = { name: string; -} +}; export type OrgPlanTableRow = { name: string; allowed: number | boolean | null; used: string; -} +}; export type OrgPlanTable = { head: OrgPlanTableHead[]; rows: OrgPlanTableRow[]; -} +}; export type ProductsTableHead = { name: string; @@ -82,7 +82,7 @@ export type ProductsTableHead = { productId: string; slug: string; tier: number; -} +}; export type ProductsTableRow = { name: string; @@ -90,9 +90,9 @@ export type ProductsTableRow = { team: number | boolean | null; pro: number | boolean | null; enterprise: number | boolean | null; -} +}; export type ProductsTable = { head: ProductsTableHead[]; rows: ProductsTableRow[]; -} \ No newline at end of file +}; diff --git a/frontend/src/hooks/api/serviceTokens/types.ts b/frontend/src/hooks/api/serviceTokens/types.ts index ea3223660..489661d8b 100644 --- a/frontend/src/hooks/api/serviceTokens/types.ts +++ b/frontend/src/hooks/api/serviceTokens/types.ts @@ -4,7 +4,7 @@ export type ServiceTokenScope = { }; export type ServiceToken = { - _id: string; + id: string; name: string; workspace: string; scopes: ServiceTokenScope[]; @@ -32,4 +32,4 @@ export type CreateServiceTokenRes = { serviceTokenData: ServiceToken; }; -export type DeleteServiceTokenRes = { serviceTokenData: ServiceToken }; \ No newline at end of file +export type DeleteServiceTokenRes = { serviceTokenData: ServiceToken }; diff --git a/frontend/src/hooks/api/tags/types.ts b/frontend/src/hooks/api/tags/types.ts index 6e428da70..161e0327b 100644 --- a/frontend/src/hooks/api/tags/types.ts +++ b/frontend/src/hooks/api/tags/types.ts @@ -9,7 +9,7 @@ export type WsTag = { createdAt: string; updatedAt: string; __v: number; -} +}; export type WorkspaceTag = { id: string; name: string; slug: string }; @@ -30,7 +30,7 @@ export type CreateTagRes = { id: string; }; -export type DeleteTagDTO = { tagID: string; }; +export type DeleteTagDTO = { tagID: string }; export type DeleteWsTagRes = { name: string; @@ -41,17 +41,16 @@ export type DeleteWsTagRes = { id: string; }; -export type SecretTags = { - id: string; +export type SecretTags = { id: string; - slug: string; + slug: string; tagColor: string; -} +}; -export type TagColor = { +export type TagColor = { id: number; - hex: string - rgba: string - name: string - selected: boolean -} \ No newline at end of file + hex: string; + rgba: string; + name: string; + selected: boolean; +}; diff --git a/frontend/src/hooks/api/trustedIps/types.ts b/frontend/src/hooks/api/trustedIps/types.ts index fb8177c45..bd14b1c6e 100644 --- a/frontend/src/hooks/api/trustedIps/types.ts +++ b/frontend/src/hooks/api/trustedIps/types.ts @@ -1,9 +1,9 @@ export type TrustedIp = { - id: string; - workspace: string; - ipAddress: string; - type: "ipv4" | "ipv6"; - isActive: boolean; - comment: string; - prefix?: number; -}; \ No newline at end of file + id: string; + workspace: string; + ipAddress: string; + type: "ipv4" | "ipv6"; + isActive: boolean; + comment: string; + prefix?: number; +}; diff --git a/frontend/src/hooks/api/types.ts b/frontend/src/hooks/api/types.ts index eae8fa0d7..06c382358 100644 --- a/frontend/src/hooks/api/types.ts +++ b/frontend/src/hooks/api/types.ts @@ -23,7 +23,7 @@ export * from "./secrets/types"; export type { CreateServiceTokenDTO, ServiceToken } from "./serviceTokens/types"; export type { SubscriptionPlan } from "./subscriptions/types"; export type { WsTag } from "./tags/types"; -export type { AddUserToWsDTO, OrgUser, TWorkspaceUser, User } from "./users/types"; +export type { AddUserToWsDTO, OrgUser, TWorkspaceUser, User, UserEnc } from "./users/types"; export type { TWebhook } from "./webhooks/types"; export type { CreateEnvironmentDTO, diff --git a/frontend/src/hooks/api/users/queries.tsx b/frontend/src/hooks/api/users/queries.tsx index b865f8758..5c0349be1 100644 --- a/frontend/src/hooks/api/users/queries.tsx +++ b/frontend/src/hooks/api/users/queries.tsx @@ -14,7 +14,8 @@ import { RenameUserDTO, TokenVersion, UpdateOrgUserRoleDTO, - User + User, + UserEnc } from "./types"; export const userKeys = { @@ -29,7 +30,7 @@ export const userKeys = { }; export const fetchUserDetails = async () => { - const { data } = await apiRequest.get<{ user: User }>("/api/v1/user"); + const { data } = await apiRequest.get<{ user: User & UserEnc }>("/api/v1/user"); return data.user; }; diff --git a/frontend/src/hooks/api/users/types.ts b/frontend/src/hooks/api/users/types.ts index 31169a3fc..5868d6f5b 100644 --- a/frontend/src/hooks/api/users/types.ts +++ b/frontend/src/hooks/api/users/types.ts @@ -19,6 +19,12 @@ export type User = { lastName?: string; authProvider?: AuthMethod; authMethods: AuthMethod[]; + isMfaEnabled: boolean; + seenIps: string[]; + id: string; +}; + +export type UserEnc = { encryptionVersion?: number; protectedKey?: string; protectedKeyIV?: string; @@ -27,19 +33,15 @@ export type User = { encryptedPrivateKey?: string; iv?: string; tag?: string; - isMfaEnabled: boolean; - seenIps: string[]; - _id: string; - __v: number; }; export type OrgUser = { - _id: string; + id: string; user: { email: string; firstName: string; lastName: string; - _id: string; + id: string; publicKey: string; }; inviteEmail: string; @@ -88,7 +90,7 @@ export type RenameUserDTO = { }; export type APIKeyData = { - _id: string; + id: string; name: string; user: string; lastUsed: string; @@ -97,7 +99,7 @@ export type APIKeyData = { }; export type TokenVersion = { - _id: string; + id: string; user: string; userAgent: string; ip: string; diff --git a/frontend/src/hooks/api/workspace/types.ts b/frontend/src/hooks/api/workspace/types.ts index 80d1aaaa8..a4acc2cf6 100644 --- a/frontend/src/hooks/api/workspace/types.ts +++ b/frontend/src/hooks/api/workspace/types.ts @@ -22,7 +22,7 @@ export type NameWorkspaceSecretsDTO = { secretName: string; id: string; }[]; -} +}; // mutation dto export type CreateWorkspaceDTO = { @@ -47,7 +47,6 @@ export type ReorderEnvironmentsDTO = { environmentName: string; otherEnvironmentSlug: string; otherEnvironmentName: string; - }; export type UpdateEnvironmentDTO = { @@ -57,4 +56,4 @@ export type UpdateEnvironmentDTO = { environmentName: string; }; -export type DeleteEnvironmentDTO = { workspaceID: string; environmentSlug: string }; \ No newline at end of file +export type DeleteEnvironmentDTO = { workspaceID: string; environmentSlug: string }; diff --git a/frontend/src/layouts/AdminLayout/AdminLayout.tsx b/frontend/src/layouts/AdminLayout/AdminLayout.tsx index 3cee01f11..0e38c9a13 100644 --- a/frontend/src/layouts/AdminLayout/AdminLayout.tsx +++ b/frontend/src/layouts/AdminLayout/AdminLayout.tsx @@ -100,7 +100,7 @@ export const AdminLayout = ({ children }: LayoutProps) => {