diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c3ce6a4 --- /dev/null +++ b/.env.example @@ -0,0 +1,24 @@ +COOKIE_SIGN_KEY=key +JWT_SIGN_KEY=key +secret_token_key=key +DB_ENCRYPTION_KEY=key + +DB_API_SK_1=key +DB_API_SK_2=key + +secret_admin_api_key=key +SECRET_AI_API_KEY=key +MOBILE_SECRET_KEY=key + +STRIPE_SECRET_KEY=key +STRIPE_WEBHOOK_SECRET=key + +OPENAI_SECRET_KEY=sk-proj-key +GOOGLE_API_KEY=key + +CLERK_PUBLISHABLE_KEY=key +CLERK_SECRET_KEY=key + +MCP_SERVER_PATH=./src/mcp-server/index.js + +CRONITOR_API_KEY=key \ No newline at end of file diff --git a/.swcrc b/.swcrc new file mode 100644 index 0000000..fa9525c --- /dev/null +++ b/.swcrc @@ -0,0 +1,21 @@ +{ + "jsc": { + "parser": { + "syntax": "typescript", + "tsx": false, + "decorators": true + }, + "target": "es2022", + "loose": false, + "externalHelpers": true, + "minify": { + "compress": true, + "mangle": true + } + }, + "module": { + "type": "es6" + }, + "minify": true, + "sourceMaps": true +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..43a74aa --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright © 2026 Silvercore + +Tous droits réservés / All Rights Reserved + +Le code source de ce projet est rendu public uniquement à des fins +de transparence. Aucune licence d'utilisation, de modification, de +distribution ou de reproduction n'est accordée. + +This source code is made publicly available for transparency purposes +only. No license to use, modify, distribute, or reproduce is granted. + +Toute utilisation non autorisée de ce code est strictement interdite. +Unauthorized use of this code is strictly prohibited. diff --git a/package-lock.json b/package-lock.json index f9eb6eb..ea4ec6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "silvernote_back", - "version": "0.3.4-beta", + "version": "1.1.11-beta", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "silvernote_back", - "version": "0.3.4-beta", + "version": "1.1.11-beta", "license": "ISC", "dependencies": { "@clerk/clerk-sdk-node": "^4.13.23", @@ -38,13 +38,14 @@ "socket.io": "^4.8.1", "socket.io-client": "^4.8.1", "stripe": "^18.3.0", - "typescript": "^5.8.3", "xmldom": "^0.6.0", "y-prosemirror": "^1.3.7", "y-protocols": "^1.0.6", "yjs": "^13.6.27" }, "devDependencies": { + "@swc/cli": "^0.8.0", + "@swc/core": "^1.15.11", "@types/cookie-parser": "^1.4.9", "@types/cors": "^2.8.19", "@types/jsdom": "^21.1.7", @@ -56,7 +57,8 @@ "@types/node-fetch": "^2.6.13", "@types/xmldom": "^0.1.34", "esbuild": "^0.25.12", - "multer": "^2.0.2" + "multer": "^2.0.2", + "typescript": "^5.9.3" } }, "node_modules/@asamuzakjp/css-color": { @@ -109,6 +111,17 @@ "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", "license": "MIT" }, + "node_modules/@borewit/text-codec": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.1.tgz", + "integrity": "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/@clerk/backend": { "version": "2.6.0", "license": "MIT", @@ -1076,6 +1089,329 @@ "node": ">=18" } }, + "node_modules/@napi-rs/nice": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", + "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/nice-android-arm-eabi": "1.1.1", + "@napi-rs/nice-android-arm64": "1.1.1", + "@napi-rs/nice-darwin-arm64": "1.1.1", + "@napi-rs/nice-darwin-x64": "1.1.1", + "@napi-rs/nice-freebsd-x64": "1.1.1", + "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", + "@napi-rs/nice-linux-arm64-gnu": "1.1.1", + "@napi-rs/nice-linux-arm64-musl": "1.1.1", + "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", + "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", + "@napi-rs/nice-linux-s390x-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-musl": "1.1.1", + "@napi-rs/nice-openharmony-arm64": "1.1.1", + "@napi-rs/nice-win32-arm64-msvc": "1.1.1", + "@napi-rs/nice-win32-ia32-msvc": "1.1.1", + "@napi-rs/nice-win32-x64-msvc": "1.1.1" + } + }, + "node_modules/@napi-rs/nice-android-arm-eabi": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", + "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-android-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", + "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", + "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", + "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-freebsd-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", + "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", + "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-ppc64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", + "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-riscv64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", + "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-s390x-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", + "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", + "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", + "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-openharmony-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", + "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-arm64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", + "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-ia32-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", + "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-x64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", + "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@peculiar/asn1-schema": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.5.0.tgz", @@ -1140,6 +1476,19 @@ "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", "license": "MIT" }, + "node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", @@ -1150,17 +1499,317 @@ "version": "1.0.1", "license": "MIT" }, - "node_modules/@tiptap/core": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.5.1.tgz", - "integrity": "sha512-OmnL68v+DAHEGEO9C48oV1/F6VUOzb6ozDySrer0cxtbasVlt4QjndoXg99Db3lSgoL0JgRSHR+dBge5RbILAQ==", + "node_modules/@swc/cli": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.8.0.tgz", + "integrity": "sha512-vzUkYzlqLe9dC+B0ZIH62CzfSZOCTjIsmquYyyyi45JCm1xmRfLDKeEeMrEPPyTWnEEN84e4iVd49Tgqa+2GaA==", + "dev": true, "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" + "dependencies": { + "@swc/counter": "^0.1.3", + "@xhmikosr/bin-wrapper": "^13.0.5", + "commander": "^8.3.0", + "minimatch": "^9.0.3", + "piscina": "^4.3.1", + "semver": "^7.3.8", + "slash": "3.0.0", + "source-map": "^0.7.3", + "tinyglobby": "^0.2.13" }, - "peerDependencies": { - "@tiptap/pm": "^3.5.1" + "bin": { + "spack": "bin/spack.js", + "swc": "bin/swc.js", + "swcx": "bin/swcx.js" + }, + "engines": { + "node": ">= 20.19.0" + }, + "peerDependencies": { + "@swc/core": "^1.2.66", + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@swc/cli/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@swc/cli/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@swc/core": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.11.tgz", + "integrity": "sha512-iLmLTodbYxU39HhMPaMUooPwO/zqJWvsqkrXv1ZI38rMb048p6N7qtAtTp37sw9NzSrvH6oli8EdDygo09IZ/w==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.11", + "@swc/core-darwin-x64": "1.15.11", + "@swc/core-linux-arm-gnueabihf": "1.15.11", + "@swc/core-linux-arm64-gnu": "1.15.11", + "@swc/core-linux-arm64-musl": "1.15.11", + "@swc/core-linux-x64-gnu": "1.15.11", + "@swc/core-linux-x64-musl": "1.15.11", + "@swc/core-win32-arm64-msvc": "1.15.11", + "@swc/core-win32-ia32-msvc": "1.15.11", + "@swc/core-win32-x64-msvc": "1.15.11" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.11.tgz", + "integrity": "sha512-QoIupRWVH8AF1TgxYyeA5nS18dtqMuxNwchjBIwJo3RdwLEFiJq6onOx9JAxHtuPwUkIVuU2Xbp+jCJ7Vzmgtg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.11.tgz", + "integrity": "sha512-S52Gu1QtPSfBYDiejlcfp9GlN+NjTZBRRNsz8PNwBgSE626/FUf2PcllVUix7jqkoMC+t0rS8t+2/aSWlMuQtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.11.tgz", + "integrity": "sha512-lXJs8oXo6Z4yCpimpQ8vPeCjkgoHu5NoMvmJZ8qxDyU99KVdg6KwU9H79vzrmB+HfH+dCZ7JGMqMF//f8Cfvdg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.11.tgz", + "integrity": "sha512-chRsz1K52/vj8Mfq/QOugVphlKPWlMh10V99qfH41hbGvwAU6xSPd681upO4bKiOr9+mRIZZW+EfJqY42ZzRyA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.11.tgz", + "integrity": "sha512-PYftgsTaGnfDK4m6/dty9ryK1FbLk+LosDJ/RJR2nkXGc8rd+WenXIlvHjWULiBVnS1RsjHHOXmTS4nDhe0v0w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.11.tgz", + "integrity": "sha512-DKtnJKIHiZdARyTKiX7zdRjiDS1KihkQWatQiCHMv+zc2sfwb4Glrodx2VLOX4rsa92NLR0Sw8WLcPEMFY1szQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.11.tgz", + "integrity": "sha512-mUjjntHj4+8WBaiDe5UwRNHuEzLjIWBTSGTw0JT9+C9/Yyuh4KQqlcEQ3ro6GkHmBGXBFpGIj/o5VMyRWfVfWw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.11.tgz", + "integrity": "sha512-ZkNNG5zL49YpaFzfl6fskNOSxtcZ5uOYmWBkY4wVAvgbSAQzLRVBp+xArGWh2oXlY/WgL99zQSGTv7RI5E6nzA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.11.tgz", + "integrity": "sha512-6XnzORkZCQzvTQ6cPrU7iaT9+i145oLwnin8JrfsLG41wl26+5cNQ2XV3zcbrnFEV6esjOceom9YO1w9mGJByw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.11.tgz", + "integrity": "sha512-IQ2n6af7XKLL6P1gIeZACskSxK8jWtoKpJWLZmdXTDj1MGzktUy4i+FvpdtxFmJWNavRWH1VmTr6kAubRDHeKw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.25", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz", + "integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@tiptap/core": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.5.1.tgz", + "integrity": "sha512-OmnL68v+DAHEGEO9C48oV1/F6VUOzb6ozDySrer0cxtbasVlt4QjndoXg99Db3lSgoL0JgRSHR+dBge5RbILAQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/pm": "^3.5.1" } }, "node_modules/@tiptap/extension-blockquote": { @@ -1523,6 +2172,32 @@ "url": "https://github.com/sponsors/ueberdosis" } }, + "node_modules/@tokenizer/inflate": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.2.7.tgz", + "integrity": "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "fflate": "^0.8.2", + "token-types": "^6.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/body-parser": { "version": "1.19.6", "license": "MIT", @@ -1584,6 +2259,13 @@ "@types/send": "*" } }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/http-errors": { "version": "2.0.5", "license": "MIT" @@ -1699,48 +2381,218 @@ "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*", - "form-data": "^4.0.4" + "@types/node": "*", + "form-data": "^4.0.4" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/xmldom": { + "version": "0.1.34", + "resolved": "https://registry.npmjs.org/@types/xmldom/-/xmldom-0.1.34.tgz", + "integrity": "sha512-7eZFfxI9XHYjJJuugddV6N5YNeXgQE1lArWOcd1eCOKWb/FGs5SIjacSYuEJuwhsGS3gy4RuZ5EUIcqYscuPDA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@xhmikosr/archive-type": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/archive-type/-/archive-type-7.1.0.tgz", + "integrity": "sha512-xZEpnGplg1sNPyEgFh0zbHxqlw5dtYg6viplmWSxUj12+QjU9SKu3U/2G73a15pEjLaOqTefNSZ1fOPUOT4Xgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "file-type": "^20.5.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@xhmikosr/bin-check": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/bin-check/-/bin-check-7.1.0.tgz", + "integrity": "sha512-y1O95J4mnl+6MpVmKfMYXec17hMEwE/yeCglFNdx+QvLLtP0yN4rSYcbkXnth+lElBuKKek2NbvOfOGPpUXCvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.1.1", + "isexe": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@xhmikosr/bin-wrapper": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/bin-wrapper/-/bin-wrapper-13.2.0.tgz", + "integrity": "sha512-t9U9X0sDPRGDk5TGx4dv5xiOvniVJpXnfTuynVKwHgtib95NYEw4MkZdJqhoSiz820D9m0o6PCqOPMXz0N9fIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xhmikosr/bin-check": "^7.1.0", + "@xhmikosr/downloader": "^15.2.0", + "@xhmikosr/os-filter-obj": "^3.0.0", + "bin-version-check": "^5.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@xhmikosr/decompress": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress/-/decompress-10.2.0.tgz", + "integrity": "sha512-MmDBvu0+GmADyQWHolcZuIWffgfnuTo4xpr2I/Qw5Ox0gt+e1Be7oYqJM4te5ylL6mzlcoicnHVDvP27zft8tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xhmikosr/decompress-tar": "^8.1.0", + "@xhmikosr/decompress-tarbz2": "^8.1.0", + "@xhmikosr/decompress-targz": "^8.1.0", + "@xhmikosr/decompress-unzip": "^7.1.0", + "graceful-fs": "^4.2.11", + "strip-dirs": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@xhmikosr/decompress-tar": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-tar/-/decompress-tar-8.1.0.tgz", + "integrity": "sha512-m0q8x6lwxenh1CrsTby0Jrjq4vzW/QU1OLhTHMQLEdHpmjR1lgahGz++seZI0bXF3XcZw3U3xHfqZSz+JPP2Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "file-type": "^20.5.0", + "is-stream": "^2.0.1", + "tar-stream": "^3.1.7" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@xhmikosr/decompress-tarbz2": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-tarbz2/-/decompress-tarbz2-8.1.0.tgz", + "integrity": "sha512-aCLfr3A/FWZnOu5eqnJfme1Z1aumai/WRw55pCvBP+hCGnTFrcpsuiaVN5zmWTR53a8umxncY2JuYsD42QQEbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xhmikosr/decompress-tar": "^8.0.1", + "file-type": "^20.5.0", + "is-stream": "^2.0.1", + "seek-bzip": "^2.0.0", + "unbzip2-stream": "^1.4.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@xhmikosr/decompress-targz": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-targz/-/decompress-targz-8.1.0.tgz", + "integrity": "sha512-fhClQ2wTmzxzdz2OhSQNo9ExefrAagw93qaG1YggoIz/QpI7atSRa7eOHv4JZkpHWs91XNn8Hry3CwUlBQhfPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xhmikosr/decompress-tar": "^8.0.1", + "file-type": "^20.5.0", + "is-stream": "^2.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@xhmikosr/decompress-unzip": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-unzip/-/decompress-unzip-7.1.0.tgz", + "integrity": "sha512-oqTYAcObqTlg8owulxFTqiaJkfv2SHsxxxz9Wg4krJAHVzGWlZsU8tAB30R6ow+aHrfv4Kub6WQ8u04NWVPUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "file-type": "^20.5.0", + "get-stream": "^6.0.1", + "yauzl": "^3.1.2" + }, + "engines": { + "node": ">=18" } }, - "node_modules/@types/qs": { - "version": "6.14.0", - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "license": "MIT" - }, - "node_modules/@types/send": { - "version": "0.17.5", + "node_modules/@xhmikosr/downloader": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/downloader/-/downloader-15.2.0.tgz", + "integrity": "sha512-lAqbig3uRGTt0sHNIM4vUG9HoM+mRl8K28WuYxyXLCUT6pyzl4Y4i0LZ3jMEsCYZ6zjPZbO9XkG91OSTd4si7g==", + "dev": true, "license": "MIT", "dependencies": { - "@types/mime": "^1", - "@types/node": "*" + "@xhmikosr/archive-type": "^7.1.0", + "@xhmikosr/decompress": "^10.2.0", + "content-disposition": "^0.5.4", + "defaults": "^2.0.2", + "ext-name": "^5.0.0", + "file-type": "^20.5.0", + "filenamify": "^6.0.0", + "get-stream": "^6.0.1", + "got": "^13.0.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/@types/serve-static": { - "version": "1.15.8", + "node_modules/@xhmikosr/downloader/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==", + "dev": true, "license": "MIT", "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" } }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/xmldom": { - "version": "0.1.34", - "resolved": "https://registry.npmjs.org/@types/xmldom/-/xmldom-0.1.34.tgz", - "integrity": "sha512-7eZFfxI9XHYjJJuugddV6N5YNeXgQE1lArWOcd1eCOKWb/FGs5SIjacSYuEJuwhsGS3gy4RuZ5EUIcqYscuPDA==", + "node_modules/@xhmikosr/os-filter-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/os-filter-obj/-/os-filter-obj-3.0.0.tgz", + "integrity": "sha512-siPY6BD5dQ2SZPl3I0OZBHL27ZqZvLEosObsZRQ1NUB8qcxegwt0T9eKtV96JMFQpIz1elhkzqOg4c/Ri6Dp9A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "arch": "^3.0.0" + }, + "engines": { + "node": "^14.14.0 || >=16.0.0" + } }, "node_modules/accepts": { "version": "2.0.0", @@ -1804,6 +2656,8 @@ }, "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==", "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -1813,6 +2667,18 @@ "node": ">= 8" } }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", @@ -1820,6 +2686,27 @@ "dev": true, "license": "MIT" }, + "node_modules/arch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-3.0.0.tgz", + "integrity": "sha512-AmIAC+Wtm2AU8lGfTtHsw0Y9Qtftx2YXEEtiBP10xFUtMOA+sHHx6OAddyL52mUKh1vsXQ6/w1mVDptZCyUt4Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/argon2": { "version": "0.44.0", "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.44.0.tgz", @@ -1917,6 +2804,21 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/bare-events": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", + "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -1987,8 +2889,45 @@ "node": "*" } }, + "node_modules/bin-version": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz", + "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "find-versions": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version-check": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.1.0.tgz", + "integrity": "sha512-bYsvMqJ8yNGILLz1KP9zKLzQ6YpljV3ln1gqhuLkUtyfGi3qXKGuK2p+U4NAvjVFzDFiBBtOpCOSFNuYYEGZ5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bin-version": "^6.0.0", + "semver": "^7.5.3", + "semver-truncate": "^3.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "license": "MIT", "engines": { "node": ">=8" @@ -2031,6 +2970,8 @@ }, "node_modules/braces": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -2039,6 +2980,41 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "license": "BSD-3-Clause" @@ -2069,6 +3045,35 @@ "node": ">= 0.8" } }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "license": "MIT", @@ -2164,28 +3169,6 @@ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", "license": "BSD-2-Clause" }, - "node_modules/chokidar": { - "version": "3.6.0", - "license": "MIT", - "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" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2216,6 +3199,16 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/concat-map": { "version": "0.0.1", "license": "MIT" @@ -2472,6 +3465,35 @@ "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", "license": "MIT" }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", @@ -2481,6 +3503,29 @@ "node": ">=0.10.0" } }, + "node_modules/defaults": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-2.0.2.tgz", + "integrity": "sha512-cuIw0PImdp76AOfgkjbW4VhQODRmNNcKR73vdCH5cLd/ifj7aamfoXvYgfGkEAjNJZ3ozMIy9Gu2LutUkGEPbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2898,6 +3943,16 @@ "node": ">= 0.6" } }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, "node_modules/eventsource": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", @@ -2919,6 +3974,37 @@ "node": ">=18.0.0" } }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "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/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/express": { "version": "5.1.0", "license": "MIT", @@ -2964,14 +4050,41 @@ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.28.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" }, - "peerDependencies": { - "express": ">= 4.11" + "engines": { + "node": ">=4" } }, "node_modules/extend": { @@ -2995,6 +4108,13 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, "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", @@ -3005,6 +4125,24 @@ "version": "1.3.0", "license": "Unlicense" }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -3028,8 +4166,65 @@ "node": "^12.20 || >= 14.13" } }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-type": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-20.5.0.tgz", + "integrity": "sha512-BfHZtG/l9iMm4Ecianu7P8HRD2tBHLtjXinm4X62XBOYzi7CYA7jyqfJzOvXHqzVrVPYqBo2/GvbARMaaJkKVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tokenizer/inflate": "^0.2.6", + "strtok3": "^10.2.0", + "token-types": "^6.0.0", + "uint8array-extras": "^1.4.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/filename-reserved-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", + "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/filenamify": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-6.0.0.tgz", + "integrity": "sha512-vqIlNogKeyD3yzrm0yhRMQg8hOVwYcYRfjEoODd49iCprMn4HL85gK3HcykQE53EPIpX3HcAbGA5ELQv216dAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "filename-reserved-regex": "^3.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/fill-range": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -3053,6 +4248,22 @@ "node": ">= 0.8" } }, + "node_modules/find-versions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", + "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver-regex": "^4.0.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/follow-redirects": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", @@ -3114,6 +4325,16 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.17" + } + }, "node_modules/form-data/node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -3269,6 +4490,19 @@ "node": ">= 0.4" } }, + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -3300,6 +4534,8 @@ }, "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==", "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -3404,6 +4640,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/got": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz", + "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "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, + "license": "ISC" + }, "node_modules/gtoken": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz", @@ -3543,6 +4812,13 @@ "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==", "license": "BSD-like" }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/http-errors": { "version": "2.0.0", "license": "MIT", @@ -3585,6 +4861,33 @@ "npm": ">=1.3.7" } }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/http2-wrapper/node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -3598,6 +4901,16 @@ "node": ">= 14" } }, + "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, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "license": "MIT", @@ -3608,6 +4921,27 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore-by-default": { "version": "1.0.1", "license": "ISC" @@ -3616,6 +4950,16 @@ "version": "2.0.4", "license": "ISC" }, + "node_modules/inspect-with-kind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/inspect-with-kind/-/inspect-with-kind-1.0.5.tgz", + "integrity": "sha512-MAQUJuIo7Xqk8EVNP+6d3CKq9c80hi4tjIbIAT6lmGW9W6WzlHiu9PS8uSuUYU+Do+j1baiFp3H25XEVxDIG2g==", + "dev": true, + "license": "ISC", + "dependencies": { + "kind-of": "^6.0.2" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "license": "MIT", @@ -3625,6 +4969,8 @@ }, "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==", "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -3635,6 +4981,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==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3651,6 +4999,8 @@ }, "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==", "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -3661,11 +5011,23 @@ }, "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==", "license": "MIT", "engines": { "node": ">=0.12.0" } }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -3680,6 +5042,19 @@ "version": "1.0.2", "license": "MIT" }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -3797,6 +5172,13 @@ "bignumber.js": "^9.0.0" } }, + "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==", + "dev": true, + "license": "MIT" + }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -3869,6 +5251,26 @@ "safe-buffer": "^5.0.1" } }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/lib0": { "version": "0.2.114", "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.114.tgz", @@ -3972,6 +5374,19 @@ "tslib": "^2.0.3" } }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lru-cache": { "version": "7.18.3", "license": "ISC", @@ -4067,6 +5482,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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, + "license": "MIT" + }, "node_modules/mime-db": { "version": "1.54.0", "license": "MIT", @@ -4084,6 +5506,29 @@ "node": ">= 0.6" } }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "license": "ISC", @@ -4402,20 +5847,96 @@ "nodemon": "bin/nodemon.js" }, "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "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" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/nodemon/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/nodemon/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, "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==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", + "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/nth-check": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", @@ -4475,6 +5996,22 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/openai": { "version": "5.12.2", "license": "Apache-2.0", @@ -4500,6 +6037,16 @@ "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", "license": "MIT" }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -4563,6 +6110,13 @@ "node": ">=16" } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -4577,15 +6131,28 @@ "peer": true }, "node_modules/picomatch": { - "version": "2.3.1", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/piscina": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.9.2.tgz", + "integrity": "sha512-Fq0FERJWFEUpB4eSY59wSNwXD4RYqR+nR/WiEVcZW8IWfVBxJJafcgTEZDQo8k3w0sUarJ8RyVbbUF4GQ2LGbQ==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "@napi-rs/nice": "^1.0.1" + } + }, "node_modules/pkce-challenge": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", @@ -4955,16 +6522,6 @@ "string_decoder": "~0.10.x" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -5063,6 +6620,29 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/rimraf": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", @@ -5138,6 +6718,30 @@ "node": ">=v12.22.7" } }, + "node_modules/seek-bzip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-2.0.0.tgz", + "integrity": "sha512-SMguiTnYrhpLdk3PwfzHeotrcwi8bNV4iemL9tx9poR/yeaMYwB9VzR1w7b57DuWpuqR8n6oZboi0hj3AxZxQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^6.0.0" + }, + "bin": { + "seek-bunzip": "bin/seek-bunzip", + "seek-table": "bin/seek-bzip-table" + } + }, + "node_modules/seek-bzip/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/semver": { "version": "7.7.2", "license": "ISC", @@ -5148,6 +6752,35 @@ "node": ">=10" } }, + "node_modules/semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-truncate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-3.0.0.tgz", + "integrity": "sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/send": { "version": "1.2.0", "license": "MIT", @@ -5295,6 +6928,16 @@ "node": ">=10" } }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/snake-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", @@ -5505,6 +7148,42 @@ "node": ">= 0.6" } }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5574,6 +7253,18 @@ "node": ">=10.0.0" } }, + "node_modules/streamx": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, "node_modules/string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -5676,6 +7367,27 @@ "node": ">=8" } }, + "node_modules/strip-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-3.0.0.tgz", + "integrity": "sha512-I0sdgcFTfKQlUPZyAqPJmSG3HLO9rWDFnxonnIbskYNM3DwFOeTNB5KzVq3dA1GdRAc/25b5Y7UO2TQfKWw4aQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "inspect-with-kind": "^1.0.5", + "is-plain-obj": "^1.1.0" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/stripe": { "version": "18.3.0", "license": "MIT", @@ -5694,6 +7406,23 @@ } } }, + "node_modules/strtok3": { + "version": "10.3.4", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.4.tgz", + "integrity": "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/supports-color": { "version": "5.5.0", "license": "MIT", @@ -5721,6 +7450,82 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "license": "MIT" }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tar-stream/node_modules/b4a": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", + "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/text-decoder/node_modules/b4a": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", + "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/tldts": { "version": "7.0.16", "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.16.tgz", @@ -5747,6 +7552,8 @@ }, "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==", "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -5780,6 +7587,25 @@ "node": ">=0.6" } }, + "node_modules/token-types": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@borewit/text-codec": "^0.2.1", + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/touch": { "version": "3.1.1", "license": "ISC", @@ -5863,7 +7689,10 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.8.3", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -5879,6 +7708,30 @@ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "license": "MIT" }, + "node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "license": "MIT" @@ -6252,6 +8105,20 @@ "yjs": "^13.0.0" } }, + "node_modules/yauzl": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.2.0.tgz", + "integrity": "sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/yjs": { "version": "13.6.27", "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.27.tgz", diff --git a/package.json b/package.json index 1cbadca..7a21464 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,16 @@ { "name": "silvernote_back", - "version": "1.1.11-beta", + "version": "1.11.21-beta", "description": "", "main": "index.js", "scripts": { "start": "node dist/app.js", - "dev": "npm run build && npm start", - "build": "tsc" + "dev:old": "tsc && npm start", + "build:old": "tsc", + "dev": "swc src -w -d dist", + "build": "npm run type-check-once && npm run build-only", + "type-check-once": "tsc --noEmit", + "build-only": "swc src -d dist --copy-files" }, "repository": { "type": "git", @@ -46,13 +50,14 @@ "socket.io": "^4.8.1", "socket.io-client": "^4.8.1", "stripe": "^18.3.0", - "typescript": "^5.8.3", "xmldom": "^0.6.0", "y-prosemirror": "^1.3.7", "y-protocols": "^1.0.6", "yjs": "^13.6.27" }, "devDependencies": { + "@swc/cli": "^0.8.0", + "@swc/core": "^1.15.11", "@types/cookie-parser": "^1.4.9", "@types/cors": "^2.8.19", "@types/jsdom": "^21.1.7", @@ -64,7 +69,8 @@ "@types/node-fetch": "^2.6.13", "@types/xmldom": "^0.1.34", "esbuild": "^0.25.12", - "multer": "^2.0.2" + "multer": "^2.0.2", + "typescript": "^5.9.3" }, "bugs": { "url": "https://github.com/SilverCore-Git/silvernote/issues" diff --git a/src/assets/config/jeremy_ai.json b/src/assets/config/jeremy_ai.json index a668f3d..3df7378 100644 --- a/src/assets/config/jeremy_ai.json +++ b/src/assets/config/jeremy_ai.json @@ -1,3 +1,3 @@ { - "prompt_system": "Tu es le chatbot de l'application de prise de notes Silvernote. Par défaut, tu parles français. Tu aides l'utilisateur à organiser ses notes, gérer ses dossiers et tags, répondre aux questions sur l'application et donner des conseils pour mieux gérer ses notes. Tes réponses doivent être toujours polies, claires, encourageantes, brèves, précises et simple, ne dit pas comment tu fait une action juste tu dis que tu la fait. Ne jamais inventer d'informations sur l'utilisateur en dehors de ce qu'il fournit. Si une question est hors sujet ou inconnue, le dire poliment. Ne pas ajouter d'informations inutiles. Toujours répondre en Markdown HTML. Les icônes des notes doivent être mises dans le champ icon: \"URL\" en utilisant un lien vers un PNG fourni par l'API https://emojiapi.dev/api/v1. Pour générer correctement l'URL, utilise le format https://emojiapi.dev/api/v1/{code_unicode}/{taille}.png, où {code_unicode} est le code unicode de l'emoji et {taille} est la taille en pixels (32 à 512). Par exemple, pour l'emoji 🐱 (code unicode 1f431) en taille 128px, l'URL sera https://emojiapi.dev/api/v1/1f431/128.png. Les todolist doivent utiliser ce format exact : . Pour le Markdown, les fonctions comme **text** ou __text__ doivent être collées au texte. Tu est connecté au MCP de silvernote qui te permet d'affectuer des actions sur les notes et les tags de l'utilisateur et de les récupérer. L'utilisateur sait qui tu es sauf s'il te le demande." + "prompt_system": "Tu es le chatbot de l'application de prise de notes Silvernote. Par défaut, tu parles français. Tu aides l'utilisateur à organiser ses notes, gérer ses dossiers et tags, répondre aux questions sur l'application et donner des conseils pour mieux gérer ses notes. Tes réponses doivent être toujours polies, claires, encourageantes, brèves, précises et simple, ne dit pas comment tu fait une action juste tu dis que tu la fait. Ne jamais inventer d'informations sur l'utilisateur en dehors de ce qu'il fournit. Toujours répondre en Markdown HTML. Les icônes des notes doivent être mises dans le champ icon: \"URL\" en utilisant un lien vers un PNG fourni par l'API https://emojiapi.dev/api/v1. Pour générer correctement l'URL, utilise le format https://emojiapi.dev/api/v1/{code_unicode}/{taille}.png, où {code_unicode} est le code unicode de l'emoji et {taille} est la taille en pixels (32 à 512). Par exemple, pour l'emoji 🐱 (code unicode 1f431) en taille 128px, l'URL sera https://emojiapi.dev/api/v1/1f431/128.png. Pour le Markdown, les fonctions comme **text** ou __text__ doivent être collées au texte. Tu est connecté au MCP de silvernote qui te permet d'affectuer des actions sur les notes et les tags de l'utilisateur et de les récupérer. Tu ne doit en aucun cas donné des information d'un autre utilisateur. L'utilisateur sait qui tu es sauf s'il te le demande." } diff --git a/src/assets/ts/database.ts b/src/assets/ts/database.ts index d03eb1d..e14f89c 100644 --- a/src/assets/ts/database.ts +++ b/src/assets/ts/database.ts @@ -69,7 +69,39 @@ class Database { } + public setAndroidToken ( userID: string, token: string ): Promise { + return new Promise( async (resolve, reject) => { + + try { + + const db: User[] = await this.get('user'); + + const userIndex = db.findIndex(user => user.userId === userID); + + if (userIndex === -1) { + throw new Error('Utilisateur non trouvé'); + } + + if (!db[userIndex].androidToken) { + db[userIndex].androidToken = ''; + } + + if (db[userIndex].androidToken !== token) { + db[userIndex].androidToken = token; + } + + await this.save('user', db); + + resolve(); + + } catch (error) { + reject(error); + } + + }); + + } public async new_session ( userID: string ): Promise { diff --git a/src/assets/ts/db/2048_db.ts b/src/assets/ts/db/2048_db.ts new file mode 100644 index 0000000..c4672c9 --- /dev/null +++ b/src/assets/ts/db/2048_db.ts @@ -0,0 +1,170 @@ +import { readFile, writeFile } from 'fs/promises'; +import path from 'path'; +import fs from 'fs'; +import { fileURLToPath } from 'url'; + + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + + +interface UserItem { + id: string; + best_score: number; + total_score: number; + max_tile: number; + lastPlayed: Date | null; + partiesCount: number; +} + +interface UserItemSmall { + id: string; + best_score: number; + max_tile: number; + lastPlayed: Date | null; +} + + + +export class GameManager +{ + + private dbPath: string; + + constructor() + { + + const dbDir = path.join(__dirname, '../../../', 'db'); + this.dbPath = path.join(dbDir, '2048.json'); + + if (!fs.existsSync(dbDir)) { + fs.mkdirSync(dbDir, { recursive: true }); + } + + if (!fs.existsSync(this.dbPath)) { + fs.writeFileSync(this.dbPath, JSON.stringify([]), 'utf-8'); + } + + } + + public async getAll(): Promise + { + + try { + + const data = await readFile(this.dbPath, 'utf-8'); + const users: UserItem[] = JSON.parse(data); + + return users.map(user => ({ + ...user, + lastPlayed: user.lastPlayed ? new Date(user.lastPlayed) : null + })); + + } + catch (error) { + console.error("Erreur lecture 2048.json:", error); + return []; + } + + } + + public async getByUserID(userId: string): Promise + { + + const users = await this.getAll(); + const user = users.find(u => u.id === userId); + + if (user) return user; + + const newUser: UserItem = { + id: userId, + best_score: 0, + total_score: 0, + max_tile: 0, + lastPlayed: null, + partiesCount: 0 + }; + + users.push(newUser); + await this.saveAll(users); + + return newUser; + + } + + + public async update(rawUpdate: UserItemSmall): Promise + { + + let existingUser = await this.getByUserID(rawUpdate.id); + + if (!existingUser) + { + existingUser = await this.create(rawUpdate.id); + } + + const update: UserItem = { + id: rawUpdate.id, + best_score: rawUpdate.best_score > existingUser.best_score ? rawUpdate.best_score : existingUser.best_score, + total_score: existingUser.total_score + rawUpdate.best_score, // best score = score + max_tile: rawUpdate.max_tile > existingUser.max_tile ? rawUpdate.max_tile : existingUser.max_tile, + lastPlayed: rawUpdate.lastPlayed || new Date(), + partiesCount: existingUser.partiesCount + 1 + }; + + const users = await this.getAll(); + const index = users.findIndex(u => u.id === update.id); + + if (index !== -1) { + users[index] = { ...update }; + } else { + users.push(update); + } + + await this.saveAll(users); + + } + + public async create(userId: string): Promise + { + + const users = await this.getAll(); + const existingUser = users.find(u => u.id === userId); + + if (existingUser) { + return existingUser; + } + + const newUser: UserItem = { + id: userId, + best_score: 0, + total_score: 0, + max_tile: 0, + lastPlayed: null, + partiesCount: 0 + }; + + users.push(newUser); + await this.saveAll(users); + + return newUser; + + } + + + private async saveAll(users: UserItem[]): Promise + { + try { + await writeFile(this.dbPath, JSON.stringify(users, null, 2), 'utf-8'); + } catch (error) { + console.error("Erreur écriture 2048.json:", error); + } + } + +} + +export default new GameManager(); + +export { + type UserItem +}; \ No newline at end of file diff --git a/src/assets/ts/db/db.silvernote.ts b/src/assets/ts/db/db.silvernote.ts new file mode 100644 index 0000000..ce456e0 --- /dev/null +++ b/src/assets/ts/db/db.silvernote.ts @@ -0,0 +1,43 @@ +import nodeFetch from 'node-fetch'; + + + +async function fetch( + path: string, + opt: { + method?: 'POST' | 'GET' | 'DELETE', + body?: string + } = { method: 'GET' } +): Promise { + + try { + + const res = await nodeFetch('https://db.silvernote.fr' + path, { + method: opt.method || 'GET', + body: opt.body, + headers: { + "Authorization": process.env.DB_API_SK_1 || "", + "X-API-Key": process.env.DB_API_SK_2 || "", + "Content-Type": "application/json" + }, + }); + + if (!res.ok) { + const errorText = await res.text(); + console.error(`Erreur API ${res.status} : `, errorText); + return null; + } + + return await res.json(); + + } catch (error) { + console.error("Erreur réseau/fetch:", error); + return null; + } + +} + + +export { + fetch +} \ No newline at end of file diff --git a/src/assets/ts/db/notifications.ts b/src/assets/ts/db/notifications.ts new file mode 100644 index 0000000..46171d5 --- /dev/null +++ b/src/assets/ts/db/notifications.ts @@ -0,0 +1,143 @@ +import { randomUUID, type UUID } from 'crypto'; +import { readFile, writeFile } from 'fs/promises'; +import path from 'path'; +import fs from 'fs'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + + +interface Btn { + text: string; + action: string, // () => void + type: 'default-primary' | 'primary' | 'primary danger' +}; + +interface NotificationItem { + id: UUID; + title: string; + content: string; // md format + date: Date; + readBy: string[]; + forUserId: string[]; + btns?: Btn[]; +} + +export class NotificationManager +{ + + private dbPath: string; + + constructor() { + this.dbPath = path.join(__dirname, '../../../', 'db', 'notifications.json'); + if (!fs.existsSync(this.dbPath)) fs.writeFileSync(this.dbPath, JSON.stringify([]), 'utf-8'); + } + + /** + * Read all notifications from the JSON file + */ + private async getAll(): Promise + { + + try { + + const data = await readFile(this.dbPath, 'utf-8'); + const parseData: NotificationItem[] = JSON.parse(data); + + return parseData.map((n: any) => ({ + ...n, + date: new Date(n.date) + })); + + } + catch (error) { + return []; + } + + } + + /** + * Save all notifications to the JSON file + */ + private async save(notifications: NotificationItem[]): Promise + { + await writeFile(this.dbPath, JSON.stringify(notifications, null, 2), 'utf-8'); + } + + /** + * Get notifications for a specific user + */ + public async getForUser(userId: string): Promise + { + const all = await this.getAll(); + return all.filter(n => n.forUserId.includes(userId)); + } + + /** + * Count unread notifications for today for a specific user + */ + public async countTodayUnread(userId: string): Promise + { + + const all = await this.getAll(); + const today = new Date().toLocaleDateString(); + + return all.filter(n => + n.forUserId.includes(userId) && + !n.readBy.includes(userId) && + new Date(n.date).toLocaleDateString() === today + ).length; + + } + + /** + * Add a new notification + */ + public async add(notif: Omit): Promise + { + + const all = await this.getAll(); + const newNotif: NotificationItem = { + ...notif, + id: randomUUID(), + date: new Date(), + readBy: [] + }; + + all.push(newNotif); + await this.save(all); + return newNotif; + + } + + /** + * Mark a notification as read + */ + public async markAsRead(id: string, user_id: string): Promise + { + + const all = await this.getAll(); + const index = all.findIndex(n => n.id === id); + + if (index !== -1) { + if (all[index].readBy.includes(user_id)) return; + all[index].readBy.push(user_id); + await this.save(all); + } + + } + + public async getByUserId(userId: string): Promise + { + const all = await this.getAll(); + return all.filter(n => n.forUserId.includes(userId)); + } + +} + +export default new NotificationManager(); + +export { + type NotificationItem +} \ No newline at end of file diff --git a/src/assets/ts/db/userDB.ts b/src/assets/ts/db/userDB.ts new file mode 100644 index 0000000..6637a5e --- /dev/null +++ b/src/assets/ts/db/userDB.ts @@ -0,0 +1,11 @@ +import https from 'https'; + +const dbAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + timeout: 60000 +}); + +export { + dbAgent +} \ No newline at end of file diff --git a/src/assets/ts/news.ts b/src/assets/ts/news.ts new file mode 100644 index 0000000..93bb021 --- /dev/null +++ b/src/assets/ts/news.ts @@ -0,0 +1,69 @@ +import fs from 'fs'; +import path from 'path'; +import __dirname from './_dirname.js'; +import { UUID } from 'crypto'; + +interface NewsItem { + id: UUID; + title: string; + content: string; // md format + readBy: string[]; + date: Date; +} + +const newsFilePath = path.join(__dirname, '../../', 'db', 'news.json'); + + +class News +{ + + constructor() + { + if (!fs.existsSync(newsFilePath)) { + fs.writeFileSync(newsFilePath, JSON.stringify([], null, 2), 'utf-8'); + } + } + + private getNewsFile (): NewsItem[] + { + return JSON.parse(fs.readFileSync(newsFilePath, 'utf-8')); + } + + private async saveNewsFile (news: NewsItem[]): Promise + { + await fs.promises.writeFile(newsFilePath, JSON.stringify(news, null, 2), 'utf-8'); + } + + public getAllNews (): NewsItem[] + { + return this.getNewsFile(); + } + + public getLastNews (count: number): NewsItem[] + { + const news = this.getNewsFile(); + return news.slice(0, count); + } + + public async markNewsAsRead (newsId: string, userId: string): Promise + { + + const news = this.getNewsFile(); + const index = news.findIndex(n => n.id === newsId); + + if (index !== -1) { + if (news[index].readBy.includes(userId)) return; + news[index].readBy.push(userId); + console.log(`User ${userId} marked news ${newsId} as read, ${news[index].readBy.length} total reads.`); + await this.saveNewsFile(news); + } + + } + +} + +export default new News(); + +export { + type NewsItem +} \ No newline at end of file diff --git a/src/assets/ts/notes.ts b/src/assets/ts/notes.ts index ec3c28d..e3fcd9d 100644 --- a/src/assets/ts/notes.ts +++ b/src/assets/ts/notes.ts @@ -1,7 +1,9 @@ import nodeFetch from 'node-fetch'; import type { Note } from "./types.js"; import { randomUUID } from "crypto"; +import { dbAgent } from './db/userDB.js'; import 'dotenv/config'; +import { decrypt, encrypt } from './utils/scrypto/scrypto.js'; class Notes { @@ -31,9 +33,10 @@ import 'dotenv/config'; try { - const res = await nodeFetch('https://db.silvernote.fr/notes' + path, { + const res = await nodeFetch('https://db.silvernote.fr/v2/notes' + path, { method: opt.method || 'GET', body: opt.body, + agent: dbAgent, headers: { "Authorization": process.env.DB_API_SK_1 || "", "X-API-Key": process.env.DB_API_SK_2 || "", @@ -60,11 +63,18 @@ import 'dotenv/config'; if (!note.user_id) return { error: true, message: "user_id requis" }; note.uuid = note.uuid || randomUUID(); - note.created_at = note.created_at || Date.now(); + note.created_at = Date.now(); + + const noteToStore = { ...note }; + if (noteToStore.content) + { + noteToStore.content = encrypt(noteToStore.content, note.user_id); + noteToStore.content_type = "text/html/crypted"; + } const res = await this.fetch('/push', { method: 'POST', - body: JSON.stringify({ note }) + body: JSON.stringify({ note: noteToStore }) }) return { success: res?._id ? true : false, note }; @@ -72,25 +82,177 @@ import 'dotenv/config'; } - public async getNoteByUUID(uuid: string) { + public async getNoteByUUID(uuid: string, userId: string) { + + const res: Note[] = await this.fetch(`/user/${userId}/id/${uuid}`).then(res => res.notes); + + const note: Note = res[0]; + + if (note && note.uuid) + { + + if (note.content_type === "text/html/crypted" && note.content) + { + + if (note.content && note.content.includes(':')) + { + + try { + note.content = decrypt(note.content, note.user_id); + return { success: true, note }; + } + catch (e) { + console.error("Error on decrypting note : ", note.uuid); + return { success: false, error: true, message: "Error on decrypting note" }; + } + + } + + } + else + { + return { success: true, note }; + } + + } + else + { + return { error: true, message: "Note introuvable" }; + } + + return { error: true, message: "Note introuvable" }; + + } + + public async getNoteByUUIDNoUserID(uuid: string) { - const res: Note[] = await this.fetch(`/get/${uuid}`); + const res: Note[] = await this.fetch(`/user/justID/id/${uuid}`).then(res => res.notes); const note: Note = res[0]; if (note && note.uuid) { - return { success: true, note }; + + if (note.content_type === "text/html/crypted" && note.content) + { + + if (note.content && note.content.includes(':')) + { + + try { + note.content = decrypt(note.content, note.user_id); + return { success: true, note }; + } + catch (e) { + console.error("Error on decrypting note : ", note.uuid); + return { success: false, error: true, message: "Error on decrypting note" }; + } + + } + + } + else + { + return { success: true, note }; + } + + } + else + { + return { error: true, message: "Note introuvable" }; + } + + return { error: true, message: "Note introuvable" }; + + } + + public async getPinnedNotesByUserID (user_id: string) + { + + const notes: Note[] = await this.fetch(`/user/${user_id}/pinned`).then(res => res.notes); + const decryptedNotes: Note[] = []; + + for (const note of notes) + { + + if (note.content_type === "text/html/crypted" && note.content) + { + + try { + note.content = decrypt(note.content, note.user_id); + decryptedNotes.push(note); + } catch (e) { + console.error("Error on decrypting note : ", note.uuid); + } + + } + else + { + decryptedNotes.push(note); + } + } - else return { error: true, message: "Note introuvable" }; + return { success: true, notes: decryptedNotes }; } public async getNoteByUserId(user_id: string) { - const notes: Note[] = await this.fetch(`/get/byuserid/${user_id}`); + const notes: Note[] = await this.fetch(`/user/${user_id}`).then(res => res.notes); + const decryptedNotes: Note[] = []; + + for (const note of notes) + { + + if (note.content_type === "text/html/crypted" && note.content) + { + + try { + note.content = decrypt(note.content, note.user_id); + decryptedNotes.push(note); + } catch (e) { + console.error("Error on decrypting note : ", note.uuid); + } + + } + else + { + decryptedNotes.push(note); + } + + } - return { success: true, notes }; + return { success: true, notes: decryptedNotes }; + + } + + public async getNoteByUserIdIndex(user_id: string, start: number, end: number, noPinned?: '1' | '0') { + + const res = await this.fetch(`/user/${user_id}/index/start/${start}/end/${end}?noPinned=${noPinned}`); + const decryptedNotes: Note[] = []; + + for (const note of res.notes) + { + + if (note.content_type === "text/html/crypted" && note.content) + { + + try { + const decryptedContent = decrypt(note.content, note.user_id); + decryptedNotes.push({ ...note, content: decryptedContent }); + } catch (e) { + console.error("Error on decrypting note : ", note.uuid); + } + + } + else + { + decryptedNotes.push(note); + } + + } + + return { ...res, success: true, notes: decryptedNotes }; } @@ -99,25 +261,32 @@ import 'dotenv/config'; if (!note.uuid || !note.user_id) { return { error: true, message: "uuid et user_id requis" }; } + + const noteToStore = { ...note }; + if (noteToStore.content) + { + noteToStore.content = encrypt(noteToStore.content, note.user_id); + noteToStore.content_type = "text/html/crypted"; + } const res = await this.fetch('/update', { method: "POST", - body: JSON.stringify({ note }) + body: JSON.stringify({ note: noteToStore }) }); if (res.error) { - return { error: true, message: "erreur", res }; + return { error: true, message: "erreur", ...res }; } if (res.uuid) { - return { success: true, note }; + return { success: true, ...res }; } return { error: true, message: "réponse inattendue", res }; } public async clearUserNotes(user_id: string) { - await this.fetch('/delete/byuserid/' + user_id, { + await this.fetch('/delete/user/' + user_id, { method: 'DELETE' }) return { success: true }; @@ -125,7 +294,7 @@ import 'dotenv/config'; public async deleteNoteByUUID(user_id: string, uuid: string) { - const res = await this.fetch('/delete/' + uuid, { + const res = await this.fetch(`/delete/user/${user_id}/id/${uuid}`, { method: "DELETE" }) diff --git a/src/assets/ts/tags.ts b/src/assets/ts/tags.ts index a1f9765..c6bc112 100644 --- a/src/assets/ts/tags.ts +++ b/src/assets/ts/tags.ts @@ -1,6 +1,7 @@ import nodeFetch from 'node-fetch'; import type { Tag } from "./types.js"; import { randomUUID } from "crypto"; +import { dbAgent } from './db/userDB.js'; class Tags { @@ -34,6 +35,7 @@ import { randomUUID } from "crypto"; { const res = await nodeFetch('https://db.silvernote.fr/tags' + path, { ...opt, + agent: dbAgent, headers: { "Authorization": process.env.DB_API_SK_1 || "", "X-API-Key": process.env.DB_API_SK_2 || "", diff --git a/src/assets/ts/types.ts b/src/assets/ts/types.ts index efc51a3..558d16c 100644 --- a/src/assets/ts/types.ts +++ b/src/assets/ts/types.ts @@ -4,17 +4,10 @@ import { Plan } from "./plan.js"; export interface User { userId: string; customerId?: string; + androidToken?: string; plan: Plan[]; }; -export interface News { - active: boolean; - message: string; - title: string; - btn: boolean; - href: string; -}; - export interface Layout { all: number; file: number; @@ -31,6 +24,7 @@ export interface Note { icon?: string; title: string; content: string; + content_type?: "text/plain" | "text/markdown" | "text/html" | "text/html/crypted"; tags?: string[]; pinned?: boolean; created_at?: number; diff --git a/src/assets/ts/utils/scrypto/scrypto.ts b/src/assets/ts/utils/scrypto/scrypto.ts new file mode 100644 index 0000000..1b5dcd9 --- /dev/null +++ b/src/assets/ts/utils/scrypto/scrypto.ts @@ -0,0 +1,86 @@ +import crypto from 'crypto'; + + +const rawKey = process.env.DB_ENCRYPTION_KEY; + +if (!rawKey || rawKey.length !== 64) { + throw new Error("La clé DB_ENCRYPTION_KEY doit faire 64 caractères hexadécimaux (32 octets)."); +} + +const MASTER_KEY = Buffer.from(rawKey, 'hex'); +const ALGORITHM = 'aes-256-gcm'; + + +function getUserKey(userId: string): Buffer +{ + + const derivedKey = crypto.hkdfSync( + 'sha256', + MASTER_KEY, + Buffer.alloc(0), // Salt + `user-key-${userId}`, // Info + 32 // Longueur + ); + + return Buffer.from(derivedKey); + +}; + +function getUserFingerprint(userId: string): string { + const userKey = getUserKey(userId); + return crypto.createHash('sha256') + .update(Buffer.from(userKey)) + .digest('hex') + .toUpperCase() + .match(/.{1,4}/g)! + .slice(0, 8) + .join('-'); +} + + +function encrypt(text: string, userId: string) +{ + + const userKey = getUserKey(userId); + + // generate random iv and cipher + const iv = crypto.randomBytes(12); + const cipher = crypto.createCipheriv(ALGORITHM, userKey, iv); + + // encrypt the text + let encrypted = cipher.update(text, 'utf8', 'hex'); + encrypted += cipher.final('hex'); + const authTag = cipher.getAuthTag().toString('hex'); + + // return iv, authTag and encrypted text concatenated + return `${iv.toString('hex')}:${authTag}:${encrypted}`; + +} + +function decrypt(data: string, userId: string) +{ + + const userKey = getUserKey(userId); + + // split the data into its components + const [ivHex, authTagHex, encryptedText] = data.split(':'); + const decipher = crypto.createDecipheriv( + ALGORITHM, + userKey, + Buffer.from(ivHex, 'hex') + ); + decipher.setAuthTag(Buffer.from(authTagHex, 'hex')); + + // decrypt the text + let decrypted = decipher.update(encryptedText, 'hex', 'utf8'); + decrypted += decipher.final('utf8'); + + return decrypted; + +} + +export { + encrypt, + decrypt, + getUserFingerprint +}; \ No newline at end of file diff --git a/src/express.ts b/src/express.ts index f2a7ec5..b461bda 100644 --- a/src/express.ts +++ b/src/express.ts @@ -26,6 +26,9 @@ import api_share from './routes/api.share.js'; import user from './routes/user.js'; import money from './routes/money.js'; import admin from './routes/admin.js'; +import resources from './routes/resources.js'; +import notifications from './routes/api.notifications.js'; +import api_2048 from './routes/api.2048.js'; const app = express(); const httpServer = createServer(app); @@ -80,12 +83,16 @@ app.use(clerkMiddleware()); // Routes app.use('/api', api); -app.use('/api/share', requireAuth(), api_share); -app.use('/api/ai', api_ai); app.use('/user', user); app.use('/admin', admin); app.use('/money', money); +app.use('/resources', resources); +// secured routes +app.use('/api/ai', requireAuth(), api_ai); +app.use('/api/share', requireAuth(), api_share); app.use('/api/db', requireAuth(), api_db); +app.use('/api/notifications', requireAuth(), notifications); +app.use('/api/2048', requireAuth(), api_2048); app.get('/version', (req, res) => { @@ -119,8 +126,8 @@ async function initializeMCP() { async function startServer() { await initializeMCP(); - httpServer.listen(config.PORT, () => { - console.log(`Serveur Express sur le port ${config.PORT}`); + httpServer.listen(process.env.PORT || config.PORT, () => { + console.log(`Serveur Express sur le port ${process.env.PORT || config.PORT}`); }); } diff --git a/src/mcp-server/src/tools/add_note_tag.ts b/src/mcp-server/src/tools/add_note_tag.ts index b9d6819..bb3c9a5 100644 --- a/src/mcp-server/src/tools/add_note_tag.ts +++ b/src/mcp-server/src/tools/add_note_tag.ts @@ -11,11 +11,12 @@ const add_note_tag: Tool = { params: { uuid: z.string().describe('note uuid'), tagId: z.string().describe('tag id'), + userId: z.string().describe('note owner id') }, handler: async (parms) => { - const note = (await notes.getNoteByUUID(parms.uuid)).note; + const note = (await notes.getNoteByUUID(parms.uuid, parms.userId)).note; if (!note) return { content: [ diff --git a/src/mcp-server/src/tools/edit_note_content.ts b/src/mcp-server/src/tools/edit_note_content.ts index 990b116..9fa6182 100644 --- a/src/mcp-server/src/tools/edit_note_content.ts +++ b/src/mcp-server/src/tools/edit_note_content.ts @@ -1,11 +1,6 @@ import { Tool } from "../../MCPTypes.js"; import useWS from "../utils/useWS.js"; import { z } from "zod"; -import * as Y from "yjs"; -import { JSDOM } from "jsdom"; -import schema from "../../../assets/ts/utils/getTiptapSchema/getTiptapSchema.js"; -import { DOMParser } from "prosemirror-model"; -import { prosemirrorToYXmlFragment } from "y-prosemirror"; const edit_note_content: Tool = { diff --git a/src/mcp-server/src/tools/get_note.ts b/src/mcp-server/src/tools/get_note.ts index b48a4e1..0040947 100644 --- a/src/mcp-server/src/tools/get_note.ts +++ b/src/mcp-server/src/tools/get_note.ts @@ -9,12 +9,13 @@ const get_note: Tool = { description: "Get note by UUID", params: { - uuid: z.string().describe('note uuid') + uuid: z.string().describe('note uuid'), + userId: z.string().describe('note owner id') }, handler: async (parms) => { - const note = (await notes.getNoteByUUID(parms.uuid)).note; + const note = (await notes.getNoteByUUID(parms.uuid, parms.userId)).note; return { content: [ diff --git a/src/package.json b/src/package.json index 1cbadca..00c0578 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "silvernote_back", - "version": "1.1.11-beta", + "version": "1.11.21-beta", "description": "", "main": "index.js", "scripts": { @@ -46,7 +46,6 @@ "socket.io": "^4.8.1", "socket.io-client": "^4.8.1", "stripe": "^18.3.0", - "typescript": "^5.8.3", "xmldom": "^0.6.0", "y-prosemirror": "^1.3.7", "y-protocols": "^1.0.6", diff --git a/src/routes/api.2048.ts b/src/routes/api.2048.ts new file mode 100644 index 0000000..a02118d --- /dev/null +++ b/src/routes/api.2048.ts @@ -0,0 +1,123 @@ +import { Router, Request, Response } from 'express'; +import GameManager from '../assets/ts/db/2048_db.js'; + + +const router = Router(); + + +router.post('/update', async (req: Request, res: Response) => { + + const data = req.body.data; + + if (!data || !data.id) + { + res.status(400).json({ + error: true, + message: "Données invalides", + received: req.body, + need: { + id: "string", + best_score: "number", + max_tile: "number", + lastPlayed: "Date", + } + }); + return; + } + + try { + + GameManager.update(data); + res.json({ success: true }); + + } + catch (error) { + res.status(500).json({ + error: true, + message: "Erreur serveur", + details: error + }); + } + +}); + + +router.get('/leaderboard', async (req: Request, res: Response) => { + + try { + + const allPlayers = await GameManager.getAll(); + + const sortedByBestScore = [...allPlayers].sort((a, b) => b.best_score - a.best_score); + const sortedByTotalScore = [...allPlayers].sort((a, b) => b.total_score - a.total_score); + const sortedByMaxTile = [...allPlayers].sort((a, b) => b.max_tile - a.max_tile); + + res.json({ + success: true, + leaderboard: { + best_score: sortedByBestScore, + total_score: sortedByTotalScore, + max_tile: sortedByMaxTile + } + }); + + } + catch (error) { + res.status(500).json({ + error: true, + message: "Erreur serveur", + details: error + }); + } + +}); + + +router.get('/player/:id', async (req: Request, res: Response) => { + + const playerId = req.params.id; + const userId = req.cookies.userId; + + if (playerId !== userId) + { + res.status(403).json({ + error: true, + message: "Accès refusé : vous ne pouvez accéder qu'à vos propres données", + playerId, + userId + }); + return; + } + + try { + + const playerData = await GameManager.getByUserID(playerId); + + if (!playerData) { + res.status(404).json({ + error: true, + message: "Joueur non trouvé", + playerId + }); + return; + } + + res.json({ + success: true, + player: playerData + }); + + } + catch (error) { + res.status(500).json({ + error: true, + message: "Erreur serveur", + details: error + }); + } + +}); + + + +export default router; diff --git a/src/routes/api.db.ts b/src/routes/api.db.ts index 5146463..46edb47 100644 --- a/src/routes/api.db.ts +++ b/src/routes/api.db.ts @@ -11,6 +11,8 @@ import axios from 'axios'; import FormData from "form-data"; import downloadFile from "../assets/ts/downloadFile.js"; import { fileURLToPath } from "url"; +import { getUserFingerprint } from "../assets/ts/utils/scrypto/scrypto.js"; +import { getAuth } from "@clerk/express"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -23,7 +25,7 @@ router.post('/verify/data', async (req: Request, res: Response) => { try { const { notes, tags } = req.body as { notes: string; tags: string }; // hash of notes and tags - const user_id: string | undefined = req.cookies?.user_id; + const user_id = getAuth(req).userId; if (!notes || !tags || !user_id) { res.json({ error: true, message: 'Missing parameters.' }); @@ -56,40 +58,59 @@ router.post('/verify/data', async (req: Request, res: Response) => { }); +router.get('/get/scrypto/fingerprint', async (req: Request, res: Response) => { + + const userId = getAuth(req).userId; + + const fingerprint = getUserFingerprint(userId!); + + res.json({ fingerprint }); + +}); + + // for notes router.post('/new/note', async (req: Request, res: Response) => { + const { userId } = getAuth(req); const note = req.body.note; - note.user_id = req.cookies.user_id; + note.user_id = userId; res.json(await note_db.createNote(note)); }); router.get('/get/a/note', async (req: Request, res: Response) => { - res.json(await note_db.getNoteByUUID(req.query.uuid as string)); + const user_id = getAuth(req).userId; + res.json(await note_db.getNoteByUUID(req.query.uuid as string, user_id!)); }); router.post('/update/a/note', async (req: Request, res: Response) => { const note = req.body.note; - note.user_id = req.cookies.user_id; + const user_id = getAuth(req).userId; + note.user_id = user_id; res.json(await note_db.updateNote(note)); }); router.post('/delete/a/note', async (req: Request, res: Response) => { - res.json(await note_db.deleteNoteByUUID(req.cookies.user_id, req.query.uuid as string)); + const user_id = getAuth(req).userId; + res.json(await note_db.deleteNoteByUUID(user_id!, req.query.uuid as string)); }); -router.get('/get/user/notes', async (req: Request, res: Response) => { +router.get('/notes/start/:start/end/:end', async (req: Request, res: Response) => { + + const noPinned = String(req.query?.noPinned || '0') as '1' | '0'; + const userId = String(getAuth(req).userId); + const start = Number(req.params.start); + const end = Number(req.params.end); - const userId = req.query.user_id as string; - const db_res = await note_db.getNoteByUserId(userId); + const db_res = await note_db.getNoteByUserIdIndex(userId, start, end, noPinned); res.json({ ...db_res, - notes: db_res.notes.filter(note => note.title !== '' || note.content !== '') + notes: db_res.notes }); // identify gost notes - const ghostNotes: Note[] = db_res.notes.filter(note => + const ghostNotes: Note[] = db_res.notes.filter((note: Note) => note.title === '' && note.content === '' || note.title === '' && note.content === '

' ); @@ -100,8 +121,22 @@ router.get('/get/user/notes', async (req: Request, res: Response) => { }); +router.get('/notes/pinned', async (req, res) => { + + const userId = String(getAuth(req).userId); + + const db_res = await note_db.getPinnedNotesByUserID(userId); + + res.json({ + ...db_res, + notes: db_res.notes + }); + +}) + router.post('/delete/notes', async (req: Request, res: Response) => { - res.json(await note_db.clearUserNotes(req.cookies.user_id)); + const user_id = getAuth(req).userId; + res.json(await note_db.clearUserNotes(user_id!)); }); @@ -109,18 +144,21 @@ router.post('/delete/notes', async (req: Request, res: Response) => { // for tags router.post('/new/tag', async (req: Request, res: Response) => { const tag = req.body.tag; - tag.user_id = req.cookies.user_id; + const user_id = getAuth(req).userId; + tag.user_id = user_id!; res.json(await tag_db.createTag(tag)); }); router.post('/update/a/tag', async (req: Request, res: Response) => { const tag = req.body.tag; - tag.user_id = req.cookies.user_id; + const user_id = getAuth(req).userId; + tag.user_id = user_id!; res.json(await tag_db.updateTag(tag)); }); router.post('/delete/a/tag', async (req: Request, res: Response) => { - res.json(await tag_db.deleteTagByUUID(req.cookies.user_id, String(req.query.uuid))); + const user_id = getAuth(req).userId; + res.json(await tag_db.deleteTagByUUID(user_id!, String(req.query.uuid))); }); router.get('/get/user/tags', async (req: Request, res: Response) => { @@ -128,7 +166,8 @@ router.get('/get/user/tags', async (req: Request, res: Response) => { }); router.post('/delete/tags', async (req: Request, res: Response) => { - res.json(await tag_db.clearUserTags(req.cookies.user_id)); + const user_id = getAuth(req).userId; + res.json(await tag_db.clearUserTags(user_id!)); }); diff --git a/src/routes/api.notifications.ts b/src/routes/api.notifications.ts new file mode 100644 index 0000000..04e09e6 --- /dev/null +++ b/src/routes/api.notifications.ts @@ -0,0 +1,115 @@ +import { Router, Request, Response } from 'express'; +import Notifications from '../assets/ts/db/notifications.js'; +import News from '../assets/ts/news.js'; +import database from '../assets/ts/database.js'; + + +const router = Router(); + +router.get('/', async (req: Request, res: Response) => { + + const client_userId = req.cookies.user_id; + + if (!client_userId) { + res.status(401).json({ error: true, message: 'UserId cookie not set' }); + return; + } + + const notif = await Notifications.getByUserId(client_userId); + const news = News.getAllNews(); + + let response = [ + ...notif, + ...news + ] + .filter(n => { + + const readers = n.readBy || []; + const isRead = readers.includes(client_userId); + + const notifDate = new Date(n.date).getTime(); + const now = new Date().getTime(); + const oneDayInMs = 24 * 60 * 60 * 1000; + const isOlderThanADay = (now - notifDate) > oneDayInMs; + + return !isRead || !isOlderThanADay; + + }) + .sort((a, b) => { + const dateA = new Date(a.date).getTime(); + const dateB = new Date(b.date).getTime(); + return dateB - dateA; + }); + + res.json(response); + +}); + +router.post('/mark-read/:id', async (req: Request, res: Response) => { + + const client_userId = req.cookies.user_id; + + if (!client_userId) { + res.status(401).json({ error: true, message: 'UserId cookie not set' }); + return; + } + + const notifId: string = req.params.id; + + await Promise.all([ + Notifications.markAsRead(notifId, client_userId), + News.markNewsAsRead(notifId, client_userId) + ]); + + res.json({ success: true }); + +}); + + +// android notifications + +router.post('/android/register', async (req: Request, res: Response) => { + + const client_userId = req.cookies.user_id; + const { fcm_token } = req.body; + + if (!client_userId) { + res.status(401).json({ error: true, message: 'UserId cookie not set' }); + return; + } + + if (!fcm_token) { + res.status(400).json({ error: true, message: 'fcm_token is required' }); + return; + } + + await database.setAndroidToken(client_userId, fcm_token); + + res.json({ success: true }); + +}); + +router.post('/android/unregister', async (req: Request, res: Response) => { + + const client_userId = req.cookies.user_id; + const { fcm_token } = req.body; + + if (!client_userId) { + res.status(401).json({ error: true, message: 'UserId cookie not set' }); + return; + } + + if (!fcm_token) { + res.status(400).json({ error: true, message: 'fcm_token is required' }); + return; + } + + await database.setAndroidToken(client_userId, 'none'); + + res.json({ success: true }); + +}); + + + +export default router; diff --git a/src/routes/api.share.ts b/src/routes/api.share.ts index 5327900..a63774d 100644 --- a/src/routes/api.share.ts +++ b/src/routes/api.share.ts @@ -2,6 +2,7 @@ import { Router } from 'express'; import type { Note } from '../assets/ts/types.js'; import notes from '../assets/ts/notes.js'; import Share from '../assets/ts/db/share/index.js'; +import { getAuth } from '@clerk/express'; const router = Router(); @@ -11,7 +12,8 @@ router.get('/:uuid', async (req, res) => { const { uuid } = req.params; const passwd = req.query.passwd; - const visitor_userid = req.cookies.user_id; + const visitor_userid = getAuth(req).userId; + if (!visitor_userid) return; const TheShare = await Share.get(uuid); @@ -36,13 +38,13 @@ router.get('/:uuid', async (req, res) => { const now = Date.now(); const isExpired: boolean = now - createdTime > TheShare.params.age; - if (TheShare.params.age !== -1 &&isExpired) { + if (TheShare.params.age !== -1 && isExpired) { Share.delete(uuid); res.json({ expired: isExpired }); return; } - const note = await notes.getNoteByUUID(TheShare.note_uuid); + const note = await notes.getNoteByUUID(TheShare.note_uuid, TheShare.owner_id); res.json({ success: true, @@ -67,10 +69,19 @@ router.get('/:uuid/info', async (req, res) => { const _share = await Share.get(uuid); - res.json({ + if (!_share) { + res.json({ success: false, error: true, message: 'Partage non trouvée.' }); + return; + } + + res.json({ + success: true, share: { ..._share, - params: {} + params: { + ..._share.params, + passwd: _share.params.passwd ? true : false + } } }); return; @@ -80,10 +91,16 @@ router.get('/:uuid/info', async (req, res) => { router.post('/create', async (req, res) => { const { note_uuid, params } = req.body; - const user_id = req.cookies.user_id; + const user_id = getAuth(req).userId; try { + if (!user_id || !note_uuid || !params) + { + res.json({ error: true, message: 'Missing parameters.' }); + return; + } + if (await Share.get(note_uuid)) { await Share.delete(note_uuid); } @@ -93,7 +110,7 @@ router.post('/create', async (req, res) => { owner_id: user_id, } - const TheShare = await Share.add({ + await Share.add({ uuid: note_uuid, owner_id: user_id, @@ -101,7 +118,7 @@ router.post('/create', async (req, res) => { params, - created_at: new Date().toString(), + created_at: new Date().toISOString(), expires_at: "", visitor: [], @@ -121,9 +138,10 @@ router.post('/create', async (req, res) => { }) -router.post('/ban', async (req, res) => { +router.post('/:uuid/ban', async (req, res) => { - const { uuid, banned_id } = req.body; + const { banned_id } = req.body; + const uuid = req.params.uuid; try { @@ -153,9 +171,62 @@ router.post('/ban', async (req, res) => { }) +router.post('/:uuid/update', async (req, res) => { + + const { share } = req.body; + const uuid = req.params.uuid; + + + try { + + const TheShare = await Share.get(uuid); + + if (TheShare) { + + const updatedShare = { ...TheShare, ...share, params: { passwd: TheShare.params.passwd, ...share.params } }; + + await Share.update(updatedShare!); + + res.json({ success: true, share: updatedShare }); + return; + + } + + res.json({ success: false }); + return; + + } + + catch (err) { + res.status(500).json({ error: true, message: err }); + return; + } + +}) + +router.post('/:uuid/delete', async (req, res) => { + + const uuid = req.params.uuid; + + try { + + await Share.delete(uuid); + + res.json({ success: true }); + + } + catch (err) { + res.status(500).json({ error: true, message: err }); + return; + } + +}) + + router.get('/for/me', async (req, res) => { - const { user_id } = req.cookies; + const user_id = getAuth(req).userId; + if (!user_id) return; try { @@ -176,7 +247,7 @@ router.get('/for/me', async (req, res) => { for (const share of share_for_me) { - const note: Note | undefined = (await notes.getNoteByUUID(share.note_uuid)).note; + const note: Note | undefined = (await notes.getNoteByUUID(share.note_uuid, user_id)).note; if (!note) continue; shared_notes.push(note); @@ -206,7 +277,8 @@ router.get('/for/me', async (req, res) => { router.get('/by/me', async (req, res) => { - const user_id = req.cookies.user_id || req.signedCookies.user_id; + const user_id = getAuth(req).userId; + if (!user_id) return; try { @@ -218,7 +290,8 @@ router.get('/by/me', async (req, res) => { for (const share of my_share) { - const __note = await notes.getNoteByUUID(share.note_uuid); + const __note = await notes.getNoteByUUID(share.note_uuid, user_id); + console.log(share) if (!__note.note) continue; _notes.push(__note.note); } diff --git a/src/routes/api.ts b/src/routes/api.ts index 4b0efaf..6289a01 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -1,27 +1,16 @@ import { Router, Request, Response } from 'express'; -import fs from 'fs'; -import type { News } from '../assets/ts/types.js'; import { clerkClient } from "@clerk/express"; -import { randomUUID } from 'crypto'; +import { randomUUID, UUID } from 'crypto'; const router = Router(); -router.get('/get_news', async (req: Request, res: Response) => { - - const data = await fs.promises.readFile(process.env.CONFIG_PATH || './dist/config.json', 'utf-8'); // remettre ./config pour prod - const news: Promise = JSON.parse(data).news; - - res.json( (await news).active ? news : false ); - -}) - -router.get('/uuid', (req, res) => { +router.get('/uuid', (req: Request, res: Response) => { res.json({ id: randomUUID() }) }) -router.get('/user/by/id/:userid', async (req, res) => { +router.get('/user/by/id/:userid', async (req: Request, res: Response) => { const userid: string = req.params.userid; const client_userId = req.cookies.user_id; @@ -37,5 +26,4 @@ router.get('/user/by/id/:userid', async (req, res) => { }) - export default router; diff --git a/src/routes/resources.ts b/src/routes/resources.ts new file mode 100644 index 0000000..f57596c --- /dev/null +++ b/src/routes/resources.ts @@ -0,0 +1,117 @@ +import { Router, Request, Response } from 'express'; +import { fetch } from '../assets/ts/db/db.silvernote.js'; +import { clerkClient } from '@clerk/clerk-sdk-node'; +import nodeFetch from 'node-fetch'; + + +const router = Router(); + + +router.get('/test', async (req: Request, res: Response) => { + res.json({ test: true }); +}) + + +router.get('/db/length', async (req: Request, res: Response) => { + + const notesLength = await fetch('/notes/length'); + const tagsLength = await fetch('/tags/length'); + + res.json({ + notes: notesLength, + tags: tagsLength + }); + +}) + + +router.get('/clerk/users/length', async (req: Request, res: Response) => { + + const data = await clerkClient.users.getCount() + + res.json({ + users: data || null + }); + +}); + + + +router.get('/status/sites', async (req: Request, res: Response) => { + + try { + + const apiKey = process.env.CRONITOR_API_KEY; + + if (!apiKey) { + throw new Error('Missing CRONITOR_API_KEY in environment'); + } + + const auth = Buffer.from(`${apiKey}:`).toString('base64'); + + const response = await nodeFetch('https://cronitor.io/api/monitors', { + method: 'GET', + headers: { + 'Authorization': `Basic ${auth}`, + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + throw new Error(`Cronitor API responded with ${response.status}`); + } + + const data = await response.json(); + + const sites = data.monitors.map((m: any) => { + + const latest = m.latest_event || {}; + const ssl = m.attributes?.site?.ssl || {}; + + return { + + key: m.key, + name: m.name.replace(/\(.*\)/, '').trim(), + url: m.request?.url, + is_online: m.passing && !m.paused, + status: m.paused ? 'paused' : (m.passing ? 'operational' : 'degraded'), + + // Métriques de performance + metrics: { + latency: latest.metrics?.duration ? Math.round(latest.metrics.duration * 1000) : null, // ms + last_check_region: latest.host || 'N/A', + last_check_at: m.latest_event?.stamp ? new Date(m.latest_event.stamp * 1000).toISOString() : null + }, + + // Sécurité (Très utile pour prévenir plutôt que guérir) + ssl: { + expires_at: ssl.expires_at || null, + is_valid: ssl.expires_at ? new Date(ssl.expires_at) > new Date() : false, + provider: ssl.issued_by || 'Unknown' + }, + + // Configuration + schedule: m.schedule, + badge: m.public_badge_url + + }; + + }); + + res.json({ + success: true, + data: sites + }); + + } catch (error: any) { + console.error('Error fetching Cronitor status:', error.message); + res.status(500).json({ + success: false, + error: error.message + }); + } + +}); + + +export default router; diff --git a/src/routes/user.ts b/src/routes/user.ts index 0bad1a7..8cc2a3f 100644 --- a/src/routes/user.ts +++ b/src/routes/user.ts @@ -9,7 +9,6 @@ import { User } from '../assets/ts/types.js'; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); - // route de gestion de plan router.post('/plan/set', async (req: Request, res: Response) => { diff --git a/src/ws.ts b/src/ws.ts index c10b284..d4fc6d1 100644 --- a/src/ws.ts +++ b/src/ws.ts @@ -8,6 +8,7 @@ import __dirname from "./assets/ts/_dirname.js"; const config = JSON.parse(fs.readFileSync(path.join(__dirname, '../../config.json'), 'utf-8')) import notes from "./assets/ts/notes.js"; import { Note } from "./assets/ts/types.js"; +import Share from "./assets/ts/db/share/Share.js"; const httpServer = createServer(); @@ -18,8 +19,9 @@ const save_note = async (note: Note): Promise => { }); } + const get_note = async (uuid: string): Promise => { - const res = await notes.getNoteByUUID(uuid); + const res = await notes.getNoteByUUIDNoUserID(uuid); if (res.note) return res.note; } @@ -45,7 +47,7 @@ io.on("connection", (socket) => { // Stocker la room du socket pour l'utiliser dans les autres événements let currentRoom: string | null = null; - socket.on("join-room", async ({ room, userId }: { room: string, userId?: string }) => { + socket.on("join-room", async ({ room, userId }: { room: string, userId: string }) => { if (!room) return; @@ -53,10 +55,12 @@ io.on("connection", (socket) => { socket.join(room); let docData = docs.get(room); + const share = await Share.get(room); + + if (!docData) + { - if (!docData) { const ydoc = new Y.Doc(); - const fragment = ydoc.getXmlFragment("prosemirror"); const awareness = new awarenessProtocol.Awareness(ydoc); const note = await get_note(room); @@ -69,6 +73,7 @@ io.on("connection", (socket) => { docs.set(room, { ydoc, awareness, saveInterval, title, icon }); docData = { ydoc, awareness, saveInterval, title, icon }; + } const { ydoc, awareness } = docData; @@ -80,9 +85,12 @@ io.on("connection", (socket) => { socket.emit("title-update", docData.title); socket.emit("icon-update", docData.icon); - if (userId) { + if (userId) + { + if (share && userId == share.owner_id) return; socket.emit('new_user', userId); } + }); socket.on("y-update", async (update: Uint8Array | number[]) => {