From e4d0d1731f5b9667f2abb1fa35923b3e0692179e Mon Sep 17 00:00:00 2001 From: intwocave Date: Tue, 22 Jul 2025 14:11:37 +0900 Subject: [PATCH 001/130] [init] initial commit --- .gitignore | 1 + README.md | 1 + main.js | 117 +++++++++++++++++++++++++++++++++++++ package-lock.json | 6 ++ package.json | 13 +++++ services/ArticleService.js | 78 +++++++++++++++++++++++++ services/ProductService.js | 83 ++++++++++++++++++++++++++ 7 files changed, 299 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 main.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 services/ArticleService.js create mode 100644 services/ProductService.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..40b878db5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..0da20315f --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Codeit Sprint Misson 2 \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 000000000..32b7b78d1 --- /dev/null +++ b/main.js @@ -0,0 +1,117 @@ +import articleService from './services/ArticleService.js'; +import productService from './services/ProductService.js'; + +class Product { + name; + description; + price; + tags; + images; + favoriteCount; + + constructor(name, description, price, tags, images, favoriteCount=0) { + this.name = name; + this.description = description; + this.price = price; + this.tags = tags; + this.images = images; + this.favoriteCount = favoriteCount; + } + + favorite() { + this.favoriteCount++; + } +} + +class ElectronicProduct extends Product { + manufacturer; + + constructor(name, description, price, tags, images, favoriteCount=0, manufacturer) { + super(name, description, price, tags, images, favoriteCount=0); + this.manufacturer = manufacturer; + } +} + +class Article { + title; + content; + writer; + likeCount; + createdAt; + + constructor(title, content, writer, likeCount=0) { + this.title = title; + this.content = content; + this.writer = writer; + this.likeCount = likeCount; + this.createdAt = new Date().toISOString(); + } + + like() { + this.likeCount++; + } +} + +let products = []; + + +let res = 0; + +// Test code for getProductList method +const productList = await productService.getProductList(); +for (const product of productList.list) { + // console.log(product); + if (product.tags.includes('전자제품')) { + // console.log('전자제품 태그 포함됨'); + products.push(new ElectronicProduct( + product.name, + product.description, + product.price, + product.tags, + product.images, + product.favoriteCount, + product.manufacturer + )); + } else { + products.push(new Product( + product.name, + product.description, + product.price, + product.tags, + product.images, + )); + } +} +// console.log(products); + + +// Test code for getProduct method +// res = await productService.getProduct(9); +// console.log(res); + + +// Test code for createProduct method +/* res = await productService.createProduct( + 'dragon', + 'myDragonDesc', + 9999, + ['dragon', ], + ['https://myImages', ], +) +console.log(res); */ + + +// Test code for patchProduct method +/* res = await productService.patchProduct({ + productId: 1195, + name: 'modifiedDragon', + description: 'modifiedDesc', + price: 1111, + tags: ['kirakira', ], +}); +console.log(res); */ + + +// Test code for deleteProduct method +/* res = await productService.deleteProduct(1195); +console.log(res); */ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..aee9846c5 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "sprint_misson_2", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..8716dddc7 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "sprint_mission_2", + "version": "1.0.0", + "description": "", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "module" +} diff --git a/services/ArticleService.js b/services/ArticleService.js new file mode 100644 index 000000000..11e13160d --- /dev/null +++ b/services/ArticleService.js @@ -0,0 +1,78 @@ +import axios from 'axios'; + +const apiUrl = 'https://panda-market-api-crud.vercel.app'; + +function getArticleList(page, pageSize, keyword) { + axios.get(apiUrl+'/articles', { + page, + pageSize, + keyword + }) + .then(res => { + // console.log(res.data) + return res.data; + }) + .catch(e => { + console.error(e); + }) +} + +function getArticle(articleId) { + axios.get(apiUrl+`/articles/${articleId}`) + .then(res => { + // console.log(res.data) + return res.data; + }) + .catch(e => { + console.error(e); + }); +} + +function createArticle(title, content, image) { + axios.post(apiUrl+`/articles`, { + title, + content, + image + }) + .then(res => { + // console.log(res.data) + return res.data; + }) + .catch(e => { + console.error(e); + }); +} + +function patchArticle(articleId, title, content, image) { + axios.patch(apiUrl+`/articles/${articleId}`, { + title, + content, + image + }) + .then(res => { + // console.log(res.data) + return res.data; + }) + .catch(e => { + console.error(e); + }); +} + +function deleteArticle(articleId) { + axios.delete(apiUrl+`/articles/${articleId}`) + .then(res => { + // console.log(res.data) + return res.data; + }) + .catch(e => { + console.error(e); + }); +} + +export default { + getArticleList, + getArticle, + createArticle, + patchArticle, + deleteArticle +}; \ No newline at end of file diff --git a/services/ProductService.js b/services/ProductService.js new file mode 100644 index 000000000..159ed2629 --- /dev/null +++ b/services/ProductService.js @@ -0,0 +1,83 @@ +import axios from 'axios'; + +const apiUrl = 'https://panda-market-api-crud.vercel.app'; + +async function getProductList(page, pageSize, keyword) { + try { + const res = await axios.get(apiUrl+'/products', { + page, + pageSize, + keyword + }); + + // console.log(res.data); + return res.data; + } catch (e) { + console.error(e); + } +}; + +async function getProduct(productId) { + try { + const res = await axios.get(apiUrl+`/products/${productId}`) + + // console.log(res.data); + return res.data; + } catch (e) { + console.error(e); + } +}; + +async function createProduct(name, description, price, tags, images) { + try { + const res = await axios.post(apiUrl+'/products', { + name, // String + description, // String + price, // Number + tags, // Arrays of string + images, // Arrays of string + }); + + // console.log(res.data); + return res.data; + } catch (e) { + console.error(e); + return e; + } +}; + +async function patchProduct( { productId, name, description, price, tags, images } ) { + try { + const res = await axios.patch(apiUrl+`/products/${productId}`, { + name, + description, + price, + tags, + images, + }); + + // console.log(res.data); + return res.data; + } catch (e) { + console.error(e); + } +}; + +async function deleteProduct(productId) { + try { + const res = await axios.delete(apiUrl+`/products/${productId}`) + + // console.log(res.data); + return res.data; + } catch (e) { + console.error(e); + } +}; + +export default { + getProductList, + getProduct, + createProduct, + patchProduct, + deleteProduct +}; \ No newline at end of file From 181c2c374a31a76bb2565ae377668c7ddf0f7fd0 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 09:21:22 +0900 Subject: [PATCH 002/130] [chore] move all files into mission_2 dir --- README.md => mission_2/README.md | 0 main.js => mission_2/main.js | 0 package-lock.json => mission_2/package-lock.json | 0 package.json => mission_2/package.json | 0 {services => mission_2/services}/ArticleService.js | 0 {services => mission_2/services}/ProductService.js | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename README.md => mission_2/README.md (100%) rename main.js => mission_2/main.js (100%) rename package-lock.json => mission_2/package-lock.json (100%) rename package.json => mission_2/package.json (100%) rename {services => mission_2/services}/ArticleService.js (100%) rename {services => mission_2/services}/ProductService.js (100%) diff --git a/README.md b/mission_2/README.md similarity index 100% rename from README.md rename to mission_2/README.md diff --git a/main.js b/mission_2/main.js similarity index 100% rename from main.js rename to mission_2/main.js diff --git a/package-lock.json b/mission_2/package-lock.json similarity index 100% rename from package-lock.json rename to mission_2/package-lock.json diff --git a/package.json b/mission_2/package.json similarity index 100% rename from package.json rename to mission_2/package.json diff --git a/services/ArticleService.js b/mission_2/services/ArticleService.js similarity index 100% rename from services/ArticleService.js rename to mission_2/services/ArticleService.js diff --git a/services/ProductService.js b/mission_2/services/ProductService.js similarity index 100% rename from services/ProductService.js rename to mission_2/services/ProductService.js From 5f834cae9aa369fdb566c29475b6607ddc1c5a47 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 09:24:09 +0900 Subject: [PATCH 003/130] [init] sprint_3 --- mission_3/.gitignore | 5 + mission_3/package-lock.json | 1483 ++++++++++++++++++++++++++++++++ mission_3/package.json | 19 + mission_3/prisma/schema.prisma | 15 + 4 files changed, 1522 insertions(+) create mode 100644 mission_3/.gitignore create mode 100644 mission_3/package-lock.json create mode 100644 mission_3/package.json create mode 100644 mission_3/prisma/schema.prisma diff --git a/mission_3/.gitignore b/mission_3/.gitignore new file mode 100644 index 000000000..9f62ec0b8 --- /dev/null +++ b/mission_3/.gitignore @@ -0,0 +1,5 @@ +node_modules +# Keep environment variables out of version control +.env + +/generated/prisma diff --git a/mission_3/package-lock.json b/mission_3/package-lock.json new file mode 100644 index 000000000..1da84d7ee --- /dev/null +++ b/mission_3/package-lock.json @@ -0,0 +1,1483 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sprint_mission_3", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@prisma/client": "^6.13.0", + "express": "^5.1.0" + }, + "devDependencies": { + "prisma": "^6.13.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@prisma/client": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.13.0.tgz", + "integrity": "sha512-8m2+I3dQovkV8CkDMluiwEV1TxV9EXdT6xaCz39O6jYw7mkf5gwfmi+cL4LJsEPwz5tG7sreBwkRpEMJedGYUQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.13.0.tgz", + "integrity": "sha512-OYMM+pcrvj/NqNWCGESSxVG3O7kX6oWuGyvufTUNnDw740KIQvNyA4v0eILgkpuwsKIDU36beZCkUtIt0naTog==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.16.12", + "read-package-up": "11.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.13.0.tgz", + "integrity": "sha512-um+9pfKJW0ihmM83id9FXGi5qEbVJ0Vxi1Gm0xpYsjwUBnw6s2LdPBbrsG9QXRX46K4CLWCTNvskXBup4i9hlw==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.13.0.tgz", + "integrity": "sha512-D+1B79LFvtWA0KTt8ALekQ6A/glB9w10ETknH5Y9g1k2NYYQOQy93ffiuqLn3Pl6IPJG3EsK/YMROKEaq8KBrA==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/fetch-engine": "6.13.0", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd.tgz", + "integrity": "sha512-MpPyKSzBX7P/ZY9odp9TSegnS/yH3CSbchQE9f0yBg3l2QyN59I6vGXcoYcqKC9VTniS1s18AMmhyr1OWavjHg==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.13.0.tgz", + "integrity": "sha512-grmmq+4FeFKmaaytA8Ozc2+Tf3BC8xn/DVJos6LL022mfRlMZYjT3hZM0/xG7+5fO95zFG9CkDUs0m1S2rXs5Q==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.13.0.tgz", + "integrity": "sha512-Nii2pX50fY4QKKxQwm7/vvqT6Ku8yYJLZAFX4e2vzHwRdMqjugcOG5hOSLjxqoXb0cvOspV70TOhMzrw8kqAnw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.16.12", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", + "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/index-to-position": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", + "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", + "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "devOptional": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/nypm": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", + "integrity": "sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.2.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/pkg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz", + "integrity": "sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/prisma": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.13.0.tgz", + "integrity": "sha512-dfzORf0AbcEyyzxuv2lEwG8g+WRGF/qDQTpHf/6JoHsyF5MyzCEZwClVaEmw3WXcobgadosOboKUgQU0kFs9kw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.13.0", + "@prisma/engines": "6.13.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "devOptional": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "devOptional": true, + "license": "CC0-1.0" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "devOptional": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + } + } +} diff --git a/mission_3/package.json b/mission_3/package.json new file mode 100644 index 000000000..87a32a746 --- /dev/null +++ b/mission_3/package.json @@ -0,0 +1,19 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@prisma/client": "^6.13.0", + "express": "^5.1.0" + }, + "devDependencies": { + "prisma": "^6.13.0" + } +} diff --git a/mission_3/prisma/schema.prisma b/mission_3/prisma/schema.prisma new file mode 100644 index 000000000..e8b9fe92e --- /dev/null +++ b/mission_3/prisma/schema.prisma @@ -0,0 +1,15 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" + output = "../generated/prisma" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} From bd4fb7b76232a3ccbabd2495c744b847a27b303a Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 10:05:42 +0900 Subject: [PATCH 004/130] [feat] new schema model 'Product' added --- mission_3/prisma/schema.prisma | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mission_3/prisma/schema.prisma b/mission_3/prisma/schema.prisma index e8b9fe92e..0f5a91119 100644 --- a/mission_3/prisma/schema.prisma +++ b/mission_3/prisma/schema.prisma @@ -6,10 +6,20 @@ generator client { provider = "prisma-client-js" - output = "../generated/prisma" + // output = "../generated/prisma" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } + +model Product { + id Int @id @default(autoincrement()) + name String + description String + price Int + tags String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} From 05888a3b4fddb34effbbb48b6dfd7b3d5f244965 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 10:12:18 +0900 Subject: [PATCH 005/130] [chore] initial migration and generating prisma stuff --- .../migrations/20250801011159_init/migration.sql | 12 ++++++++++++ mission_3/prisma/migrations/migration_lock.toml | 3 +++ 2 files changed, 15 insertions(+) create mode 100644 mission_3/prisma/migrations/20250801011159_init/migration.sql create mode 100644 mission_3/prisma/migrations/migration_lock.toml diff --git a/mission_3/prisma/migrations/20250801011159_init/migration.sql b/mission_3/prisma/migrations/20250801011159_init/migration.sql new file mode 100644 index 000000000..7b7ab401e --- /dev/null +++ b/mission_3/prisma/migrations/20250801011159_init/migration.sql @@ -0,0 +1,12 @@ +-- CreateTable +CREATE TABLE "public"."Product" ( + "id" SERIAL NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT NOT NULL, + "price" INTEGER NOT NULL, + "tags" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Product_pkey" PRIMARY KEY ("id") +); diff --git a/mission_3/prisma/migrations/migration_lock.toml b/mission_3/prisma/migrations/migration_lock.toml new file mode 100644 index 000000000..044d57cdb --- /dev/null +++ b/mission_3/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (e.g., Git) +provider = "postgresql" From 7789c21d3db0d3cca1d3bf3df6d53809b60efef1 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 10:16:51 +0900 Subject: [PATCH 006/130] [feat] switch CJS to MJS in package.json --- mission_3/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mission_3/package.json b/mission_3/package.json index 87a32a746..58142aa0d 100644 --- a/mission_3/package.json +++ b/mission_3/package.json @@ -15,5 +15,6 @@ }, "devDependencies": { "prisma": "^6.13.0" - } + }, + "type": "module" } From 559fed4cf415e183d403507734ce9bba72456e8f Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 10:18:14 +0900 Subject: [PATCH 007/130] [feat] basic boilerplate for express.js --- mission_3/main.js | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 mission_3/main.js diff --git a/mission_3/main.js b/mission_3/main.js new file mode 100644 index 000000000..69cdad368 --- /dev/null +++ b/mission_3/main.js @@ -0,0 +1,11 @@ +import express from 'express'; +import { PrismaClient } from '@prisma/client'; + +const app = express(); +const prisma = new PrismaClient(); + +const PORT = process.env.PORT || 3000; + +app.use(express.json()); + +app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file From 2456f8be9021f5f8d649d24f12cd35dd88abc0f8 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 11:15:45 +0900 Subject: [PATCH 008/130] [feat] implemented product uploading feature --- mission_3/main.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/mission_3/main.js b/mission_3/main.js index 69cdad368..b63d29e03 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -8,4 +8,40 @@ const PORT = process.env.PORT || 3000; app.use(express.json()); +app.post('/product', async (req, res) => { + + // destructuring field data from request body + const { + name, + description, + price, + tags + } = req.body; + + // validation logic (possible improvements with Zod libraries in the future) + if ( !name || !description || !price || !tags ) + return res.status(500).json({ message: "Invalid SQL Parameters" }); + + try { + // insert into Product table + const product = await prisma.product.create({ + data: { + name, + description, + price, + tags + } + }); + + // send 201 response status code indicating the query was processed successfully + // with the Product record + res.status(201).json(product); + } catch (err) { + console.error('An error has occurred: ', err); + + res.status(500).json({ "message": "an error has occurred during processing sql" }); + } + +}); + app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file From 7609547244abb384d954495edc6e086b6c7b899e Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 11:17:06 +0900 Subject: [PATCH 009/130] [feat] added request logging middleware --- mission_3/main.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mission_3/main.js b/mission_3/main.js index b63d29e03..8129e0572 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -8,7 +8,12 @@ const PORT = process.env.PORT || 3000; app.use(express.json()); -app.post('/product', async (req, res) => { +function logRequest(req, res, next) { + console.log(`[${req.method}] ${req.path}`) + next(); +} + +app.post('/product', logRequest, async (req, res) => { // destructuring field data from request body const { From 72d629b04f881b70c8851f999d2780a167ad8fc3 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 11:20:15 +0900 Subject: [PATCH 010/130] [chore] spell error --- mission_3/main.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mission_3/main.js b/mission_3/main.js index 8129e0572..9345e706c 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -23,7 +23,7 @@ app.post('/product', logRequest, async (req, res) => { tags } = req.body; - // validation logic (possible improvements with Zod libraries in the future) + // validation logic (possible improvements with Zod library in the future) if ( !name || !description || !price || !tags ) return res.status(500).json({ message: "Invalid SQL Parameters" }); @@ -49,4 +49,8 @@ app.post('/product', logRequest, async (req, res) => { }); +app.get('/product/:id', logRequest, async (req, res) => { + +}); + app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file From ad0a92d522f05ceac92edf01cdfe503319bf77a9 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 11:21:14 +0900 Subject: [PATCH 011/130] [chore] improved status code --- mission_3/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission_3/main.js b/mission_3/main.js index 9345e706c..629a9c972 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -25,7 +25,7 @@ app.post('/product', logRequest, async (req, res) => { // validation logic (possible improvements with Zod library in the future) if ( !name || !description || !price || !tags ) - return res.status(500).json({ message: "Invalid SQL Parameters" }); + return res.status(400).json({ message: "Invalid SQL Parameters" }); try { // insert into Product table From ed8e034c9c0855406f28f0f5e11b6ff844793725 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 11:41:50 +0900 Subject: [PATCH 012/130] [feat] implemented product inquiry --- mission_3/main.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/mission_3/main.js b/mission_3/main.js index 629a9c972..5da6e1cff 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -44,13 +44,32 @@ app.post('/product', logRequest, async (req, res) => { } catch (err) { console.error('An error has occurred: ', err); - res.status(500).json({ "message": "an error has occurred during processing sql" }); + res.status(500).json({ message: "An error has occurred during processing sql" }); } }); app.get('/product/:id', logRequest, async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ "message": "Invalid parameter 'id'" }); + try { + const product = await prisma.product.findUnique({ + where: { + id: parseInt(id) + } + }); + + if (product) + res.status(200).json(product); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }) + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } }); app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file From 54def3ab5f92395ef743f0d4939b160e700719db Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 11:44:54 +0900 Subject: [PATCH 013/130] [feat] use logRequest middleware as global --- mission_3/main.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mission_3/main.js b/mission_3/main.js index 5da6e1cff..752bf2a76 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -13,7 +13,10 @@ function logRequest(req, res, next) { next(); } -app.post('/product', logRequest, async (req, res) => { +// middleware for loggin all http request +app.use(logRequest); + +app.post('/product', async (req, res) => { // destructuring field data from request body const { @@ -49,7 +52,7 @@ app.post('/product', logRequest, async (req, res) => { }); -app.get('/product/:id', logRequest, async (req, res) => { +app.get('/product/:id', async (req, res) => { const { id } = req.params; if (!id) return res.status(400).json({ "message": "Invalid parameter 'id'" }); From 8ed26cfb3dae454e13ac351f519b6be63b52a3e9 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 15:07:43 +0900 Subject: [PATCH 014/130] [feat] implemented product patch --- mission_3/main.js | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/mission_3/main.js b/mission_3/main.js index 752bf2a76..f47a7d8b2 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -55,7 +55,7 @@ app.post('/product', async (req, res) => { app.get('/product/:id', async (req, res) => { const { id } = req.params; if (!id) - return res.status(400).json({ "message": "Invalid parameter 'id'" }); + return res.status(400).json({ message: "Invalid parameter 'id'" }); try { const product = await prisma.product.findUnique({ @@ -75,4 +75,45 @@ app.get('/product/:id', async (req, res) => { } }); +app.patch('/product/:id', async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + // Columns in model Product + const productCols = [ + "name", + "description", + "price", + "tags" + ]; + + const filteredBody = Object.entries(req.body) + .filter(e => productCols.includes(e[0])) + .reduce((obj, ele) => { + obj[ele[0]] = ele[1] + return obj; + }, {}); + + try { + const product = await prisma.product.update({ + where: { + id: Number(id) + }, + data: { + ...filteredBody + } + }); + + if (product) + res.status(200).json(product); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } +}); + app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file From 02c048bbe490bef8b765701c2b383eb05e485b18 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 15:08:39 +0900 Subject: [PATCH 015/130] [feat] implemeneted delete product --- mission_3/main.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/mission_3/main.js b/mission_3/main.js index f47a7d8b2..176beec6c 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -116,4 +116,27 @@ app.patch('/product/:id', async (req, res) => { } }); +app.delete('/product/:id', async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const deleted = await prisma.product.delete({ + where: { + id: Number(id) + } + }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + + if (product) + res.status(200).json(product); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); +}); + app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file From 18ceee1ba768032b1daa2b56da30191f253a22b0 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 15:13:42 +0900 Subject: [PATCH 016/130] [fixed] bug fixed Product DELETE --- mission_3/main.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mission_3/main.js b/mission_3/main.js index 176beec6c..4c265e994 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -127,16 +127,16 @@ app.delete('/product/:id', async (req, res) => { id: Number(id) } }); + + if (deleted) + res.status(200).json(deleted); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); } catch (err) { console.error('An error has occurred: ', err.message); res.status(500).json({ message: "An error has occurred during processing sql" }); } - - if (product) - res.status(200).json(product); - else - res.status(404).json({ message: `Cannot find product with ID ${id}` }); }); app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file From f3098719131db041719bbd4fcf0665da194e2da1 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 15:34:01 +0900 Subject: [PATCH 017/130] [feat] implemented inquiry all products --- mission_3/main.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/mission_3/main.js b/mission_3/main.js index 4c265e994..96b70e05b 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -139,4 +139,30 @@ app.delete('/product/:id', async (req, res) => { } }); +app.get('/product', async (req, res) => { + const { offset = 0, limit = 10 } = req.query; + + try { + const products = await prisma.product.findMany({ + select: { + id: true, + name: true, + price: true, + createdAt: true + }, + skip: offset * limit, + take: limit + }); + + if (products) + res.status(200).json(products); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } +}); + app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file From 8d82340ffa77aff5a0f946cf8f34abeaa188fbe2 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 15:40:31 +0900 Subject: [PATCH 018/130] [chore] add info about endpoints --- mission_3/main.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mission_3/main.js b/mission_3/main.js index 96b70e05b..8d2a8d700 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -16,6 +16,7 @@ function logRequest(req, res, next) { // middleware for loggin all http request app.use(logRequest); +// Upload a new product app.post('/product', async (req, res) => { // destructuring field data from request body @@ -52,6 +53,7 @@ app.post('/product', async (req, res) => { }); +// Get informations of a certain product app.get('/product/:id', async (req, res) => { const { id } = req.params; if (!id) @@ -75,6 +77,7 @@ app.get('/product/:id', async (req, res) => { } }); +// Modify a product property app.patch('/product/:id', async (req, res) => { const { id } = req.params; if (!id) @@ -116,6 +119,7 @@ app.patch('/product/:id', async (req, res) => { } }); +// Look up a particular product app.delete('/product/:id', async (req, res) => { const { id } = req.params; if (!id) @@ -139,6 +143,7 @@ app.delete('/product/:id', async (req, res) => { } }); +// Inquiry all products app.get('/product', async (req, res) => { const { offset = 0, limit = 10 } = req.query; From ea9775f1ed4ecbed432d51e9ebe9d9b1075aaac8 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 16:17:52 +0900 Subject: [PATCH 019/130] [feat] introduct Express router to products.js --- mission_3/main.js | 162 +-------------------------------- mission_3/routes/products.js | 169 +++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+), 158 deletions(-) create mode 100644 mission_3/routes/products.js diff --git a/mission_3/main.js b/mission_3/main.js index 8d2a8d700..b357d2d31 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -1,14 +1,12 @@ import express from 'express'; -import { PrismaClient } from '@prisma/client'; - -const app = express(); -const prisma = new PrismaClient(); +import productRouter from './routes/products.js'; const PORT = process.env.PORT || 3000; +const app = express(); app.use(express.json()); -function logRequest(req, res, next) { +function logRequest(req, _, next) { console.log(`[${req.method}] ${req.path}`) next(); } @@ -16,158 +14,6 @@ function logRequest(req, res, next) { // middleware for loggin all http request app.use(logRequest); -// Upload a new product -app.post('/product', async (req, res) => { - - // destructuring field data from request body - const { - name, - description, - price, - tags - } = req.body; - - // validation logic (possible improvements with Zod library in the future) - if ( !name || !description || !price || !tags ) - return res.status(400).json({ message: "Invalid SQL Parameters" }); - - try { - // insert into Product table - const product = await prisma.product.create({ - data: { - name, - description, - price, - tags - } - }); - - // send 201 response status code indicating the query was processed successfully - // with the Product record - res.status(201).json(product); - } catch (err) { - console.error('An error has occurred: ', err); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } - -}); - -// Get informations of a certain product -app.get('/product/:id', async (req, res) => { - const { id } = req.params; - if (!id) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - try { - const product = await prisma.product.findUnique({ - where: { - id: parseInt(id) - } - }); - - if (product) - res.status(200).json(product); - else - res.status(404).json({ message: `Cannot find product with ID ${id}` }) - } catch (err) { - console.error('An error has occurred: ', err.message); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } -}); - -// Modify a product property -app.patch('/product/:id', async (req, res) => { - const { id } = req.params; - if (!id) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - // Columns in model Product - const productCols = [ - "name", - "description", - "price", - "tags" - ]; - - const filteredBody = Object.entries(req.body) - .filter(e => productCols.includes(e[0])) - .reduce((obj, ele) => { - obj[ele[0]] = ele[1] - return obj; - }, {}); - - try { - const product = await prisma.product.update({ - where: { - id: Number(id) - }, - data: { - ...filteredBody - } - }); - - if (product) - res.status(200).json(product); - else - res.status(404).json({ message: `Cannot find product with ID ${id}` }); - } catch (err) { - console.error('An error has occurred: ', err.message); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } -}); - -// Look up a particular product -app.delete('/product/:id', async (req, res) => { - const { id } = req.params; - if (!id) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - try { - const deleted = await prisma.product.delete({ - where: { - id: Number(id) - } - }); - - if (deleted) - res.status(200).json(deleted); - else - res.status(404).json({ message: `Cannot find product with ID ${id}` }); - } catch (err) { - console.error('An error has occurred: ', err.message); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } -}); - -// Inquiry all products -app.get('/product', async (req, res) => { - const { offset = 0, limit = 10 } = req.query; - - try { - const products = await prisma.product.findMany({ - select: { - id: true, - name: true, - price: true, - createdAt: true - }, - skip: offset * limit, - take: limit - }); - - if (products) - res.status(200).json(products); - else - res.status(404).json({ message: `Cannot find product with ID ${id}` }); - } catch (err) { - console.error('An error has occurred: ', err.message); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } -}); +app.use('/products', productRouter); app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file diff --git a/mission_3/routes/products.js b/mission_3/routes/products.js new file mode 100644 index 000000000..187c2c4cb --- /dev/null +++ b/mission_3/routes/products.js @@ -0,0 +1,169 @@ +import express from 'express'; +import { PrismaClient } from '@prisma/client'; + +const router = express.Router(); +const prisma = new PrismaClient(); + + + +router.route('/') + + // Upload a new product + .post(async (req, res) => { + // destructuring field data from request body + const { + name, + description, + price, + tags + } = req.body; + + // validation logic (possible improvements with Zod library in the future) + if ( !name || !description || !price || !tags ) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + try { + // insert into Product table + const product = await prisma.product.create({ + data: { + name, + description, + price, + tags + } + }); + + // send 201 response status code indicating the query was processed successfully + // with the Product record + res.status(201).json(product); + } catch (err) { + console.error('An error has occurred: ', err); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }) + + // Inquiry all products + .get(async (req, res) => { + const { offset = 0, limit = 10 } = req.query; + + try { + const products = await prisma.product.findMany({ + select: { + id: true, + name: true, + price: true, + createdAt: true + }, + skip: offset * limit, + take: limit + }); + + if (products) + res.status(200).json(products); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }); + + + +router.route('/:id') + + // Get informations of a certain product + .get(async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const product = await prisma.product.findUnique({ + where: { + id: parseInt(id) + } + }); + + if (product) + res.status(200).json(product); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }) + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }) + + // Modify a product property + .patch(async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + // Columns in model Product + const productCols = [ + "name", + "description", + "price", + "tags" + ]; + + const filteredBody = Object.entries(req.body) + .filter(e => productCols.includes(e[0])) + .reduce((obj, ele) => { + obj[ele[0]] = ele[1] + return obj; + }, {}); + + try { + const product = await prisma.product.update({ + where: { + id: Number(id) + }, + data: { + ...filteredBody + } + }); + + if (product) + res.status(200).json(product); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }) + + // Look up a particular product + .delete(async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const deleted = await prisma.product.delete({ + where: { + id: Number(id) + } + }); + + if (deleted) + res.status(200).json(deleted); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }); + + + + export default router; \ No newline at end of file From 35862e59a01cafacbf3bb0ca3b80339bffed4b58 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 16:28:53 +0900 Subject: [PATCH 020/130] [chore] print originalUrl (full path) --- mission_3/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission_3/main.js b/mission_3/main.js index b357d2d31..808f4493d 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -7,7 +7,7 @@ const app = express(); app.use(express.json()); function logRequest(req, _, next) { - console.log(`[${req.method}] ${req.path}`) + console.log(`[${req.method}] ${req.originalUrl}`) next(); } From a492b50b54fdeba19df31cb7139979f2f8cea580 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 16:29:34 +0900 Subject: [PATCH 021/130] [feat] implement sorting --- mission_3/routes/products.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/mission_3/routes/products.js b/mission_3/routes/products.js index 187c2c4cb..1d5996a7f 100644 --- a/mission_3/routes/products.js +++ b/mission_3/routes/products.js @@ -45,7 +45,23 @@ router.route('/') // Inquiry all products .get(async (req, res) => { - const { offset = 0, limit = 10 } = req.query; + const { + offset = 0, + limit = 10, + sort = 'recent' + } = req.query; + + let productsSort = ''; + + switch (sort) { + case 'old': + productsSort = 'asc'; + break; + + case 'recent': + default: + productsSort = 'desc'; + } try { const products = await prisma.product.findMany({ @@ -55,6 +71,9 @@ router.route('/') price: true, createdAt: true }, + orderBy: { + createdAt: productsSort + }, skip: offset * limit, take: limit }); @@ -164,6 +183,6 @@ router.route('/:id') } }); - + export default router; \ No newline at end of file From d4a321a7c84ebf69f2a9f87007ec168dc8900a0d Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 16:40:03 +0900 Subject: [PATCH 022/130] [feat] new schema model 'Article' added --- mission_3/prisma/schema.prisma | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mission_3/prisma/schema.prisma b/mission_3/prisma/schema.prisma index 0f5a91119..237225054 100644 --- a/mission_3/prisma/schema.prisma +++ b/mission_3/prisma/schema.prisma @@ -23,3 +23,11 @@ model Product { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } + +model Article { + id Int @id @default(autoincrement()) + title String + content String + createdAt DateTime @default(now()) + updateedAt DateTime @updatedAt +} From ff194c4e8dc9ee7a23375565a6b59989bbed1a73 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 16:40:43 +0900 Subject: [PATCH 023/130] [chore] migrate for model 'Article' --- .../20250801073244_new_model_article/migration.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 mission_3/prisma/migrations/20250801073244_new_model_article/migration.sql diff --git a/mission_3/prisma/migrations/20250801073244_new_model_article/migration.sql b/mission_3/prisma/migrations/20250801073244_new_model_article/migration.sql new file mode 100644 index 000000000..ca9853da5 --- /dev/null +++ b/mission_3/prisma/migrations/20250801073244_new_model_article/migration.sql @@ -0,0 +1,10 @@ +-- CreateTable +CREATE TABLE "public"."Article" ( + "id" SERIAL NOT NULL, + "title" TEXT NOT NULL, + "content" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updateedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Article_pkey" PRIMARY KEY ("id") +); From f8653a5394196d646cf22ebaea1a598455515599 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 17:19:50 +0900 Subject: [PATCH 024/130] [feat] implement article upload --- mission_3/routes/articles.js | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 mission_3/routes/articles.js diff --git a/mission_3/routes/articles.js b/mission_3/routes/articles.js new file mode 100644 index 000000000..46a22cef7 --- /dev/null +++ b/mission_3/routes/articles.js @@ -0,0 +1,38 @@ +import express from 'express'; +import { PrismaClient } from '@prisma/client'; + +const router = express.Router(); +const prisma = new PrismaClient(); + + + +router.route('/') + + // Create a post + .post(async (req, res) => { + const { + title, + content + } = req.body; + + // validation + if ( !title || !content ) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + try { + const article = await prisma.article.create({ + data: { + title, + content + } + }); + + res.status(201).json(article); + } catch (err) { + console.error('An error has occurred: ', err); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }); + +export default router; \ No newline at end of file From 3c875d8f84704c744d57728f3eba5eb7362d8440 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 17:29:14 +0900 Subject: [PATCH 025/130] [feat] add function inquiring a certain article --- mission_3/routes/articles.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/mission_3/routes/articles.js b/mission_3/routes/articles.js index 46a22cef7..7cf4bcb6a 100644 --- a/mission_3/routes/articles.js +++ b/mission_3/routes/articles.js @@ -35,4 +35,31 @@ router.route('/') } }); + +router.route('/:id') + + // Get informations of a certain article + .get(async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const article = await prisma.article.findUnique({ + where: { + id: parseInt(id) + } + }); + + if (article) + res.status(200).json(article); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }) + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }) + export default router; \ No newline at end of file From 511d279286534eeaa909c6165756406d21a44740 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 17:30:49 +0900 Subject: [PATCH 026/130] [feat] add function patching a certain article --- mission_3/routes/articles.js | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/mission_3/routes/articles.js b/mission_3/routes/articles.js index 7cf4bcb6a..2aeec4654 100644 --- a/mission_3/routes/articles.js +++ b/mission_3/routes/articles.js @@ -62,4 +62,44 @@ router.route('/:id') } }) + // Modify a article property + .patch(async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + // Columns in model Product + const articleCols = [ + "title", + "content" + ]; + + const filteredBody = Object.entries(req.body) + .filter(e => articleCols.includes(e[0])) + .reduce((obj, ele) => { + obj[ele[0]] = ele[1]; + return obj; + }, {}); + + try { + const article = await prisma.article.update({ + where: { + id: Number(id) + }, + data: { + ...filteredBody + } + }); + + if (article) + res.status(200).json(article); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }); + export default router; \ No newline at end of file From 14cbe4a0ac678ec5e221b080b509f6c4d39bef71 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 17:34:50 +0900 Subject: [PATCH 027/130] [chore] misspelled --- mission_3/routes/products.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission_3/routes/products.js b/mission_3/routes/products.js index 1d5996a7f..86d4c975b 100644 --- a/mission_3/routes/products.js +++ b/mission_3/routes/products.js @@ -159,7 +159,7 @@ router.route('/:id') } }) - // Look up a particular product + // Delete a particular product .delete(async (req, res) => { const { id } = req.params; if (!id) From 5d1944243bd4d9171d7fada5c69991a7dd836e05 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 17:36:22 +0900 Subject: [PATCH 028/130] [feat] add a function deleting a particular article --- mission_3/routes/articles.js | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/mission_3/routes/articles.js b/mission_3/routes/articles.js index 2aeec4654..c0006f34e 100644 --- a/mission_3/routes/articles.js +++ b/mission_3/routes/articles.js @@ -33,8 +33,9 @@ router.route('/') res.status(500).json({ message: "An error has occurred during processing sql" }); } - }); + }) + router.route('/:id') @@ -98,6 +99,30 @@ router.route('/:id') } catch (err) { console.error('An error has occurred: ', err.message); + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }) + + // Delete a particular article + .delete(async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const deleted = await prisma.article.delete({ + where: { + id: Number(id) + } + }); + + if (deleted) + res.status(200).json(deleted); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + res.status(500).json({ message: "An error has occurred during processing sql" }); } }); From 473c997883a9ad8dc725018445e42d094c394db1 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 17:56:29 +0900 Subject: [PATCH 029/130] [feat] GET Product with search term --- mission_3/routes/products.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/mission_3/routes/products.js b/mission_3/routes/products.js index 86d4c975b..75bb781cd 100644 --- a/mission_3/routes/products.js +++ b/mission_3/routes/products.js @@ -48,7 +48,8 @@ router.route('/') const { offset = 0, limit = 10, - sort = 'recent' + sort = 'recent', + search = '' } = req.query; let productsSort = ''; @@ -74,6 +75,22 @@ router.route('/') orderBy: { createdAt: productsSort }, + where: { + OR: [ + { + name: { + contains: search, + mode: 'insensitive', + } + }, + { + description: { + contains: search, + mode: 'insensitive', + } + } + ], + }, skip: offset * limit, take: limit }); From 3ead61b92aca97c4d925c4100f37f187e21093db Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 17:58:47 +0900 Subject: [PATCH 030/130] [feat] GET Article with search term --- mission_3/routes/articles.js | 65 +++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/mission_3/routes/articles.js b/mission_3/routes/articles.js index c0006f34e..ad300b4cb 100644 --- a/mission_3/routes/articles.js +++ b/mission_3/routes/articles.js @@ -35,7 +35,70 @@ router.route('/') } }) - + // Inquiry all products + .get(async (req, res) => { + const { + offset = 0, + limit = 10, + sort = 'recent', + search = '' + } = req.query; + + let articlesSort = ''; + + switch (sort) { + case 'old': + articlesSort = 'asc'; + break; + + case 'recent': + default: + articlesSort = 'desc'; + } + + try { + const articles = await prisma.article.findMany({ + select: { + id: true, + title: true, + content: true, + createdAt: true + }, + orderBy: { + createdAt: articlesSort + }, + where: { + OR: [ + { + title: { + contains: search, + mode: 'insensitive', + } + }, + { + content: { + contains: search, + mode: 'insensitive', + } + } + ], + }, + skip: offset * limit, + take: limit + }); + + if (articles) + res.status(200).json(articles); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }); + + router.route('/:id') From 977dfceec4428721b84fdd36cd7d583873ec8582 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 1 Aug 2025 18:02:16 +0900 Subject: [PATCH 031/130] [feat] add 'articleRouter' --- mission_3/main.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mission_3/main.js b/mission_3/main.js index 808f4493d..bb3c69752 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -1,5 +1,6 @@ import express from 'express'; import productRouter from './routes/products.js'; +import articleRouter from './routes/articles.js'; const PORT = process.env.PORT || 3000; @@ -15,5 +16,6 @@ function logRequest(req, _, next) { app.use(logRequest); app.use('/products', productRouter); +app.use('/articles', articleRouter); app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file From 7069cbd4c2cd40d007322c46c0d6bdc98384ea38 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 4 Aug 2025 15:23:52 +0900 Subject: [PATCH 032/130] [feat] add schema model "Comment" --- mission_3/prisma/schema.prisma | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/mission_3/prisma/schema.prisma b/mission_3/prisma/schema.prisma index 237225054..64e5ddfcf 100644 --- a/mission_3/prisma/schema.prisma +++ b/mission_3/prisma/schema.prisma @@ -15,19 +15,33 @@ datasource db { } model Product { - id Int @id @default(autoincrement()) + id Int @id @default(autoincrement()) name String description String price Int tags String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] } model Article { - id Int @id @default(autoincrement()) + id Int @id @default(autoincrement()) title String content String - createdAt DateTime @default(now()) - updateedAt DateTime @updatedAt + createdAt DateTime @default(now()) + updateedAt DateTime @updatedAt + comments Comment[] +} + +model Comment { + id Int @id @default(autoincrement()) + name String + content String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Product Product? @relation(fields: [productId], references: [id]) + productId Int? + Article Article? @relation(fields: [articleId], references: [id]) + articleId Int? } From ea703a6570c2ff3b9dbfb6e08f2d5ab4bdbbe137 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 4 Aug 2025 15:28:39 +0900 Subject: [PATCH 033/130] [chore] schema model "Article" misspelled --- mission_3/prisma/schema.prisma | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission_3/prisma/schema.prisma b/mission_3/prisma/schema.prisma index 64e5ddfcf..a65196ecb 100644 --- a/mission_3/prisma/schema.prisma +++ b/mission_3/prisma/schema.prisma @@ -30,7 +30,7 @@ model Article { title String content String createdAt DateTime @default(now()) - updateedAt DateTime @updatedAt + updatedAt DateTime @updatedAt comments Comment[] } From c4784381bb305ae9455a6c90e5309462fa8423fc Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 4 Aug 2025 16:13:09 +0900 Subject: [PATCH 034/130] [chore] migrate model Comment --- .../migration.sql | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 mission_3/prisma/migrations/20250804063045_add_model_comment/migration.sql diff --git a/mission_3/prisma/migrations/20250804063045_add_model_comment/migration.sql b/mission_3/prisma/migrations/20250804063045_add_model_comment/migration.sql new file mode 100644 index 000000000..f35c9cee3 --- /dev/null +++ b/mission_3/prisma/migrations/20250804063045_add_model_comment/migration.sql @@ -0,0 +1,29 @@ +/* + Warnings: + + - You are about to drop the column `updateedAt` on the `Article` table. All the data in the column will be lost. + - Added the required column `updatedAt` to the `Article` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "public"."Article" DROP COLUMN "updateedAt", +ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL; + +-- CreateTable +CREATE TABLE "public"."Comment" ( + "id" SERIAL NOT NULL, + "name" TEXT NOT NULL, + "content" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "productId" INTEGER, + "articleId" INTEGER, + + CONSTRAINT "Comment_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "public"."Comment" ADD CONSTRAINT "Comment_productId_fkey" FOREIGN KEY ("productId") REFERENCES "public"."Product"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "public"."Comment" ADD CONSTRAINT "Comment_articleId_fkey" FOREIGN KEY ("articleId") REFERENCES "public"."Article"("id") ON DELETE SET NULL ON UPDATE CASCADE; From 89565e6fd03d434c1ef8d58e50e5104158c52841 Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 7 Aug 2025 17:15:09 +0900 Subject: [PATCH 035/130] [feat] add products-comments methods --- mission_3/routes/products.js | 99 ++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/mission_3/routes/products.js b/mission_3/routes/products.js index 75bb781cd..3972e4118 100644 --- a/mission_3/routes/products.js +++ b/mission_3/routes/products.js @@ -202,4 +202,103 @@ router.route('/:id') +router.route('/:id/comments') + + // Add a comment + .post(async (req, res, next) => { + const { id: pid } = req.params; + if (!pid) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + const { + name, + content + } = req.body; + + // validation + if ( !name || !content || !pid ) + return res.status(400).json({ message: "Invalid SQL Parameters"} ); + + const comment = await prisma.comment.create({ + data: { + name, + content, + productId: Number(pid) + } + }); + + res.status(201).json(comment); + }) + + // Inquery all comments + .get(async (req, res, next) => { + const { id: pid } = req.params; + if (!pid) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + const comments = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true + }, + where: { + productId: Number(pid) + } + }); + + if (comments) + res.status(200).json(comments); + else + throw new Error(`Cannot find any comments with board ${board}`); + }); + + + +router.route('/:id/comments/:cid') + + .patch(async (req, res) => { + const { id: pid, cid } = req.params; + if (!pid || !cid) + return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); + + const { name, content } = req.body; + if ( !name || !content ) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + const comment = await prisma.comment.update({ + where: { + id: Number(cid) + }, + data: { + name, + content + } + }); + + if (comment) + res.status(200).json(comment); + else + res.status(404).json({ message: `Cannot find any comment with ID ${id}` }); + }) + + .delete(async (req, res) => { + const { id: pid, cid } = req.params; + if (!pid || !cid) + return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); + + const deleted = await prisma.comment.delete({ + where: { + id: Number(cid) + } + }); + + if (deleted) + res.status(200).json(deleted); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + }); + + + export default router; \ No newline at end of file From 3aecb80b45a9d17a4985dd0ff23f292aab25f595 Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 7 Aug 2025 17:17:07 +0900 Subject: [PATCH 036/130] [feat] add basic errorHandler --- mission_3/main.js | 3 +++ mission_3/routes/handler/errorHandler.js | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 mission_3/routes/handler/errorHandler.js diff --git a/mission_3/main.js b/mission_3/main.js index bb3c69752..1a33c4b3a 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -1,6 +1,7 @@ import express from 'express'; import productRouter from './routes/products.js'; import articleRouter from './routes/articles.js'; +import errorHandler from './routes/handler/errorHandler.js'; const PORT = process.env.PORT || 3000; @@ -18,4 +19,6 @@ app.use(logRequest); app.use('/products', productRouter); app.use('/articles', articleRouter); +app.use(errorHandler); + app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file diff --git a/mission_3/routes/handler/errorHandler.js b/mission_3/routes/handler/errorHandler.js new file mode 100644 index 000000000..c4c45f21f --- /dev/null +++ b/mission_3/routes/handler/errorHandler.js @@ -0,0 +1,7 @@ +function errorHandler(err, req, res, next) { + console.error(`[ERROR] ${err.message}`); + + res.status(err.status || 500).json({ message: "An error has occurred during processing sql" }); +} + +export default errorHandler; \ No newline at end of file From cf8b4f4b69d9a737d7e8420fbe7d328d7c214e3e Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 7 Aug 2025 17:23:01 +0900 Subject: [PATCH 037/130] [feat] add articles-comments methods --- mission_3/routes/articles.js | 113 +++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 6 deletions(-) diff --git a/mission_3/routes/articles.js b/mission_3/routes/articles.js index ad300b4cb..d6e75530a 100644 --- a/mission_3/routes/articles.js +++ b/mission_3/routes/articles.js @@ -35,7 +35,7 @@ router.route('/') } }) - // Inquiry all products + // Inquiry all articles .get(async (req, res) => { const { offset = 0, @@ -90,7 +90,7 @@ router.route('/') if (articles) res.status(200).json(articles); else - res.status(404).json({ message: `Cannot find product with ID ${id}` }); + res.status(404).json({ message: `Cannot find article with ID ${id}` }); } catch (err) { console.error('An error has occurred: ', err.message); @@ -118,7 +118,7 @@ router.route('/:id') if (article) res.status(200).json(article); else - res.status(404).json({ message: `Cannot find product with ID ${id}` }) + res.status(404).json({ message: `Cannot find article with ID ${id}` }) } catch (err) { console.error('An error has occurred: ', err.message); @@ -132,7 +132,7 @@ router.route('/:id') if (!id) return res.status(400).json({ message: "Invalid parameter 'id'" }); - // Columns in model Product + // Columns in model Article const articleCols = [ "title", "content" @@ -158,7 +158,7 @@ router.route('/:id') if (article) res.status(200).json(article); else - res.status(404).json({ message: `Cannot find product with ID ${id}` }); + res.status(404).json({ message: `Cannot find article with ID ${id}` }); } catch (err) { console.error('An error has occurred: ', err.message); @@ -182,7 +182,7 @@ router.route('/:id') if (deleted) res.status(200).json(deleted); else - res.status(404).json({ message: `Cannot find product with ID ${id}` }); + res.status(404).json({ message: `Cannot find article with ID ${id}` }); } catch (err) { console.error('An error has occurred: ', err.message); @@ -190,4 +190,105 @@ router.route('/:id') } }); + + +router.route('/:id/comments') + + // Add a comment + .post(async (req, res, next) => { + const { id: pid } = req.params; + if (!pid) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + const { + name, + content + } = req.body; + + // validation + if ( !name || !content || !pid ) + return res.status(400).json({ message: "Invalid SQL Parameters"} ); + + const comment = await prisma.comment.create({ + data: { + name, + content, + articleId: Number(pid) + } + }); + + res.status(201).json(comment); + }) + + // Inquery all comments + .get(async (req, res, next) => { + const { id: pid } = req.params; + if (!pid) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + const comments = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true + }, + where: { + articleId: Number(pid) + } + }); + + if (comments) + res.status(200).json(comments); + else + throw new Error(`Cannot find any comments with board ${board}`); + }); + + + +router.route('/:id/comments/:cid') + + .patch(async (req, res) => { + const { id: pid, cid } = req.params; + if (!pid || !cid) + return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); + + const { name, content } = req.body; + if ( !name || !content ) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + const comment = await prisma.comment.update({ + where: { + id: Number(cid) + }, + data: { + name, + content + } + }); + + if (comment) + res.status(200).json(comment); + else + res.status(404).json({ message: `Cannot find any comment with ID ${id}` }); + }) + + .delete(async (req, res) => { + const { id: pid, cid } = req.params; + if (!pid || !cid) + return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); + + const deleted = await prisma.comment.delete({ + where: { + id: Number(cid) + } + }); + + if (deleted) + res.status(200).json(deleted); + else + res.status(404).json({ message: `Cannot find article with ID ${id}` }); + }); + + + export default router; \ No newline at end of file From bd2749eebdd1b30348d815b675311fddd644d7af Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 7 Aug 2025 18:22:26 +0900 Subject: [PATCH 038/130] [feat] add onDelete Cascade to model "Comments" --- .../20250807082719_on_delete/migration.sql | 11 +++++++++++ mission_3/prisma/schema.prisma | 14 +++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 mission_3/prisma/migrations/20250807082719_on_delete/migration.sql diff --git a/mission_3/prisma/migrations/20250807082719_on_delete/migration.sql b/mission_3/prisma/migrations/20250807082719_on_delete/migration.sql new file mode 100644 index 000000000..5b2790f30 --- /dev/null +++ b/mission_3/prisma/migrations/20250807082719_on_delete/migration.sql @@ -0,0 +1,11 @@ +-- DropForeignKey +ALTER TABLE "public"."Comment" DROP CONSTRAINT "Comment_articleId_fkey"; + +-- DropForeignKey +ALTER TABLE "public"."Comment" DROP CONSTRAINT "Comment_productId_fkey"; + +-- AddForeignKey +ALTER TABLE "public"."Comment" ADD CONSTRAINT "Comment_productId_fkey" FOREIGN KEY ("productId") REFERENCES "public"."Product"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "public"."Comment" ADD CONSTRAINT "Comment_articleId_fkey" FOREIGN KEY ("articleId") REFERENCES "public"."Article"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/mission_3/prisma/schema.prisma b/mission_3/prisma/schema.prisma index a65196ecb..ff91fde21 100644 --- a/mission_3/prisma/schema.prisma +++ b/mission_3/prisma/schema.prisma @@ -26,12 +26,12 @@ model Product { } model Article { - id Int @id @default(autoincrement()) - title String - content String - createdAt DateTime @default(now()) + id Int @id @default(autoincrement()) + title String + content String + createdAt DateTime @default(now()) updatedAt DateTime @updatedAt - comments Comment[] + comments Comment[] } model Comment { @@ -40,8 +40,8 @@ model Comment { content String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt - Product Product? @relation(fields: [productId], references: [id]) + Product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) productId Int? - Article Article? @relation(fields: [articleId], references: [id]) + Article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) articleId Int? } From c9055a2c3a9f20481f4a558691bb8641723bb5f9 Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 7 Aug 2025 18:37:39 +0900 Subject: [PATCH 039/130] [feat] add cors library (not configured yet) --- mission_3/main.js | 2 ++ mission_3/package-lock.json | 23 +++++++++++++++++++++++ mission_3/package.json | 3 ++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/mission_3/main.js b/mission_3/main.js index 1a33c4b3a..01f141a0c 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -1,4 +1,5 @@ import express from 'express'; +import cors from 'cors'; import productRouter from './routes/products.js'; import articleRouter from './routes/articles.js'; import errorHandler from './routes/handler/errorHandler.js'; @@ -7,6 +8,7 @@ const PORT = process.env.PORT || 3000; const app = express(); app.use(express.json()); +app.use(cors()); function logRequest(req, _, next) { console.log(`[${req.method}] ${req.originalUrl}`) diff --git a/mission_3/package-lock.json b/mission_3/package-lock.json index 1da84d7ee..443185ee6 100644 --- a/mission_3/package-lock.json +++ b/mission_3/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "@prisma/client": "^6.13.0", + "cors": "^2.8.5", "express": "^5.1.0" }, "devDependencies": { @@ -322,6 +323,19 @@ "node": ">=6.6.0" } }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", @@ -906,6 +920,15 @@ "node": "^14.16.0 || >=16.10.0" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", diff --git a/mission_3/package.json b/mission_3/package.json index 58142aa0d..d068d38cd 100644 --- a/mission_3/package.json +++ b/mission_3/package.json @@ -11,10 +11,11 @@ "description": "", "dependencies": { "@prisma/client": "^6.13.0", + "cors": "^2.8.5", "express": "^5.1.0" }, "devDependencies": { "prisma": "^6.13.0" }, - "type": "module" + "type": "module" } From 8328aba93e60ed7ffbedd22d3503c1a8741ce939 Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 7 Aug 2025 18:40:31 +0900 Subject: [PATCH 040/130] [chore] correct spelling --- mission_3/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission_3/main.js b/mission_3/main.js index 01f141a0c..d49328c8d 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -15,7 +15,7 @@ function logRequest(req, _, next) { next(); } -// middleware for loggin all http request +// middleware for logging all http request app.use(logRequest); app.use('/products', productRouter); From 48fb9bb13e6fae09a67f44c39031aed459a69d5f Mon Sep 17 00:00:00 2001 From: intwocave Date: Sat, 16 Aug 2025 00:00:40 +0900 Subject: [PATCH 041/130] [feat] add cors option --- mission_3/main.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mission_3/main.js b/mission_3/main.js index d49328c8d..84c3b6028 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -8,7 +8,9 @@ const PORT = process.env.PORT || 3000; const app = express(); app.use(express.json()); -app.use(cors()); +app.use(cors({ + methods: ['GET', 'POST', 'PUT', 'DELETE'] +})); function logRequest(req, _, next) { console.log(`[${req.method}] ${req.originalUrl}`) From ba920bfe2d2df50872f154ab35cfa89b60abf8d1 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sat, 16 Aug 2025 00:00:56 +0900 Subject: [PATCH 042/130] [feat] add seed file --- mission_3/package.json | 3 ++ mission_3/prisma/seed.js | 95 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 mission_3/prisma/seed.js diff --git a/mission_3/package.json b/mission_3/package.json index d068d38cd..bfa99ae93 100644 --- a/mission_3/package.json +++ b/mission_3/package.json @@ -17,5 +17,8 @@ "devDependencies": { "prisma": "^6.13.0" }, + "prisma": { + "seed": "node prisma/seed.js" + }, "type": "module" } diff --git a/mission_3/prisma/seed.js b/mission_3/prisma/seed.js new file mode 100644 index 000000000..c3afea45a --- /dev/null +++ b/mission_3/prisma/seed.js @@ -0,0 +1,95 @@ +// prisma/seed.js +import { PrismaClient } from '@prisma/client'; +const prisma = new PrismaClient(); + +async function main() { + // ------------------------------ + // Product 더미 데이터 생성 + // ------------------------------ + const product1 = await prisma.product.create({ + data: { + name: "게이밍 노트북", + description: "고성능 게이밍 및 작업용 노트북", + price: 1800000, + tags: "노트북,게이밍,고성능", + comments: { + create: [ + { name: "홍길동", content: "배틀그라운드도 잘 돌아가네요!" }, + { name: "김철수", content: "팬 소음이 조금 있지만 성능은 최고입니다." } + ] + } + } + }); + + const product2 = await prisma.product.create({ + data: { + name: "기계식 키보드", + description: "청축 기계식 키보드, 타건감이 뛰어남", + price: 120000, + tags: "키보드,기계식,청축", + comments: { + create: [ + { name: "이영희", content: "타이핑할 맛이 납니다." } + ] + } + } + }); + + // ------------------------------ + // Article 더미 데이터 생성 + // ------------------------------ + const article1 = await prisma.article.create({ + data: { + title: "게이밍 PC 조립 가이드", + content: "부품 선택부터 조립까지 단계별 설명...", + comments: { + create: [ + { name: "박영수", content: "이 글 덕분에 처음으로 PC를 조립했습니다." }, + { name: "최민지", content: "부품 추천이 매우 유용했습니다." } + ] + } + } + }); + + const article2 = await prisma.article.create({ + data: { + title: "2025년 인기 프로그래밍 언어 TOP 10", + content: "올해 주목받는 프로그래밍 언어와 트렌드를 분석...", + comments: { + create: [ + { name: "장우진", content: "Rust가 상위권이라니 반갑네요!" } + ] + } + } + }); + + // ------------------------------ + // Comment 모델 개별 생성 (Product/Article와 직접 연결) + // ------------------------------ + await prisma.comment.create({ + data: { + name: "손흥민", + content: "이 제품은 가격 대비 성능이 좋습니다.", + productId: product1.id + } + }); + + await prisma.comment.create({ + data: { + name: "유재석", + content: "기사 내용이 깔끔하게 잘 정리되어 있네요.", + articleId: article2.id + } + }); + + console.log("시딩이 완료되었습니다."); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); From 5e9f1d65c54e0e2d46be3c519ad66d21df6ff667 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 17 Aug 2025 23:28:21 +0900 Subject: [PATCH 043/130] [feat] implement cursor pagination --- mission_3/routes/articles.js | 20 ++++++++++++++++++-- mission_3/routes/products.js | 22 ++++++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/mission_3/routes/articles.js b/mission_3/routes/articles.js index d6e75530a..5a65fd2ca 100644 --- a/mission_3/routes/articles.js +++ b/mission_3/routes/articles.js @@ -226,6 +226,8 @@ router.route('/:id/comments') if (!pid) return res.status(400).json({ message: "Invalid parameter 'id'" }); + const { cursor, limit = 10 } = req.query; + const comments = await prisma.comment.findMany({ select: { id: true, @@ -234,11 +236,25 @@ router.route('/:id/comments') }, where: { articleId: Number(pid) - } + }, + orderBy: { + id: 'asc' + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) } + } + : {} + ) }); if (comments) - res.status(200).json(comments); + res.status(200).json({ + comments, + nextCursor + }); else throw new Error(`Cannot find any comments with board ${board}`); }); diff --git a/mission_3/routes/products.js b/mission_3/routes/products.js index 3972e4118..8a0f9aacd 100644 --- a/mission_3/routes/products.js +++ b/mission_3/routes/products.js @@ -236,6 +236,8 @@ router.route('/:id/comments') if (!pid) return res.status(400).json({ message: "Invalid parameter 'id'" }); + const { cursor, limit = 10 } = req.query; + const comments = await prisma.comment.findMany({ select: { id: true, @@ -244,11 +246,27 @@ router.route('/:id/comments') }, where: { productId: Number(pid) - } + }, + orderBy: { + id: 'asc' + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) } + } + : {} + ) }); + const nextCursor = comments.length > 0 ? comments[comments.length - 1] : null; + if (comments) - res.status(200).json(comments); + res.status(200).json({ + comments, + nextCursor + }); else throw new Error(`Cannot find any comments with board ${board}`); }); From 56e38a96427dca06927be79b7f1531b3ed73b220 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 17 Aug 2025 23:28:49 +0900 Subject: [PATCH 044/130] [feat] modulize validation middleware --- mission_3/routes/articles.js | 21 ++++++++++++++++----- mission_3/routes/products.js | 23 ++++++++++++++++++----- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/mission_3/routes/articles.js b/mission_3/routes/articles.js index 5a65fd2ca..c7dc42a61 100644 --- a/mission_3/routes/articles.js +++ b/mission_3/routes/articles.js @@ -6,19 +6,30 @@ const prisma = new PrismaClient(); +async function validateArticle (req, res, next) { + const { + title, + content + } = req.body; + + // validation + if ( !title || !content ) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + next(); +} + + + router.route('/') // Create a post - .post(async (req, res) => { + .post(validateArticle, async (req, res) => { const { title, content } = req.body; - // validation - if ( !title || !content ) - return res.status(400).json({ message: "Invalid SQL Parameters" }); - try { const article = await prisma.article.create({ data: { diff --git a/mission_3/routes/products.js b/mission_3/routes/products.js index 8a0f9aacd..c7aedfad6 100644 --- a/mission_3/routes/products.js +++ b/mission_3/routes/products.js @@ -6,10 +6,27 @@ const prisma = new PrismaClient(); +async function validateProduct (req, res, next) { + const { + name, + description, + price, + tags + } = req.body; + + // validation logic (possible improvements with Zod library in the future) + if ( !name || !description || !price || !tags ) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + next(); +} + + + router.route('/') // Upload a new product - .post(async (req, res) => { + .post(validateProduct, async (req, res) => { // destructuring field data from request body const { name, @@ -18,10 +35,6 @@ router.route('/') tags } = req.body; - // validation logic (possible improvements with Zod library in the future) - if ( !name || !description || !price || !tags ) - return res.status(400).json({ message: "Invalid SQL Parameters" }); - try { // insert into Product table const product = await prisma.product.create({ From 68aafed2dbe9473d2d4cc85ef5f23987b432e1b1 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 17 Aug 2025 23:32:55 +0900 Subject: [PATCH 045/130] [feat] install 'multer' lib --- mission_3/package-lock.json | 175 +++++++++++++++++++++++++++++++++++- mission_3/package.json | 9 +- 2 files changed, 179 insertions(+), 5 deletions(-) diff --git a/mission_3/package-lock.json b/mission_3/package-lock.json index 443185ee6..539c2e20a 100644 --- a/mission_3/package-lock.json +++ b/mission_3/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "@prisma/client": "^6.13.0", "cors": "^2.8.5", - "express": "^5.1.0" + "express": "^5.1.0", + "multer": "^2.0.2" }, "devDependencies": { "prisma": "^6.13.0" @@ -154,6 +155,12 @@ "node": ">= 0.6" } }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, "node_modules/body-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", @@ -174,6 +181,23 @@ "node": ">=18" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -267,6 +291,21 @@ "consola": "^3.2.3" } }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, "node_modules/confbox": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", @@ -863,12 +902,94 @@ "node": ">= 0.6" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/multer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", + "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "mkdirp": "^0.5.6", + "object-assign": "^4.1.1", + "type-is": "^1.6.18", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -1182,6 +1303,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -1411,6 +1546,23 @@ "node": ">= 0.8" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/tinyexec": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", @@ -1454,6 +1606,12 @@ "node": ">= 0.6" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", @@ -1476,6 +1634,12 @@ "node": ">= 0.8" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -1501,6 +1665,15 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } } } } diff --git a/mission_3/package.json b/mission_3/package.json index bfa99ae93..eb6e01d27 100644 --- a/mission_3/package.json +++ b/mission_3/package.json @@ -12,13 +12,14 @@ "dependencies": { "@prisma/client": "^6.13.0", "cors": "^2.8.5", - "express": "^5.1.0" + "express": "^5.1.0", + "multer": "^2.0.2" }, "devDependencies": { "prisma": "^6.13.0" }, - "prisma": { - "seed": "node prisma/seed.js" - }, + "prisma": { + "seed": "node prisma/seed.js" + }, "type": "module" } From a894f77eacba60246c3d482a6dab3cb9de125af4 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 17 Aug 2025 23:53:08 +0900 Subject: [PATCH 046/130] [chore] add DS_store to gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 40b878db5..12ac64720 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules/ \ No newline at end of file +node_modules/ +.DS_Store \ No newline at end of file From e1cf08dc36f403cb34d5684a80dbec6d9e96a12c Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 17 Aug 2025 23:53:45 +0900 Subject: [PATCH 047/130] [feat] add image upload API endpoint --- mission_3/main.js | 3 +++ mission_3/routes/images.js | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 mission_3/routes/images.js diff --git a/mission_3/main.js b/mission_3/main.js index 84c3b6028..e40a50efe 100644 --- a/mission_3/main.js +++ b/mission_3/main.js @@ -2,6 +2,7 @@ import express from 'express'; import cors from 'cors'; import productRouter from './routes/products.js'; import articleRouter from './routes/articles.js'; +import imageRouter from './routes/images.js'; import errorHandler from './routes/handler/errorHandler.js'; const PORT = process.env.PORT || 3000; @@ -22,7 +23,9 @@ app.use(logRequest); app.use('/products', productRouter); app.use('/articles', articleRouter); +app.use('/upload', imageRouter); app.use(errorHandler); +app.use('/upload', express.static('uploads')); app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file diff --git a/mission_3/routes/images.js b/mission_3/routes/images.js new file mode 100644 index 000000000..8b1b70abb --- /dev/null +++ b/mission_3/routes/images.js @@ -0,0 +1,15 @@ +import express from 'express'; +import multer from "multer"; + +const router = express.Router(); + +const upload = multer({ dest: 'uploads/' }); + + +router.post('/', upload.single('image'), async (req, res) => { + // console.log(req.file); + res.status(201).json({ message: 'Upload OK', filePath: req.file.path }); +}); + + +export default router; \ No newline at end of file From 9b5c00e4b957b5a3837fc92a777627a0134e5f44 Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 4 Sep 2025 18:32:17 +0900 Subject: [PATCH 048/130] feat: add gitignore for mission4 --- mission_4/.gitignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 mission_4/.gitignore diff --git a/mission_4/.gitignore b/mission_4/.gitignore new file mode 100644 index 000000000..9f62ec0b8 --- /dev/null +++ b/mission_4/.gitignore @@ -0,0 +1,5 @@ +node_modules +# Keep environment variables out of version control +.env + +/generated/prisma From 3e0c736b8fa1ac6a7b8358b8dc10555b9e84c3eb Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 4 Sep 2025 18:33:26 +0900 Subject: [PATCH 049/130] chore: init for mission4 --- mission_4/.gitignore | 1 + mission_4/main.js | 31 + mission_4/package-lock.json | 1679 ++++++++++++++++++++++ mission_4/package.json | 25 + mission_4/prisma/schema.prisma | 47 + mission_4/prisma/seed.js | 95 ++ mission_4/routes/articles.js | 321 +++++ mission_4/routes/handler/errorHandler.js | 5 + mission_4/routes/images.js | 15 + mission_4/routes/middleware/validator.js | 20 + mission_4/routes/products.js | 306 ++++ mission_4/todo.list | 1 + 12 files changed, 2546 insertions(+) create mode 100644 mission_4/main.js create mode 100644 mission_4/package-lock.json create mode 100644 mission_4/package.json create mode 100644 mission_4/prisma/schema.prisma create mode 100644 mission_4/prisma/seed.js create mode 100644 mission_4/routes/articles.js create mode 100644 mission_4/routes/handler/errorHandler.js create mode 100644 mission_4/routes/images.js create mode 100644 mission_4/routes/middleware/validator.js create mode 100644 mission_4/routes/products.js create mode 100644 mission_4/todo.list diff --git a/mission_4/.gitignore b/mission_4/.gitignore index 9f62ec0b8..a86d0d8e6 100644 --- a/mission_4/.gitignore +++ b/mission_4/.gitignore @@ -3,3 +3,4 @@ node_modules .env /generated/prisma +/prisma/migrations diff --git a/mission_4/main.js b/mission_4/main.js new file mode 100644 index 000000000..43131b44e --- /dev/null +++ b/mission_4/main.js @@ -0,0 +1,31 @@ +import express from 'express'; +import cors from 'cors'; +import productRouter from './routes/products.js'; +import articleRouter from './routes/articles.js'; +import imageRouter from './routes/images.js'; +import errorHandler from './routes/handler/errorHandler.js'; + +const PORT = process.env.PORT || 3000; + +const app = express(); +app.use(express.json()); +app.use(cors({ + methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] +})); + +function logRequest(req, _, next) { + console.log(`[${req.method}] ${req.originalUrl}`) + next(); +} + +// middleware for logging all http request +app.use(logRequest); + +app.use('/products', productRouter); +app.use('/articles', articleRouter); +app.use('/upload', imageRouter); + +app.use(errorHandler); +app.use('/upload', express.static('uploads')); + +app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file diff --git a/mission_4/package-lock.json b/mission_4/package-lock.json new file mode 100644 index 000000000..539c2e20a --- /dev/null +++ b/mission_4/package-lock.json @@ -0,0 +1,1679 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sprint_mission_3", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@prisma/client": "^6.13.0", + "cors": "^2.8.5", + "express": "^5.1.0", + "multer": "^2.0.2" + }, + "devDependencies": { + "prisma": "^6.13.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@prisma/client": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.13.0.tgz", + "integrity": "sha512-8m2+I3dQovkV8CkDMluiwEV1TxV9EXdT6xaCz39O6jYw7mkf5gwfmi+cL4LJsEPwz5tG7sreBwkRpEMJedGYUQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.13.0.tgz", + "integrity": "sha512-OYMM+pcrvj/NqNWCGESSxVG3O7kX6oWuGyvufTUNnDw740KIQvNyA4v0eILgkpuwsKIDU36beZCkUtIt0naTog==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.16.12", + "read-package-up": "11.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.13.0.tgz", + "integrity": "sha512-um+9pfKJW0ihmM83id9FXGi5qEbVJ0Vxi1Gm0xpYsjwUBnw6s2LdPBbrsG9QXRX46K4CLWCTNvskXBup4i9hlw==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.13.0.tgz", + "integrity": "sha512-D+1B79LFvtWA0KTt8ALekQ6A/glB9w10ETknH5Y9g1k2NYYQOQy93ffiuqLn3Pl6IPJG3EsK/YMROKEaq8KBrA==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/fetch-engine": "6.13.0", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd.tgz", + "integrity": "sha512-MpPyKSzBX7P/ZY9odp9TSegnS/yH3CSbchQE9f0yBg3l2QyN59I6vGXcoYcqKC9VTniS1s18AMmhyr1OWavjHg==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.13.0.tgz", + "integrity": "sha512-grmmq+4FeFKmaaytA8Ozc2+Tf3BC8xn/DVJos6LL022mfRlMZYjT3hZM0/xG7+5fO95zFG9CkDUs0m1S2rXs5Q==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.13.0.tgz", + "integrity": "sha512-Nii2pX50fY4QKKxQwm7/vvqT6Ku8yYJLZAFX4e2vzHwRdMqjugcOG5hOSLjxqoXb0cvOspV70TOhMzrw8kqAnw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.16.12", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", + "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/index-to-position": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", + "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", + "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "mkdirp": "^0.5.6", + "object-assign": "^4.1.1", + "type-is": "^1.6.18", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", + "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "devOptional": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/nypm": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", + "integrity": "sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.2.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/pkg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz", + "integrity": "sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/prisma": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.13.0.tgz", + "integrity": "sha512-dfzORf0AbcEyyzxuv2lEwG8g+WRGF/qDQTpHf/6JoHsyF5MyzCEZwClVaEmw3WXcobgadosOboKUgQU0kFs9kw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.13.0", + "@prisma/engines": "6.13.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "devOptional": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "devOptional": true, + "license": "CC0-1.0" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "devOptional": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/mission_4/package.json b/mission_4/package.json new file mode 100644 index 000000000..eb6e01d27 --- /dev/null +++ b/mission_4/package.json @@ -0,0 +1,25 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@prisma/client": "^6.13.0", + "cors": "^2.8.5", + "express": "^5.1.0", + "multer": "^2.0.2" + }, + "devDependencies": { + "prisma": "^6.13.0" + }, + "prisma": { + "seed": "node prisma/seed.js" + }, + "type": "module" +} diff --git a/mission_4/prisma/schema.prisma b/mission_4/prisma/schema.prisma new file mode 100644 index 000000000..2681c99a7 --- /dev/null +++ b/mission_4/prisma/schema.prisma @@ -0,0 +1,47 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" + // output = "../generated/prisma" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model Product { + id Int @id @default(autoincrement()) + name String + description String + price Int + tags String[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] +} + +model Article { + id Int @id @default(autoincrement()) + title String + content String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] +} + +model Comment { + id Int @id @default(autoincrement()) + name String + content String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int? + Article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) + articleId Int? +} diff --git a/mission_4/prisma/seed.js b/mission_4/prisma/seed.js new file mode 100644 index 000000000..c3afea45a --- /dev/null +++ b/mission_4/prisma/seed.js @@ -0,0 +1,95 @@ +// prisma/seed.js +import { PrismaClient } from '@prisma/client'; +const prisma = new PrismaClient(); + +async function main() { + // ------------------------------ + // Product 더미 데이터 생성 + // ------------------------------ + const product1 = await prisma.product.create({ + data: { + name: "게이밍 노트북", + description: "고성능 게이밍 및 작업용 노트북", + price: 1800000, + tags: "노트북,게이밍,고성능", + comments: { + create: [ + { name: "홍길동", content: "배틀그라운드도 잘 돌아가네요!" }, + { name: "김철수", content: "팬 소음이 조금 있지만 성능은 최고입니다." } + ] + } + } + }); + + const product2 = await prisma.product.create({ + data: { + name: "기계식 키보드", + description: "청축 기계식 키보드, 타건감이 뛰어남", + price: 120000, + tags: "키보드,기계식,청축", + comments: { + create: [ + { name: "이영희", content: "타이핑할 맛이 납니다." } + ] + } + } + }); + + // ------------------------------ + // Article 더미 데이터 생성 + // ------------------------------ + const article1 = await prisma.article.create({ + data: { + title: "게이밍 PC 조립 가이드", + content: "부품 선택부터 조립까지 단계별 설명...", + comments: { + create: [ + { name: "박영수", content: "이 글 덕분에 처음으로 PC를 조립했습니다." }, + { name: "최민지", content: "부품 추천이 매우 유용했습니다." } + ] + } + } + }); + + const article2 = await prisma.article.create({ + data: { + title: "2025년 인기 프로그래밍 언어 TOP 10", + content: "올해 주목받는 프로그래밍 언어와 트렌드를 분석...", + comments: { + create: [ + { name: "장우진", content: "Rust가 상위권이라니 반갑네요!" } + ] + } + } + }); + + // ------------------------------ + // Comment 모델 개별 생성 (Product/Article와 직접 연결) + // ------------------------------ + await prisma.comment.create({ + data: { + name: "손흥민", + content: "이 제품은 가격 대비 성능이 좋습니다.", + productId: product1.id + } + }); + + await prisma.comment.create({ + data: { + name: "유재석", + content: "기사 내용이 깔끔하게 잘 정리되어 있네요.", + articleId: article2.id + } + }); + + console.log("시딩이 완료되었습니다."); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/mission_4/routes/articles.js b/mission_4/routes/articles.js new file mode 100644 index 000000000..c7dc42a61 --- /dev/null +++ b/mission_4/routes/articles.js @@ -0,0 +1,321 @@ +import express from 'express'; +import { PrismaClient } from '@prisma/client'; + +const router = express.Router(); +const prisma = new PrismaClient(); + + + +async function validateArticle (req, res, next) { + const { + title, + content + } = req.body; + + // validation + if ( !title || !content ) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + next(); +} + + + +router.route('/') + + // Create a post + .post(validateArticle, async (req, res) => { + const { + title, + content + } = req.body; + + try { + const article = await prisma.article.create({ + data: { + title, + content + } + }); + + res.status(201).json(article); + } catch (err) { + console.error('An error has occurred: ', err); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }) + + // Inquiry all articles + .get(async (req, res) => { + const { + offset = 0, + limit = 10, + sort = 'recent', + search = '' + } = req.query; + + let articlesSort = ''; + + switch (sort) { + case 'old': + articlesSort = 'asc'; + break; + + case 'recent': + default: + articlesSort = 'desc'; + } + + try { + const articles = await prisma.article.findMany({ + select: { + id: true, + title: true, + content: true, + createdAt: true + }, + orderBy: { + createdAt: articlesSort + }, + where: { + OR: [ + { + title: { + contains: search, + mode: 'insensitive', + } + }, + { + content: { + contains: search, + mode: 'insensitive', + } + } + ], + }, + skip: offset * limit, + take: limit + }); + + if (articles) + res.status(200).json(articles); + else + res.status(404).json({ message: `Cannot find article with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }); + + + +router.route('/:id') + + // Get informations of a certain article + .get(async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const article = await prisma.article.findUnique({ + where: { + id: parseInt(id) + } + }); + + if (article) + res.status(200).json(article); + else + res.status(404).json({ message: `Cannot find article with ID ${id}` }) + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }) + + // Modify a article property + .patch(async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + // Columns in model Article + const articleCols = [ + "title", + "content" + ]; + + const filteredBody = Object.entries(req.body) + .filter(e => articleCols.includes(e[0])) + .reduce((obj, ele) => { + obj[ele[0]] = ele[1]; + return obj; + }, {}); + + try { + const article = await prisma.article.update({ + where: { + id: Number(id) + }, + data: { + ...filteredBody + } + }); + + if (article) + res.status(200).json(article); + else + res.status(404).json({ message: `Cannot find article with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }) + + // Delete a particular article + .delete(async (req, res) => { + const { id } = req.params; + if (!id) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const deleted = await prisma.article.delete({ + where: { + id: Number(id) + } + }); + + if (deleted) + res.status(200).json(deleted); + else + res.status(404).json({ message: `Cannot find article with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }); + + + +router.route('/:id/comments') + + // Add a comment + .post(async (req, res, next) => { + const { id: pid } = req.params; + if (!pid) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + const { + name, + content + } = req.body; + + // validation + if ( !name || !content || !pid ) + return res.status(400).json({ message: "Invalid SQL Parameters"} ); + + const comment = await prisma.comment.create({ + data: { + name, + content, + articleId: Number(pid) + } + }); + + res.status(201).json(comment); + }) + + // Inquery all comments + .get(async (req, res, next) => { + const { id: pid } = req.params; + if (!pid) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + const { cursor, limit = 10 } = req.query; + + const comments = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true + }, + where: { + articleId: Number(pid) + }, + orderBy: { + id: 'asc' + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) } + } + : {} + ) + }); + + if (comments) + res.status(200).json({ + comments, + nextCursor + }); + else + throw new Error(`Cannot find any comments with board ${board}`); + }); + + + +router.route('/:id/comments/:cid') + + .patch(async (req, res) => { + const { id: pid, cid } = req.params; + if (!pid || !cid) + return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); + + const { name, content } = req.body; + if ( !name || !content ) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + const comment = await prisma.comment.update({ + where: { + id: Number(cid) + }, + data: { + name, + content + } + }); + + if (comment) + res.status(200).json(comment); + else + res.status(404).json({ message: `Cannot find any comment with ID ${id}` }); + }) + + .delete(async (req, res) => { + const { id: pid, cid } = req.params; + if (!pid || !cid) + return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); + + const deleted = await prisma.comment.delete({ + where: { + id: Number(cid) + } + }); + + if (deleted) + res.status(200).json(deleted); + else + res.status(404).json({ message: `Cannot find article with ID ${id}` }); + }); + + + +export default router; \ No newline at end of file diff --git a/mission_4/routes/handler/errorHandler.js b/mission_4/routes/handler/errorHandler.js new file mode 100644 index 000000000..3df194bd0 --- /dev/null +++ b/mission_4/routes/handler/errorHandler.js @@ -0,0 +1,5 @@ +export function errorHandler(err, req, res, next) { + console.error(`[ERROR] ${err.message}`); + + res.status(err.status || 500).json({ message: err.message }); +} \ No newline at end of file diff --git a/mission_4/routes/images.js b/mission_4/routes/images.js new file mode 100644 index 000000000..467943419 --- /dev/null +++ b/mission_4/routes/images.js @@ -0,0 +1,15 @@ +import express from 'express'; +import multer from "multer"; + +const router = express.Router(); + +const upload = multer({ dest: 'uploads/' }); + +// 이미지 리사이징 기능 구현 예정 +router.post('/', upload.single('image'), async (req, res) => { + // console.log(req.file); + res.status(201).json({ message: 'Upload OK', filePath: req.file.path }); +}); + + +export default router; \ No newline at end of file diff --git a/mission_4/routes/middleware/validator.js b/mission_4/routes/middleware/validator.js new file mode 100644 index 000000000..bc6fae849 --- /dev/null +++ b/mission_4/routes/middleware/validator.js @@ -0,0 +1,20 @@ +export async function validateProduct (req, res, next) { + const { + name, + description, + price, + tags + } = req.body; + + // validation logic (possible improvements with Zod library in the future) + if ( !name || !description || !price || !tags ) + return res.status(400).json({ message: "Missing required fields" }); + + if (isNaN(price)) + return res.status(400).json({ message: "Price must be a number" }); + + if (!Array.isArray(tags) || !tags.every(tag => typeof tag !== 'string')) + return res.status(400).json({ message: "Tags must be an array of string" }); + + next(); +}; \ No newline at end of file diff --git a/mission_4/routes/products.js b/mission_4/routes/products.js new file mode 100644 index 000000000..4ce1f2dd9 --- /dev/null +++ b/mission_4/routes/products.js @@ -0,0 +1,306 @@ +import express from 'express'; +import { PrismaClient } from '@prisma/client'; +import { validateProduct } from './middleware/validator'; + +const router = express.Router(); +const prisma = new PrismaClient(); + +router.route('/') + + // Upload a new product + .post(validateProduct, async (req, res) => { + // destructuring field data from request body + const { + name, + description, + price, + tags + } = req.body; + + try { + // insert into Product table + const product = await prisma.product.create({ + data: { + name, + description, + price, + tags + } + }); + + // send 201 response status code indicating the query was processed successfully + // with the Product record + res.status(201).json(product); + } catch (err) { + next(err); + } + }) + + // Inquiry all products + .get(async (req, res) => { + const { + offset = 0, + limit = 10, + sort = 'recent', + search = '' + } = req.query; + + const productsSort = sort === 'old' ? 'asc' : 'desc'; + + try { + const products = await prisma.product.findMany({ + select: { + id: true, + name: true, + price: true, + createdAt: true + }, + orderBy: { + createdAt: productsSort + }, + where: { + OR: [ + { + name: { + contains: search, + mode: 'insensitive', + } + }, + { + description: { + contains: search, + mode: 'insensitive', + } + } + ], + }, + skip: offset * limit, + take: limit + }); + + if (products) + res.status(200).json(products); + else + res.status(404).json({ message: `Cannot find product` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }); + + + +router.route('/:id') + + // Get informations of a certain product + .get(async (req, res) => { + const { id } = req.params; + if (isNaN(id) || parseInt(id) < 0) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const product = await prisma.product.findUnique({ + where: { + id: parseInt(id) + } + }); + + if (product) + res.status(200).json(product); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }) + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }) + + // Modify a product property + .patch(async (req, res) => { + const { id } = req.params; + if (isNaN(id) || parseInt(id) < 0) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + // Attributes in model Product + const productCols = [ + "name", + "description", + "price", + "tags" + ]; + + // Possible improvement? + const filteredBody = Object.entries(req.body) + .filter(e => productCols.includes(e[0])) + .reduce((obj, ele) => { + obj[ele[0]] = ele[1] + return obj; + }, {}); + + try { + const product = await prisma.product.update({ + where: { + id: Number(id) + }, + data: { + ...filteredBody + } + }); + + if (product) + res.status(200).json(product); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }) + + // Delete a particular product + .delete(async (req, res) => { + const { id } = req.params; + if (isNaN(id) || parseInt(id) < 0) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const deleted = await prisma.product.delete({ + where: { + id: Number(id) + } + }); + + if (deleted) + res.status(200).json(deleted); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + } catch (err) { + console.error('An error has occurred: ', err.message); + + res.status(500).json({ message: "An error has occurred during processing sql" }); + } + }); + + + +router.route('/:id/comments') + + // Add a comment + .post(async (req, res, next) => { + const { id: pid } = req.params; + if (!pid) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + const { + name, + content + } = req.body; + + // validation + if ( !name || !content || !pid ) + return res.status(400).json({ message: "Invalid SQL Parameters"} ); + + const comment = await prisma.comment.create({ + data: { + name, + content, + productId: Number(pid) + } + }); + + res.status(201).json(comment); + }) + + // Inquery all comments + .get(async (req, res, next) => { + const { id: pid } = req.params; + if (!pid) + return res.status(400).json({ message: "Invalid parameter 'id'" }); + + const { cursor, limit = 10 } = req.query; + + const comments = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true + }, + where: { + productId: Number(pid) + }, + orderBy: { + id: 'asc' + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) } + } + : {} + ) + }); + + const nextCursor = comments.length > 0 ? comments[comments.length - 1] : null; + + if (comments) + res.status(200).json({ + comments, + nextCursor + }); + else + throw new Error(`Cannot find any comments with board ${board}`); + }); + + + +router.route('/:id/comments/:cid') + + .patch(async (req, res) => { + const { id: pid, cid } = req.params; + if (!pid || !cid) + return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); + + const { name, content } = req.body; + if ( !name || !content ) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + const comment = await prisma.comment.update({ + where: { + id: Number(cid) + }, + data: { + name, + content + } + }); + + if (comment) + res.status(200).json(comment); + else + res.status(404).json({ message: `Cannot find any comment with ID ${id}` }); + }) + + .delete(async (req, res) => { + const { id: pid, cid } = req.params; + if (!pid || !cid) + return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); + + const deleted = await prisma.comment.delete({ + where: { + id: Number(cid) + } + }); + + if (deleted) + res.status(200).json(deleted); + else + res.status(404).json({ message: `Cannot find product with ID ${id}` }); + }); + + + + export default router; \ No newline at end of file diff --git a/mission_4/todo.list b/mission_4/todo.list new file mode 100644 index 000000000..a60894894 --- /dev/null +++ b/mission_4/todo.list @@ -0,0 +1 @@ +* `mission_3/routes/images.js` 이미지 리사이징 기능 구현 \ No newline at end of file From e2f7f620b3328895da0692326952f189603976e3 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 5 Sep 2025 09:20:32 +0900 Subject: [PATCH 050/130] fix: fix misc errors --- mission_4/.gitignore | 2 ++ mission_4/routes/handler/errorHandler.js | 2 +- mission_4/routes/products.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mission_4/.gitignore b/mission_4/.gitignore index a86d0d8e6..d42e3ca1d 100644 --- a/mission_4/.gitignore +++ b/mission_4/.gitignore @@ -4,3 +4,5 @@ node_modules /generated/prisma /prisma/migrations + +todo.list \ No newline at end of file diff --git a/mission_4/routes/handler/errorHandler.js b/mission_4/routes/handler/errorHandler.js index 3df194bd0..eba73d121 100644 --- a/mission_4/routes/handler/errorHandler.js +++ b/mission_4/routes/handler/errorHandler.js @@ -1,4 +1,4 @@ -export function errorHandler(err, req, res, next) { +export default function errorHandler(err, req, res, next) { console.error(`[ERROR] ${err.message}`); res.status(err.status || 500).json({ message: err.message }); diff --git a/mission_4/routes/products.js b/mission_4/routes/products.js index 4ce1f2dd9..f269a6e65 100644 --- a/mission_4/routes/products.js +++ b/mission_4/routes/products.js @@ -1,6 +1,6 @@ import express from 'express'; import { PrismaClient } from '@prisma/client'; -import { validateProduct } from './middleware/validator'; +import { validateProduct } from './middleware/validator.js'; const router = express.Router(); const prisma = new PrismaClient(); From edafed7795fb855bd314d7d363c08d88e4c3dbb8 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 8 Sep 2025 17:03:52 +0900 Subject: [PATCH 051/130] refactor: refactor misson 3 (incomplete) --- mission_4/lib/prisma.js | 5 + mission_4/main.js | 8 +- mission_4/prisma/seed.js | 4 +- mission_4/routes/articles.js | 321 ------------------ mission_4/routes/handler/errorHandler.js | 5 - mission_4/src/container.js | 1 + mission_4/src/controller/articleController.js | 217 ++++++++++++ mission_4/src/controller/index.js | 1 + mission_4/src/controller/userController.js | 40 +++ mission_4/src/handler/errorHandler.js | 8 + mission_4/src/middleware/index.js | 1 + .../{routes => src}/middleware/validator.js | 13 + mission_4/src/repository/articleRepository.js | 143 ++++++++ mission_4/src/repository/index.js | 1 + mission_4/src/router/articleRouter.js | 54 +++ .../images.js => src/router/imageRouter.js} | 0 mission_4/src/router/index.js | 3 + .../router/productRouter.js} | 2 +- mission_4/src/services/articleService.js | 57 ++++ mission_4/src/services/index.js | 1 + 20 files changed, 552 insertions(+), 333 deletions(-) create mode 100644 mission_4/lib/prisma.js delete mode 100644 mission_4/routes/articles.js delete mode 100644 mission_4/routes/handler/errorHandler.js create mode 100644 mission_4/src/container.js create mode 100644 mission_4/src/controller/articleController.js create mode 100644 mission_4/src/controller/index.js create mode 100644 mission_4/src/controller/userController.js create mode 100644 mission_4/src/handler/errorHandler.js create mode 100644 mission_4/src/middleware/index.js rename mission_4/{routes => src}/middleware/validator.js (71%) create mode 100644 mission_4/src/repository/articleRepository.js create mode 100644 mission_4/src/repository/index.js create mode 100644 mission_4/src/router/articleRouter.js rename mission_4/{routes/images.js => src/router/imageRouter.js} (100%) create mode 100644 mission_4/src/router/index.js rename mission_4/{routes/products.js => src/router/productRouter.js} (99%) create mode 100644 mission_4/src/services/articleService.js create mode 100644 mission_4/src/services/index.js diff --git a/mission_4/lib/prisma.js b/mission_4/lib/prisma.js new file mode 100644 index 000000000..b904402d2 --- /dev/null +++ b/mission_4/lib/prisma.js @@ -0,0 +1,5 @@ +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +export default prisma; \ No newline at end of file diff --git a/mission_4/main.js b/mission_4/main.js index 43131b44e..6b5b6c216 100644 --- a/mission_4/main.js +++ b/mission_4/main.js @@ -1,9 +1,9 @@ import express from 'express'; import cors from 'cors'; -import productRouter from './routes/products.js'; -import articleRouter from './routes/articles.js'; -import imageRouter from './routes/images.js'; -import errorHandler from './routes/handler/errorHandler.js'; +import productRouter from './src/router/productRouter.js'; +import articleRouter from './src/router/articleRouter.js'; +import imageRouter from './src/router/imageRouter.js'; +import errorHandler from './src/handler/errorHandler.js'; const PORT = process.env.PORT || 3000; diff --git a/mission_4/prisma/seed.js b/mission_4/prisma/seed.js index c3afea45a..a5c1077d6 100644 --- a/mission_4/prisma/seed.js +++ b/mission_4/prisma/seed.js @@ -11,7 +11,7 @@ async function main() { name: "게이밍 노트북", description: "고성능 게이밍 및 작업용 노트북", price: 1800000, - tags: "노트북,게이밍,고성능", + tags: ["노트북", "게이밍", "고성능",], comments: { create: [ { name: "홍길동", content: "배틀그라운드도 잘 돌아가네요!" }, @@ -26,7 +26,7 @@ async function main() { name: "기계식 키보드", description: "청축 기계식 키보드, 타건감이 뛰어남", price: 120000, - tags: "키보드,기계식,청축", + tags: ["키보드","기계식","청축",], comments: { create: [ { name: "이영희", content: "타이핑할 맛이 납니다." } diff --git a/mission_4/routes/articles.js b/mission_4/routes/articles.js deleted file mode 100644 index c7dc42a61..000000000 --- a/mission_4/routes/articles.js +++ /dev/null @@ -1,321 +0,0 @@ -import express from 'express'; -import { PrismaClient } from '@prisma/client'; - -const router = express.Router(); -const prisma = new PrismaClient(); - - - -async function validateArticle (req, res, next) { - const { - title, - content - } = req.body; - - // validation - if ( !title || !content ) - return res.status(400).json({ message: "Invalid SQL Parameters" }); - - next(); -} - - - -router.route('/') - - // Create a post - .post(validateArticle, async (req, res) => { - const { - title, - content - } = req.body; - - try { - const article = await prisma.article.create({ - data: { - title, - content - } - }); - - res.status(201).json(article); - } catch (err) { - console.error('An error has occurred: ', err); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } - }) - - // Inquiry all articles - .get(async (req, res) => { - const { - offset = 0, - limit = 10, - sort = 'recent', - search = '' - } = req.query; - - let articlesSort = ''; - - switch (sort) { - case 'old': - articlesSort = 'asc'; - break; - - case 'recent': - default: - articlesSort = 'desc'; - } - - try { - const articles = await prisma.article.findMany({ - select: { - id: true, - title: true, - content: true, - createdAt: true - }, - orderBy: { - createdAt: articlesSort - }, - where: { - OR: [ - { - title: { - contains: search, - mode: 'insensitive', - } - }, - { - content: { - contains: search, - mode: 'insensitive', - } - } - ], - }, - skip: offset * limit, - take: limit - }); - - if (articles) - res.status(200).json(articles); - else - res.status(404).json({ message: `Cannot find article with ID ${id}` }); - } catch (err) { - console.error('An error has occurred: ', err.message); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } - }); - - - -router.route('/:id') - - // Get informations of a certain article - .get(async (req, res) => { - const { id } = req.params; - if (!id) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - try { - const article = await prisma.article.findUnique({ - where: { - id: parseInt(id) - } - }); - - if (article) - res.status(200).json(article); - else - res.status(404).json({ message: `Cannot find article with ID ${id}` }) - } catch (err) { - console.error('An error has occurred: ', err.message); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } - }) - - // Modify a article property - .patch(async (req, res) => { - const { id } = req.params; - if (!id) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - // Columns in model Article - const articleCols = [ - "title", - "content" - ]; - - const filteredBody = Object.entries(req.body) - .filter(e => articleCols.includes(e[0])) - .reduce((obj, ele) => { - obj[ele[0]] = ele[1]; - return obj; - }, {}); - - try { - const article = await prisma.article.update({ - where: { - id: Number(id) - }, - data: { - ...filteredBody - } - }); - - if (article) - res.status(200).json(article); - else - res.status(404).json({ message: `Cannot find article with ID ${id}` }); - } catch (err) { - console.error('An error has occurred: ', err.message); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } - }) - - // Delete a particular article - .delete(async (req, res) => { - const { id } = req.params; - if (!id) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - try { - const deleted = await prisma.article.delete({ - where: { - id: Number(id) - } - }); - - if (deleted) - res.status(200).json(deleted); - else - res.status(404).json({ message: `Cannot find article with ID ${id}` }); - } catch (err) { - console.error('An error has occurred: ', err.message); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } - }); - - - -router.route('/:id/comments') - - // Add a comment - .post(async (req, res, next) => { - const { id: pid } = req.params; - if (!pid) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - const { - name, - content - } = req.body; - - // validation - if ( !name || !content || !pid ) - return res.status(400).json({ message: "Invalid SQL Parameters"} ); - - const comment = await prisma.comment.create({ - data: { - name, - content, - articleId: Number(pid) - } - }); - - res.status(201).json(comment); - }) - - // Inquery all comments - .get(async (req, res, next) => { - const { id: pid } = req.params; - if (!pid) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - const { cursor, limit = 10 } = req.query; - - const comments = await prisma.comment.findMany({ - select: { - id: true, - content: true, - createdAt: true - }, - where: { - articleId: Number(pid) - }, - orderBy: { - id: 'asc' - }, - take: Number(limit), - ...(cursor - ? { - skip: 1, - cursor: { id: Number(cursor) } - } - : {} - ) - }); - - if (comments) - res.status(200).json({ - comments, - nextCursor - }); - else - throw new Error(`Cannot find any comments with board ${board}`); - }); - - - -router.route('/:id/comments/:cid') - - .patch(async (req, res) => { - const { id: pid, cid } = req.params; - if (!pid || !cid) - return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); - - const { name, content } = req.body; - if ( !name || !content ) - return res.status(400).json({ message: "Invalid SQL Parameters" }); - - const comment = await prisma.comment.update({ - where: { - id: Number(cid) - }, - data: { - name, - content - } - }); - - if (comment) - res.status(200).json(comment); - else - res.status(404).json({ message: `Cannot find any comment with ID ${id}` }); - }) - - .delete(async (req, res) => { - const { id: pid, cid } = req.params; - if (!pid || !cid) - return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); - - const deleted = await prisma.comment.delete({ - where: { - id: Number(cid) - } - }); - - if (deleted) - res.status(200).json(deleted); - else - res.status(404).json({ message: `Cannot find article with ID ${id}` }); - }); - - - -export default router; \ No newline at end of file diff --git a/mission_4/routes/handler/errorHandler.js b/mission_4/routes/handler/errorHandler.js deleted file mode 100644 index eba73d121..000000000 --- a/mission_4/routes/handler/errorHandler.js +++ /dev/null @@ -1,5 +0,0 @@ -export default function errorHandler(err, req, res, next) { - console.error(`[ERROR] ${err.message}`); - - res.status(err.status || 500).json({ message: err.message }); -} \ No newline at end of file diff --git a/mission_4/src/container.js b/mission_4/src/container.js new file mode 100644 index 000000000..711877055 --- /dev/null +++ b/mission_4/src/container.js @@ -0,0 +1 @@ +import prisma from '../lib/prisma.js'; \ No newline at end of file diff --git a/mission_4/src/controller/articleController.js b/mission_4/src/controller/articleController.js new file mode 100644 index 000000000..411c5e0f5 --- /dev/null +++ b/mission_4/src/controller/articleController.js @@ -0,0 +1,217 @@ +import * as articleService from "../services/articleService.js"; + +export async function createPost(req, res, next) { + const { title, content } = req.body; + + if (!title || !content) { + const err = new Error(); + err.statusCode = 400; + err.message = "Required data is not sufficient"; + next(err); + } + + try { + const article = await articleService.createPost({ title, content }); + res.status(201).json(article); + } catch (err) { + next(err); + } +} + +export async function getPosts(req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search } = req.query; + + try { + const articles = await articleService.getPosts({ + offset, + limit, + sort: articlesSort, + search, + }); + + if (articles) res.status(200).json(articles); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function getPost(req, res, next) { + const { id } = req.params; + if (!id) return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const article = await articleService.getPost(id); + + if (article) res.status(200).json(article); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function patchPost(req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + // Columns in model Article + const articleCols = ["title", "content"]; + + // ? + const filteredBody = Object.entries(req.body) + .filter((e) => articleCols.includes(e[0])) + .reduce((obj, ele) => { + obj[ele[0]] = ele[1]; + return obj; + }, {}); + + try { + const article = await articleService.patchPost(filteredBody); + + if (article) res.status(200).json(article); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function deletePost(req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const deleted = await articleService.deletePost(id); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function postComment(req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + const { name, content } = req.body; + + // validation + if (!name || !content || !pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid SQL Parameters"; + next(err); + } + + const comment = await articleService.postComment({ name, content, pid }); + + res.status(201).json(comment); +} + +export async function getComments(req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + const { cursor, limit = 10 } = req.query; + + const comments = await articleService.getComments({ pid, cursor, limit }); + + if (comments) + res.status(200).json({ + comments, + nextCursor, + }); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comments with board ${board}`; + next(err); + } +} + +export async function patchComment(req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id' and 'cid'"; + next(err); + } + + const { name, content } = req.body; + if (!name || !content) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid SQL Parameters"; + next(err); + } + + const comment = await articleService.patchComment({ + cid, + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comment with ID ${id}`; + next(err); + } +} + +export async function deleteComment(req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id' and 'cid'"; + next(err); + } + + const deleted = await articleService.deleteComment(cid); + + if (deleted) res.status(200).json(deleted); + else res.status(404).json({ message: `Cannot find article with ID ${id}` }); +} diff --git a/mission_4/src/controller/index.js b/mission_4/src/controller/index.js new file mode 100644 index 000000000..1d9c8cc37 --- /dev/null +++ b/mission_4/src/controller/index.js @@ -0,0 +1 @@ +export * from './articleController.js'; \ No newline at end of file diff --git a/mission_4/src/controller/userController.js b/mission_4/src/controller/userController.js new file mode 100644 index 000000000..daa32cccf --- /dev/null +++ b/mission_4/src/controller/userController.js @@ -0,0 +1,40 @@ +import * as userService from "../services/userService.js"; + +// for Creating user +export async function createUser(req, res, next) { + const { email, nickname, password } = req.body; + + if (!email || !nickname || !password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + next(err); + } + + try { + const userId = await userService.createUser(req.body); + + return res.status(200).json(userId); + } catch (err) { + next(err); + } +} + +// for Login +export async function getUser(req, res, next) { + const { email, password } = req.body; + + if (!email || !password) { + const err = new Error("Email or password is wrong"); + err.statusCode = 404; + next(err); + } + + try { + const user = await userService.getUser(req.body); + const accessToken = await userService.createUser(user); + + return res.status(200).json(accessToken); + } catch (err) { + next(err); + } +} diff --git a/mission_4/src/handler/errorHandler.js b/mission_4/src/handler/errorHandler.js new file mode 100644 index 000000000..0cc4f2a3d --- /dev/null +++ b/mission_4/src/handler/errorHandler.js @@ -0,0 +1,8 @@ +export default function errorHandler(err, req, res, next) { + console.error(`[ERROR] ${err.stack || err.message}`); + + const statusCode = err.statusCode || 500; + const message = err.message || 'Internal server error!'; + + res.status(statusCode).json({ message }); +} \ No newline at end of file diff --git a/mission_4/src/middleware/index.js b/mission_4/src/middleware/index.js new file mode 100644 index 000000000..02584180c --- /dev/null +++ b/mission_4/src/middleware/index.js @@ -0,0 +1 @@ +export * from './validator.js'; \ No newline at end of file diff --git a/mission_4/routes/middleware/validator.js b/mission_4/src/middleware/validator.js similarity index 71% rename from mission_4/routes/middleware/validator.js rename to mission_4/src/middleware/validator.js index bc6fae849..82377ac76 100644 --- a/mission_4/routes/middleware/validator.js +++ b/mission_4/src/middleware/validator.js @@ -16,5 +16,18 @@ export async function validateProduct (req, res, next) { if (!Array.isArray(tags) || !tags.every(tag => typeof tag !== 'string')) return res.status(400).json({ message: "Tags must be an array of string" }); + next(); +}; + +export async function validateArticle (req, res, next) { + const { + title, + content + } = req.body; + + // validation + if ( !title || !content ) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + next(); }; \ No newline at end of file diff --git a/mission_4/src/repository/articleRepository.js b/mission_4/src/repository/articleRepository.js new file mode 100644 index 000000000..903534a7d --- /dev/null +++ b/mission_4/src/repository/articleRepository.js @@ -0,0 +1,143 @@ +import prisma from "../../lib/prisma.js"; + +export async function createPost({ title, content }) { + return await prisma.article.create({ + data: { + title, + content, + }, + }); +} + +export async function getPosts({ offset, limit, sort, search }) { + // search에 값이 있을 때만 where로 문자열 검색 + const where = search + ? { + OR: [ + { + title: { + contains: search, + mode: "insensitive", + }, + }, + { + content: { + contains: search, + mode: "insensitive", + }, + }, + ], + } + : {}; + + const result = await prisma.article.findMany({ + select: { + id: true, + title: true, + content: true, + createdAt: true, + }, + orderBy: { + createdAt: articlesSort, + }, + where, + skip: offset * limit, + take: limit, + }); + + return result; +} + +export async function getPost(id) { + const result = await prisma.article.findUnique({ + where: { + id: parseInt(id), + }, + }); + + return result; +} + +export async function patchPost(filteredBody) { + const result = await prisma.article.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deletePost(id) { + const result = await prisma.article.delete({ + where: { + id: Number(id), + }, + }); + + return result; +} + +export async function postComment({ pid, name, content }) { + const result = await prisma.comment.create({ + data: { + name, + content, + articleId: Number(pid), + }, + }); + + return result; +} + +export async function getComments({ pid, cursor, limit }) { + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + articleId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function patchComment({ cid, name, content }) { + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(cid) { + const result = prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} diff --git a/mission_4/src/repository/index.js b/mission_4/src/repository/index.js new file mode 100644 index 000000000..a9bc4c15b --- /dev/null +++ b/mission_4/src/repository/index.js @@ -0,0 +1 @@ +export * from './articleRepository.js'; \ No newline at end of file diff --git a/mission_4/src/router/articleRouter.js b/mission_4/src/router/articleRouter.js new file mode 100644 index 000000000..136a16d02 --- /dev/null +++ b/mission_4/src/router/articleRouter.js @@ -0,0 +1,54 @@ +import express from "express"; +import { validateArticle } from "../middleware/index.js"; +import { + createPost, + getPosts, + getPost, + patchPost, + deletePost, + postComment, + getComments, + patchComment, + deleteComment, +} from "../controller/index.js"; + +const router = express.Router(); + +router + .route("/") + + // Create a post + .post(validateArticle, createPost) + + // Inquiry all articles + .get(getPosts); + +router + .route("/:id") + + // Get informations of a certain article + .get(getPost) + + // Modify a article property + .patch(patchPost) + + // Delete a particular article + .delete(deletePost); + +router + .route("/:id/comments") + + // Add a comment + .post(postComment) + + // Inquery all comments + .get(getComments); + +router + .route("/:id/comments/:cid") + + .patch(patchComment) + + .delete(deleteComment); + +export default router; diff --git a/mission_4/routes/images.js b/mission_4/src/router/imageRouter.js similarity index 100% rename from mission_4/routes/images.js rename to mission_4/src/router/imageRouter.js diff --git a/mission_4/src/router/index.js b/mission_4/src/router/index.js new file mode 100644 index 000000000..921cc19ab --- /dev/null +++ b/mission_4/src/router/index.js @@ -0,0 +1,3 @@ +export * from './articleRouter.js'; +export * from './productRouter.js'; +export * from './imageRouter.js'; \ No newline at end of file diff --git a/mission_4/routes/products.js b/mission_4/src/router/productRouter.js similarity index 99% rename from mission_4/routes/products.js rename to mission_4/src/router/productRouter.js index f269a6e65..0a280063e 100644 --- a/mission_4/routes/products.js +++ b/mission_4/src/router/productRouter.js @@ -1,6 +1,6 @@ import express from 'express'; import { PrismaClient } from '@prisma/client'; -import { validateProduct } from './middleware/validator.js'; +import { validateProduct } from '../middleware/validator.js'; const router = express.Router(); const prisma = new PrismaClient(); diff --git a/mission_4/src/services/articleService.js b/mission_4/src/services/articleService.js new file mode 100644 index 000000000..c390e9ee5 --- /dev/null +++ b/mission_4/src/services/articleService.js @@ -0,0 +1,57 @@ +import * as articleRepository from "../repository/articleRepository.js"; + +export async function createPost(data) { + const result = await articleRepository.createPost(data); + + return result; +} + +export async function getPosts(data) { + // 기본 desc + data.sort = data.sort === "old" ? "asc" : "desc"; + + const result = await articleRepository.getPosts(data); + + return result; +} + +export async function getPost(id) { + const result = await articleRepository.getPost(id); + + return result; +} + +export async function patchPost(data) { + const result = await articleRepository.patchPost(data); + + return result; +} + +export async function deletePost(id) { + const result = await articleRepository.deletePost(id); + + return result; +} + +export async function postComment(data) { + const result = await articleRepository.postComment(data); + + return result; +} + +export async function getComments(data) { + const result = await articleRepository.getComments(data); + + return result; +} + +export async function patchComment(data) { + const result = await articleRepository.patchComment(data); + + return result; +} +export async function deleteComment(data) { + const result = await articleRepository.deleteComment(data); + + return result; +} diff --git a/mission_4/src/services/index.js b/mission_4/src/services/index.js new file mode 100644 index 000000000..ce045fa9e --- /dev/null +++ b/mission_4/src/services/index.js @@ -0,0 +1 @@ +export * from './articleService.js'; \ No newline at end of file From a1bf4d5cc9061252909254478543ef6eda954cbb Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 8 Sep 2025 17:04:50 +0900 Subject: [PATCH 052/130] feat: add scheme model "User" --- mission_4/prisma/schema.prisma | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mission_4/prisma/schema.prisma b/mission_4/prisma/schema.prisma index 2681c99a7..fdc98f807 100644 --- a/mission_4/prisma/schema.prisma +++ b/mission_4/prisma/schema.prisma @@ -45,3 +45,13 @@ model Comment { Article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) articleId Int? } + +model User { + id Int @id @default(autoincrement()) + email String @unique + nickname String + image String? + password String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} From ff5fbc219f9781523cefdde3ad0fa14e1f83ca38 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 8 Sep 2025 18:37:06 +0900 Subject: [PATCH 053/130] feat: add userId foreign key to model Article, Product, Comment --- mission_4/prisma/schema.prisma | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/mission_4/prisma/schema.prisma b/mission_4/prisma/schema.prisma index fdc98f807..15b204a43 100644 --- a/mission_4/prisma/schema.prisma +++ b/mission_4/prisma/schema.prisma @@ -20,6 +20,8 @@ model Product { description String price Int tags String[] + user User @relation(fields: [userId], references: [id]) + userId Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt comments Comment[] @@ -29,6 +31,8 @@ model Article { id Int @id @default(autoincrement()) title String content String + user User @relation(fields: [userId], references: [id]) + userId Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt comments Comment[] @@ -38,6 +42,8 @@ model Comment { id Int @id @default(autoincrement()) name String content String + user User @relation(fields: [userId], references: [id]) + userId Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt Product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) @@ -47,11 +53,14 @@ model Comment { } model User { - id Int @id @default(autoincrement()) - email String @unique + id Int @id @default(autoincrement()) + email String @unique nickname String image String? password String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Article Article[] + Product Product[] + Comment Comment[] } From 19d13d914c4c87ece9c5a32463b2074f4f183376 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 8 Sep 2025 18:39:20 +0900 Subject: [PATCH 054/130] feat: add verifyAccessToken --- mission_4/package-lock.json | 243 +++++++++++++++++++++++++- mission_4/package.json | 7 +- mission_4/src/middleware/auth.js | 43 +++++ mission_4/src/router/articleRouter.js | 5 +- mission_4/src/router/productRouter.js | 3 +- 5 files changed, 296 insertions(+), 5 deletions(-) create mode 100644 mission_4/src/middleware/auth.js diff --git a/mission_4/package-lock.json b/mission_4/package-lock.json index 539c2e20a..d6538953e 100644 --- a/mission_4/package-lock.json +++ b/mission_4/package-lock.json @@ -10,9 +10,14 @@ "license": "ISC", "dependencies": { "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", "cors": "^2.8.5", "express": "^5.1.0", - "multer": "^2.0.2" + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1" }, "devDependencies": { "prisma": "^6.13.0" @@ -135,6 +140,31 @@ "devOptional": true, "license": "MIT" }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", @@ -161,6 +191,20 @@ "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", "license": "MIT" }, + "node_modules/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/body-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", @@ -181,6 +225,12 @@ "node": ">=18" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -452,6 +502,15 @@ "node": ">= 0.4" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -565,6 +624,26 @@ "url": "https://opencollective.com/express" } }, + "node_modules/express-jwt": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.5.1.tgz", + "integrity": "sha512-Dv6QjDLpR2jmdb8M6XQXiCcpEom7mK8TOqnr0/TngDKsG2DHVkO8+XnVxkJVN7BuS1I3OrGw6N8j5DaaGgkDRQ==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "^9", + "express-unless": "^2.1.3", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express-unless": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz", + "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==", + "license": "MIT" + }, "node_modules/exsolve": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", @@ -844,6 +923,91 @@ "devOptional": true, "license": "MIT" }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", @@ -999,6 +1163,15 @@ "node": ">= 0.6" } }, + "node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, "node_modules/node-fetch-native": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", @@ -1006,6 +1179,17 @@ "devOptional": true, "license": "MIT" }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/normalize-package-data": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", @@ -1117,6 +1301,42 @@ "node": ">= 0.8" } }, + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path-to-regexp": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", @@ -1133,6 +1353,11 @@ "devOptional": true, "license": "MIT" }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, "node_modules/perfect-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", @@ -1377,7 +1602,6 @@ "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1612,6 +1836,12 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "license": "MIT" }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "license": "MIT" + }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", @@ -1640,6 +1870,15 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/mission_4/package.json b/mission_4/package.json index eb6e01d27..e4eebb7e0 100644 --- a/mission_4/package.json +++ b/mission_4/package.json @@ -11,9 +11,14 @@ "description": "", "dependencies": { "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", "cors": "^2.8.5", "express": "^5.1.0", - "multer": "^2.0.2" + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1" }, "devDependencies": { "prisma": "^6.13.0" diff --git a/mission_4/src/middleware/auth.js b/mission_4/src/middleware/auth.js new file mode 100644 index 000000000..0cb7a9ab6 --- /dev/null +++ b/mission_4/src/middleware/auth.js @@ -0,0 +1,43 @@ +import { expressjwt } from "express-jwt"; +import * as articleRepository from "../repository/articleRepository.js"; + +const verifyAccessToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + requestProperty: "user", +}); + +const verifyArticleAuth = async (req, res, next) => { + // Get article id + const { id } = req.params; + + // Get article author's id + try { + const article = await articleRepository.getPost(id); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + next(err); + } + + // Call next if valid user + if (req.user.id === article.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + next(err); + } + } catch (err) { + next(err); + } +}; + +const verifyProductAuth = (req, res, next) => { + const { id } = req.params; +}; + +export default { + verifyAccessToken, + verifyArticleAuth, + verifyProductAuth, +}; diff --git a/mission_4/src/router/articleRouter.js b/mission_4/src/router/articleRouter.js index 136a16d02..7533492b1 100644 --- a/mission_4/src/router/articleRouter.js +++ b/mission_4/src/router/articleRouter.js @@ -1,5 +1,6 @@ import express from "express"; import { validateArticle } from "../middleware/index.js"; +import auth from '../middleware/auth.js'; import { createPost, getPosts, @@ -18,7 +19,7 @@ router .route("/") // Create a post - .post(validateArticle, createPost) + .post(auth.verifyAccessToken, validateArticle, createPost) // Inquiry all articles .get(getPosts); @@ -47,8 +48,10 @@ router router .route("/:id/comments/:cid") + // Modify comment .patch(patchComment) + // Delete comment .delete(deleteComment); export default router; diff --git a/mission_4/src/router/productRouter.js b/mission_4/src/router/productRouter.js index 0a280063e..cacfd8bec 100644 --- a/mission_4/src/router/productRouter.js +++ b/mission_4/src/router/productRouter.js @@ -1,6 +1,7 @@ import express from 'express'; import { PrismaClient } from '@prisma/client'; import { validateProduct } from '../middleware/validator.js'; +import auth from '../middleware/auth.js'; const router = express.Router(); const prisma = new PrismaClient(); @@ -8,7 +9,7 @@ const prisma = new PrismaClient(); router.route('/') // Upload a new product - .post(validateProduct, async (req, res) => { + .post(auth.verifyAccessToken, validateProduct, async (req, res) => { // destructuring field data from request body const { name, From ddda8a3568640f9134c5dc9a6b9fdd0111284315 Mon Sep 17 00:00:00 2001 From: intwocave Date: Tue, 9 Sep 2025 12:00:33 +0900 Subject: [PATCH 055/130] feat: article-user authentication --- mission_4/main.js | 3 ++ mission_4/src/controller/articleController.js | 11 ++-- mission_4/src/controller/userController.js | 4 +- mission_4/src/middleware/auth.js | 30 ++++++++++- mission_4/src/middleware/validator.js | 2 + mission_4/src/repository/articleRepository.js | 20 +++++-- mission_4/src/repository/userRepository.js | 39 ++++++++++++++ mission_4/src/router/articleRouter.js | 12 ++--- mission_4/src/router/userRouter.js | 10 ++++ mission_4/src/services/userService.js | 53 +++++++++++++++++++ 10 files changed, 167 insertions(+), 17 deletions(-) create mode 100644 mission_4/src/repository/userRepository.js create mode 100644 mission_4/src/router/userRouter.js create mode 100644 mission_4/src/services/userService.js diff --git a/mission_4/main.js b/mission_4/main.js index 6b5b6c216..eee8fda0d 100644 --- a/mission_4/main.js +++ b/mission_4/main.js @@ -3,6 +3,8 @@ import cors from 'cors'; import productRouter from './src/router/productRouter.js'; import articleRouter from './src/router/articleRouter.js'; import imageRouter from './src/router/imageRouter.js'; +import userRouter from './src/router/userRouter.js'; + import errorHandler from './src/handler/errorHandler.js'; const PORT = process.env.PORT || 3000; @@ -24,6 +26,7 @@ app.use(logRequest); app.use('/products', productRouter); app.use('/articles', articleRouter); app.use('/upload', imageRouter); +app.use(userRouter); app.use(errorHandler); app.use('/upload', express.static('uploads')); diff --git a/mission_4/src/controller/articleController.js b/mission_4/src/controller/articleController.js index 411c5e0f5..f4b1ede16 100644 --- a/mission_4/src/controller/articleController.js +++ b/mission_4/src/controller/articleController.js @@ -2,6 +2,7 @@ import * as articleService from "../services/articleService.js"; export async function createPost(req, res, next) { const { title, content } = req.body; + const userId = req.user.userId; if (!title || !content) { const err = new Error(); @@ -11,7 +12,7 @@ export async function createPost(req, res, next) { } try { - const article = await articleService.createPost({ title, content }); + const article = await articleService.createPost({ userId, title, content }); res.status(201).json(article); } catch (err) { next(err); @@ -25,7 +26,7 @@ export async function getPosts(req, res, next) { const articles = await articleService.getPosts({ offset, limit, - sort: articlesSort, + sort: sort === "old" ? "asc" : "desc", search, }); @@ -81,7 +82,7 @@ export async function patchPost(req, res, next) { }, {}); try { - const article = await articleService.patchPost(filteredBody); + const article = await articleService.patchPost({ id, ...filteredBody }); if (article) res.status(200).json(article); else { @@ -121,6 +122,8 @@ export async function deletePost(req, res, next) { export async function postComment(req, res, next) { const { id: pid } = req.params; + const userId = req.user.userId; + if (!pid) { const err = new Error(); err.statusCode = 400; @@ -138,7 +141,7 @@ export async function postComment(req, res, next) { next(err); } - const comment = await articleService.postComment({ name, content, pid }); + const comment = await articleService.postComment({ userId, name, content, pid }); res.status(201).json(comment); } diff --git a/mission_4/src/controller/userController.js b/mission_4/src/controller/userController.js index daa32cccf..fcde6b962 100644 --- a/mission_4/src/controller/userController.js +++ b/mission_4/src/controller/userController.js @@ -31,9 +31,9 @@ export async function getUser(req, res, next) { try { const user = await userService.getUser(req.body); - const accessToken = await userService.createUser(user); + const accessToken = userService.createToken(user); - return res.status(200).json(accessToken); + return res.status(200).json({ accessToken }); } catch (err) { next(err); } diff --git a/mission_4/src/middleware/auth.js b/mission_4/src/middleware/auth.js index 0cb7a9ab6..a8151ca67 100644 --- a/mission_4/src/middleware/auth.js +++ b/mission_4/src/middleware/auth.js @@ -1,12 +1,14 @@ import { expressjwt } from "express-jwt"; import * as articleRepository from "../repository/articleRepository.js"; +// 토큰 검증 const verifyAccessToken = expressjwt({ secret: process.env.JWT_SECRET, algorithms: ["HS256"], requestProperty: "user", }); +// 게시글 유저 검증 const verifyArticleAuth = async (req, res, next) => { // Get article id const { id } = req.params; @@ -21,7 +23,7 @@ const verifyArticleAuth = async (req, res, next) => { } // Call next if valid user - if (req.user.id === article.userId) next(); + if (req.user.userId === article.userId) next(); else { const err = new Error("Unauthorized"); err.statusCode = 403; @@ -32,6 +34,31 @@ const verifyArticleAuth = async (req, res, next) => { } }; +// 게시글 댓글 유저 검증 +const verifyArticleCommentAuth = async (req, res, next) => { + const { cid } = req.params; + + try { + const comment = await articleRepository.getComment(parseInt(cid)); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + next(err); + } + + if (req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 유저 검증 const verifyProductAuth = (req, res, next) => { const { id } = req.params; }; @@ -39,5 +66,6 @@ const verifyProductAuth = (req, res, next) => { export default { verifyAccessToken, verifyArticleAuth, + verifyArticleCommentAuth, verifyProductAuth, }; diff --git a/mission_4/src/middleware/validator.js b/mission_4/src/middleware/validator.js index 82377ac76..9b1c0fe27 100644 --- a/mission_4/src/middleware/validator.js +++ b/mission_4/src/middleware/validator.js @@ -1,3 +1,4 @@ +// Verify required parameters are okay export async function validateProduct (req, res, next) { const { name, @@ -19,6 +20,7 @@ export async function validateProduct (req, res, next) { next(); }; +// Verify required parameters are okay export async function validateArticle (req, res, next) { const { title, diff --git a/mission_4/src/repository/articleRepository.js b/mission_4/src/repository/articleRepository.js index 903534a7d..509ac30ef 100644 --- a/mission_4/src/repository/articleRepository.js +++ b/mission_4/src/repository/articleRepository.js @@ -1,10 +1,11 @@ import prisma from "../../lib/prisma.js"; -export async function createPost({ title, content }) { +export async function createPost({ userId, title, content }) { return await prisma.article.create({ data: { title, content, + userId, }, }); } @@ -38,7 +39,7 @@ export async function getPosts({ offset, limit, sort, search }) { createdAt: true, }, orderBy: { - createdAt: articlesSort, + createdAt: sort, }, where, skip: offset * limit, @@ -58,7 +59,7 @@ export async function getPost(id) { return result; } -export async function patchPost(filteredBody) { +export async function patchPost({ id, ...filteredBody }) { const result = await prisma.article.update({ where: { id: Number(id), @@ -81,12 +82,13 @@ export async function deletePost(id) { return result; } -export async function postComment({ pid, name, content }) { +export async function postComment({ userId, pid, name, content }) { const result = await prisma.comment.create({ data: { name, content, articleId: Number(pid), + userId, }, }); @@ -118,6 +120,16 @@ export async function getComments({ pid, cursor, limit }) { return result; } +export async function getComment(cid) { + const result = await prisma.comment.findUnique({ + where: { + id: cid, + }, + }); + + return result; +} + export async function patchComment({ cid, name, content }) { const result = await prisma.comment.update({ where: { diff --git a/mission_4/src/repository/userRepository.js b/mission_4/src/repository/userRepository.js new file mode 100644 index 000000000..4645399ea --- /dev/null +++ b/mission_4/src/repository/userRepository.js @@ -0,0 +1,39 @@ +import prisma from "../../lib/prisma.js"; +import bcrypt from 'bcrypt'; + +export async function createUser(user) { + const hashedPassword = await hashPassword(user.password); + + const createdUser = await prisma.user.create({ + data: { + ...user, + password: hashedPassword, // This line overwrites user.password + }, + }); + + const { id: createdUserId } = filterSensitiveUserData(createdUser); + + return createdUserId; +} + +export async function findByEmail(email) { + const result = await prisma.user.findFirst({ + where: { + email, + }, + }); + + return result; +} + +async function hashPassword(password) { + const salt = await bcrypt.genSalt(10); + const hash = await bcrypt.hash(password, salt) + + return hash; +} + +export function filterSensitiveUserData(user) { + const { password, ...rest } = user; + return rest; +} diff --git a/mission_4/src/router/articleRouter.js b/mission_4/src/router/articleRouter.js index 7533492b1..aae1626b6 100644 --- a/mission_4/src/router/articleRouter.js +++ b/mission_4/src/router/articleRouter.js @@ -1,6 +1,6 @@ import express from "express"; import { validateArticle } from "../middleware/index.js"; -import auth from '../middleware/auth.js'; +import auth from "../middleware/auth.js"; import { createPost, getPosts, @@ -31,16 +31,16 @@ router .get(getPost) // Modify a article property - .patch(patchPost) + .patch(auth.verifyAccessToken, auth.verifyArticleAuth, patchPost) // Delete a particular article - .delete(deletePost); + .delete(auth.verifyAccessToken, auth.verifyArticleAuth, deletePost); router .route("/:id/comments") // Add a comment - .post(postComment) + .post(auth.verifyAccessToken, postComment) // Inquery all comments .get(getComments); @@ -49,9 +49,9 @@ router .route("/:id/comments/:cid") // Modify comment - .patch(patchComment) + .patch(auth.verifyAccessToken, auth.verifyArticleCommentAuth, patchComment) // Delete comment - .delete(deleteComment); + .delete(auth.verifyAccessToken, auth.verifyArticleCommentAuth, deleteComment); export default router; diff --git a/mission_4/src/router/userRouter.js b/mission_4/src/router/userRouter.js new file mode 100644 index 000000000..bc37d270e --- /dev/null +++ b/mission_4/src/router/userRouter.js @@ -0,0 +1,10 @@ +import express from "express"; +import * as userController from "../controller/userController.js"; + +const userRouter = express.Router(); + +userRouter.post('/users', userController.createUser); + +userRouter.post('/login', userController.getUser); + +export default userRouter; diff --git a/mission_4/src/services/userService.js b/mission_4/src/services/userService.js new file mode 100644 index 000000000..948e50da3 --- /dev/null +++ b/mission_4/src/services/userService.js @@ -0,0 +1,53 @@ +import * as userRepository from "../repository/userRepository.js"; +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; + +export async function createUser(user) { + // 이미 가입된 이메일인지 검증 + const existedUser = await userRepository.findByEmail(user.email); + + if (existedUser) { + const err = new Error("User already exists"); + err.statusCode = 422; + err.data = { email: user.email }; + throw err; + } + + const createdUserId = await userRepository.createUser(user); + + return createdUserId; +} + +export async function getUser({ email, password }) { + const user = await userRepository.findByEmail(email); + + // If user is invalid + if (!user) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + throw err; + } + + // Verifying password + await verifyPassword(password, user.password); + + // Return without password + return userRepository.filterSensitiveUserData(user); +} + +async function verifyPassword(inputPassword, password) { + const isVerified = await bcrypt.compare(inputPassword, password); + + if (!isVerified) { + const err = new Error("Password is wrong"); + err.statusCode = 401; + throw err; + } +} + +export function createToken(user) { + const payload = { userId: user.id }; + const options = { expiresIn: "1h" }; + + return jwt.sign(payload, process.env.JWT_SECRET, options); +} From 11618a04955204ac59419f8a39967281a2f109eb Mon Sep 17 00:00:00 2001 From: intwocave Date: Tue, 9 Sep 2025 16:04:32 +0900 Subject: [PATCH 056/130] refactor: product --- mission_4/src/controller/productController.js | 239 ++++++++++++++ mission_4/src/repository/productRepository.js | 140 ++++++++ mission_4/src/router/productRouter.js | 310 ++---------------- mission_4/src/services/productService.js | 55 ++++ 4 files changed, 460 insertions(+), 284 deletions(-) create mode 100644 mission_4/src/controller/productController.js create mode 100644 mission_4/src/repository/productRepository.js create mode 100644 mission_4/src/services/productService.js diff --git a/mission_4/src/controller/productController.js b/mission_4/src/controller/productController.js new file mode 100644 index 000000000..1fe63c4a4 --- /dev/null +++ b/mission_4/src/controller/productController.js @@ -0,0 +1,239 @@ +import * as productService from "../services/productService.js"; + +export async function createProduct(req, res, next) { + // destructuring field data from request body + const { name, description, price, tags } = req.body; + + if (!name || !description || !price || !tags) { + const err = new Error(); + err.statusCode = 400; + err.message = "Required data is not sufficient"; + next(err); + } + + try { + // insert into Product table + const product = await productService.createProduct({ + name, + description, + price, + tags, + }); + + res.status(201).json(product); + } catch (err) { + next(err); + } +} + +export async function getProducts(req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search = "" } = req.query; + + try { + const products = await productService.getProducts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search, + }); + + if (products) res.status(200).json(products); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find products`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function getProduct(req, res, next) { + const { id } = req.params; + if (isNaN(id) || parseInt(id) < 0) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const product = await productService.getProduct(Number(id)); + + if (product) res.status(200).json(product); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find product with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function patchProduct(req, res, next) { + const { id } = req.params; + if (isNaN(id) || parseInt(id) < 0) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + // Attributes in model Product + const productCols = ["name", "description", "price", "tags"]; + + // Possible improvement? + const filteredBody = Object.entries(req.body) + .filter((e) => productCols.includes(e[0])) + .reduce((obj, ele) => { + obj[ele[0]] = ele[1]; + return obj; + }, {}); + + try { + const product = await productService.patchProduct({ id, ...filteredBody }); + + if (product) res.status(200).json(product); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find product with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function deleteProduct(req, res, next) { + const { id } = req.params; + if (isNaN(id) || parseInt(id) < 0) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const deleted = await productService.deleteProduct(id); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find product with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function postComment(req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + + // validation + if (!name || !content || !pid) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Comment table + const comment = await productService.postComment({ + pid: Number(pid), + name, + content, + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +} + +export async function getComments(req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + try { + const comments = await productService.getComments({ + pid: Number(pid), + cursor, + limit: Number(limit), + }); + + // Cursor pagination + const nextCursor = + comments.length > 0 ? comments[comments.length - 1] : null; + + if (comments) + res.status(200).json({ + comments, + nextCursor, + }); + else { + const err = new Error(`Cannot find any comments with board ${board}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +} + +export async function patchComment(req, res, next) { + const { id: pid, cid } = req.params; + const { name, content } = req.body; + if (!pid || !cid || !name || !content) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(`Cannot find any comment with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +} + +export async function deleteComment(req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await productService.deleteComment(Number(cid)); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } +} diff --git a/mission_4/src/repository/productRepository.js b/mission_4/src/repository/productRepository.js new file mode 100644 index 000000000..5d3a75d82 --- /dev/null +++ b/mission_4/src/repository/productRepository.js @@ -0,0 +1,140 @@ +import prisma from "../../lib/prisma.js"; + +export async function createProduct({ name, description, price, tags }) { + return await prisma.product.create({ + data: { + name, + description, + price, + tags, + }, + }); +} + +export async function getProducts({ offset, limit, sort, search }) { + const result = await prisma.product.findMany({ + select: { + id: true, + name: true, + price: true, + createdAt: true, + }, + orderBy: { + createdAt: sort, + }, + where: { + OR: [ + { + name: { + contains: search, + mode: "insensitive", + }, + }, + { + description: { + contains: search, + mode: "insensitive", + }, + }, + ], + }, + skip: offset * limit, + take: limit, + }); + + return result; +} + +export async function getProduct(id) { + const result = await prisma.product.findUnique({ + where: { + id: parseInt(id), + }, + }); + + return result; +} + +export async function patchProduct({ id, ...filteredBody }) { + const result = await prisma.product.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deleteProduct(id) { + const result = await prisma.product.delete({ + where: { + id: Number(id), + }, + }); + + return result; +} + +export async function postComment({ pid, name, content }) { + const result = await prisma.comment.create({ + data: { + name, + content, + productId: Number(pid), + }, + }); + + return result; +} + +export async function getComments({ pid, cursor, limit }) { + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + productId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function patchComment({ cid, name, content }) { + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(cid) { + const result = await prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} diff --git a/mission_4/src/router/productRouter.js b/mission_4/src/router/productRouter.js index cacfd8bec..5152df6a0 100644 --- a/mission_4/src/router/productRouter.js +++ b/mission_4/src/router/productRouter.js @@ -1,307 +1,49 @@ -import express from 'express'; -import { PrismaClient } from '@prisma/client'; -import { validateProduct } from '../middleware/validator.js'; -import auth from '../middleware/auth.js'; +import express from "express"; +import { validateProduct } from "../middleware/validator.js"; +import auth from "../middleware/auth.js"; +import * as productController from "../controller/productController.js"; const router = express.Router(); -const prisma = new PrismaClient(); -router.route('/') +router + .route("/") // Upload a new product - .post(auth.verifyAccessToken, validateProduct, async (req, res) => { - // destructuring field data from request body - const { - name, - description, - price, - tags - } = req.body; - - try { - // insert into Product table - const product = await prisma.product.create({ - data: { - name, - description, - price, - tags - } - }); - - // send 201 response status code indicating the query was processed successfully - // with the Product record - res.status(201).json(product); - } catch (err) { - next(err); - } - }) + .post( + auth.verifyAccessToken, + validateProduct, + productController.createProduct + ) // Inquiry all products - .get(async (req, res) => { - const { - offset = 0, - limit = 10, - sort = 'recent', - search = '' - } = req.query; - - const productsSort = sort === 'old' ? 'asc' : 'desc'; - - try { - const products = await prisma.product.findMany({ - select: { - id: true, - name: true, - price: true, - createdAt: true - }, - orderBy: { - createdAt: productsSort - }, - where: { - OR: [ - { - name: { - contains: search, - mode: 'insensitive', - } - }, - { - description: { - contains: search, - mode: 'insensitive', - } - } - ], - }, - skip: offset * limit, - take: limit - }); - - if (products) - res.status(200).json(products); - else - res.status(404).json({ message: `Cannot find product` }); - } catch (err) { - console.error('An error has occurred: ', err.message); + .get(productController.getProducts); - res.status(500).json({ message: "An error has occurred during processing sql" }); - } - }); - - - -router.route('/:id') +router + .route("/:id") // Get informations of a certain product - .get(async (req, res) => { - const { id } = req.params; - if (isNaN(id) || parseInt(id) < 0) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - try { - const product = await prisma.product.findUnique({ - where: { - id: parseInt(id) - } - }); - - if (product) - res.status(200).json(product); - else - res.status(404).json({ message: `Cannot find product with ID ${id}` }) - } catch (err) { - console.error('An error has occurred: ', err.message); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } - }) + .get(productController.getProduct) // Modify a product property - .patch(async (req, res) => { - const { id } = req.params; - if (isNaN(id) || parseInt(id) < 0) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - // Attributes in model Product - const productCols = [ - "name", - "description", - "price", - "tags" - ]; - - // Possible improvement? - const filteredBody = Object.entries(req.body) - .filter(e => productCols.includes(e[0])) - .reduce((obj, ele) => { - obj[ele[0]] = ele[1] - return obj; - }, {}); - - try { - const product = await prisma.product.update({ - where: { - id: Number(id) - }, - data: { - ...filteredBody - } - }); - - if (product) - res.status(200).json(product); - else - res.status(404).json({ message: `Cannot find product with ID ${id}` }); - } catch (err) { - console.error('An error has occurred: ', err.message); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } - }) + .patch(productController.patchProduct) // Delete a particular product - .delete(async (req, res) => { - const { id } = req.params; - if (isNaN(id) || parseInt(id) < 0) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - try { - const deleted = await prisma.product.delete({ - where: { - id: Number(id) - } - }); - - if (deleted) - res.status(200).json(deleted); - else - res.status(404).json({ message: `Cannot find product with ID ${id}` }); - } catch (err) { - console.error('An error has occurred: ', err.message); - - res.status(500).json({ message: "An error has occurred during processing sql" }); - } - }); + .delete(productController.deleteProduct); - - -router.route('/:id/comments') +router + .route("/:id/comments") // Add a comment - .post(async (req, res, next) => { - const { id: pid } = req.params; - if (!pid) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - const { - name, - content - } = req.body; - - // validation - if ( !name || !content || !pid ) - return res.status(400).json({ message: "Invalid SQL Parameters"} ); - - const comment = await prisma.comment.create({ - data: { - name, - content, - productId: Number(pid) - } - }); - - res.status(201).json(comment); - }) + .post(productController.postComment) // Inquery all comments - .get(async (req, res, next) => { - const { id: pid } = req.params; - if (!pid) - return res.status(400).json({ message: "Invalid parameter 'id'" }); - - const { cursor, limit = 10 } = req.query; - - const comments = await prisma.comment.findMany({ - select: { - id: true, - content: true, - createdAt: true - }, - where: { - productId: Number(pid) - }, - orderBy: { - id: 'asc' - }, - take: Number(limit), - ...(cursor - ? { - skip: 1, - cursor: { id: Number(cursor) } - } - : {} - ) - }); - - const nextCursor = comments.length > 0 ? comments[comments.length - 1] : null; - - if (comments) - res.status(200).json({ - comments, - nextCursor - }); - else - throw new Error(`Cannot find any comments with board ${board}`); - }); - - - -router.route('/:id/comments/:cid') - - .patch(async (req, res) => { - const { id: pid, cid } = req.params; - if (!pid || !cid) - return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); - - const { name, content } = req.body; - if ( !name || !content ) - return res.status(400).json({ message: "Invalid SQL Parameters" }); - - const comment = await prisma.comment.update({ - where: { - id: Number(cid) - }, - data: { - name, - content - } - }); - - if (comment) - res.status(200).json(comment); - else - res.status(404).json({ message: `Cannot find any comment with ID ${id}` }); - }) - - .delete(async (req, res) => { - const { id: pid, cid } = req.params; - if (!pid || !cid) - return res.status(400).json({ message: "Invalid parameter 'id' and 'cid'" }); - - const deleted = await prisma.comment.delete({ - where: { - id: Number(cid) - } - }); + .get(productController.getComments); - if (deleted) - res.status(200).json(deleted); - else - res.status(404).json({ message: `Cannot find product with ID ${id}` }); - }); +router + .route("/:id/comments/:cid") + .patch(productController.patchComment) + .delete(productController.deleteComment); - export default router; \ No newline at end of file +export default router; diff --git a/mission_4/src/services/productService.js b/mission_4/src/services/productService.js new file mode 100644 index 000000000..74fa32db4 --- /dev/null +++ b/mission_4/src/services/productService.js @@ -0,0 +1,55 @@ +import * as productRepository from "../repository/productRepository.js"; + +export async function createProduct(data) { + const result = await productRepository.createProduct(data); + + return result; +} + +export async function getProducts(data) { + const result = await productRepository.getProducts(data); + + return result; +} + +export async function getProduct(data) { + const result = await productRepository.getProduct(data); + + return result; +} + +export async function patchProduct(data) { + const result = await productRepository.patchProduct(data); + + return result; +} + +export async function deleteProduct(data) { + const result = await productRepository.deleteProduct(data); + + return result; +} + +export async function postComment(data) { + const result = await productRepository.postComment(data); + + return result; +} + +export async function getComments(data) { + const result = await productRepository.getComments(data); + + return result; +} + +export async function patchComment(data) { + const result = await productRepository.patchComment(data); + + return result; +} + +export async function deleteComment(data) { + const result = await productRepository.deleteComment(data); + + return result; +} From d88ac92ad15c1eb8527d5d7fa64febebcfa676c0 Mon Sep 17 00:00:00 2001 From: intwocave Date: Tue, 9 Sep 2025 17:33:54 +0900 Subject: [PATCH 057/130] feat: implement existence check for articles and products --- mission_4/src/controller/articleController.js | 24 ++--- mission_4/src/controller/productController.js | 4 + mission_4/src/middleware/auth.js | 89 ++++++++++++++++++- mission_4/src/middleware/validator.js | 2 +- mission_4/src/repository/articleRepository.js | 2 +- mission_4/src/repository/productRepository.js | 24 ++++- mission_4/src/router/articleRouter.js | 56 +++++++----- mission_4/src/router/productRouter.js | 34 +++++-- 8 files changed, 188 insertions(+), 47 deletions(-) diff --git a/mission_4/src/controller/articleController.js b/mission_4/src/controller/articleController.js index f4b1ede16..82e1042af 100644 --- a/mission_4/src/controller/articleController.js +++ b/mission_4/src/controller/articleController.js @@ -122,28 +122,28 @@ export async function deletePost(req, res, next) { export async function postComment(req, res, next) { const { id: pid } = req.params; + const { name, content } = req.body; const userId = req.user.userId; - - if (!pid) { + + if (!name || !content || !pid) { const err = new Error(); err.statusCode = 400; err.message = "Invalid parameter 'id'"; next(err); } - const { name, content } = req.body; + try { + const comment = await articleService.postComment({ + userId, + name, + content, + pid: Number(pid), + }); - // validation - if (!name || !content || !pid) { - const err = new Error(); - err.statusCode = 400; - err.message = "Invalid SQL Parameters"; + res.status(201).json(comment); + } catch (err) { next(err); } - - const comment = await articleService.postComment({ userId, name, content, pid }); - - res.status(201).json(comment); } export async function getComments(req, res, next) { diff --git a/mission_4/src/controller/productController.js b/mission_4/src/controller/productController.js index 1fe63c4a4..85cfbcaea 100644 --- a/mission_4/src/controller/productController.js +++ b/mission_4/src/controller/productController.js @@ -3,6 +3,7 @@ import * as productService from "../services/productService.js"; export async function createProduct(req, res, next) { // destructuring field data from request body const { name, description, price, tags } = req.body; + const userId = req.user.userId; if (!name || !description || !price || !tags) { const err = new Error(); @@ -14,6 +15,7 @@ export async function createProduct(req, res, next) { try { // insert into Product table const product = await productService.createProduct({ + userId, name, description, price, @@ -135,6 +137,7 @@ export async function deleteProduct(req, res, next) { export async function postComment(req, res, next) { const { id: pid } = req.params; const { name, content } = req.body; + const userId = req.user.userId; // validation if (!name || !content || !pid) { @@ -146,6 +149,7 @@ export async function postComment(req, res, next) { try { // insert into Comment table const comment = await productService.postComment({ + userId, pid: Number(pid), name, content, diff --git a/mission_4/src/middleware/auth.js b/mission_4/src/middleware/auth.js index a8151ca67..ec31c407e 100644 --- a/mission_4/src/middleware/auth.js +++ b/mission_4/src/middleware/auth.js @@ -1,5 +1,6 @@ import { expressjwt } from "express-jwt"; import * as articleRepository from "../repository/articleRepository.js"; +import * as productRepository from "../repository/productRepository.js"; // 토큰 검증 const verifyAccessToken = expressjwt({ @@ -34,6 +35,64 @@ const verifyArticleAuth = async (req, res, next) => { } }; +// 상품 유저 검증 +const verifyProductAuth = async (req, res, next) => { + // Get product id + const { id } = req.params; + + // Get product uploaders's id + try { + const product = await productRepository.getProduct(id); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + next(err); + } + + // Call next if valid user + if (req.user.userId === product.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + next(err); + } + } catch (err) { + next(err); + } +}; + +// 게시글 존재 여부 확인 +const checkArticleExist = async (req, res, next) => { + const { id } = req.params; + + try { + const article = await articleRepository.getPost(id); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 상품 존재 여부 확인 +const checkProductExist = async (req, res, next) => { + const { id } = req.params; + + try { + const product = await productRepository.getProduct(id); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + next(err); + } else next(); + } catch (err) { + next(err); + } +}; + // 게시글 댓글 유저 검증 const verifyArticleCommentAuth = async (req, res, next) => { const { cid } = req.params; @@ -58,14 +117,36 @@ const verifyArticleCommentAuth = async (req, res, next) => { } }; -// 상품 유저 검증 -const verifyProductAuth = (req, res, next) => { - const { id } = req.params; +// 상품 댓글 유저 검증 +const verifyProductCommentAuth = async (req, res, next) => { + const { cid } = req.params; + + try { + const comment = await productRepository.getComment(parseInt(cid)); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + next(err); + } + + if (req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + next(err); + } + } catch (err) { + next(err); + } }; export default { verifyAccessToken, verifyArticleAuth, - verifyArticleCommentAuth, verifyProductAuth, + checkArticleExist, + checkProductExist, + verifyArticleCommentAuth, + verifyProductCommentAuth, }; diff --git a/mission_4/src/middleware/validator.js b/mission_4/src/middleware/validator.js index 9b1c0fe27..1b58eb14a 100644 --- a/mission_4/src/middleware/validator.js +++ b/mission_4/src/middleware/validator.js @@ -14,7 +14,7 @@ export async function validateProduct (req, res, next) { if (isNaN(price)) return res.status(400).json({ message: "Price must be a number" }); - if (!Array.isArray(tags) || !tags.every(tag => typeof tag !== 'string')) + if (!Array.isArray(tags) || !tags.every(tag => typeof tag === 'string')) return res.status(400).json({ message: "Tags must be an array of string" }); next(); diff --git a/mission_4/src/repository/articleRepository.js b/mission_4/src/repository/articleRepository.js index 509ac30ef..15c41f0fe 100644 --- a/mission_4/src/repository/articleRepository.js +++ b/mission_4/src/repository/articleRepository.js @@ -87,7 +87,7 @@ export async function postComment({ userId, pid, name, content }) { data: { name, content, - articleId: Number(pid), + articleId: pid, userId, }, }); diff --git a/mission_4/src/repository/productRepository.js b/mission_4/src/repository/productRepository.js index 5d3a75d82..940578285 100644 --- a/mission_4/src/repository/productRepository.js +++ b/mission_4/src/repository/productRepository.js @@ -1,12 +1,19 @@ import prisma from "../../lib/prisma.js"; -export async function createProduct({ name, description, price, tags }) { +export async function createProduct({ + userId, + name, + description, + price, + tags, +}) { return await prisma.product.create({ data: { name, description, price, tags, + userId, }, }); } @@ -78,12 +85,13 @@ export async function deleteProduct(id) { return result; } -export async function postComment({ pid, name, content }) { +export async function postComment({ userId, pid, name, content }) { const result = await prisma.comment.create({ data: { + userId, name, content, - productId: Number(pid), + productId: pid, }, }); @@ -115,6 +123,16 @@ export async function getComments({ pid, cursor, limit }) { return result; } +export async function getComment(cid) { + const result = await prisma.comment.findUnique({ + where: { + id: cid, + }, + }); + + return result; +} + export async function patchComment({ cid, name, content }) { const result = await prisma.comment.update({ where: { diff --git a/mission_4/src/router/articleRouter.js b/mission_4/src/router/articleRouter.js index aae1626b6..6599813b0 100644 --- a/mission_4/src/router/articleRouter.js +++ b/mission_4/src/router/articleRouter.js @@ -1,17 +1,7 @@ import express from "express"; import { validateArticle } from "../middleware/index.js"; import auth from "../middleware/auth.js"; -import { - createPost, - getPosts, - getPost, - patchPost, - deletePost, - postComment, - getComments, - patchComment, - deleteComment, -} from "../controller/index.js"; +import * as articleController from "../controller/articleController.js"; const router = express.Router(); @@ -19,39 +9,65 @@ router .route("/") // Create a post - .post(auth.verifyAccessToken, validateArticle, createPost) + .post( + auth.verifyAccessToken, + validateArticle, + articleController.createPost + ) // Inquiry all articles - .get(getPosts); + .get(articleController.getPosts); router .route("/:id") // Get informations of a certain article - .get(getPost) + .get(articleController.getPost) // Modify a article property - .patch(auth.verifyAccessToken, auth.verifyArticleAuth, patchPost) + .patch( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.patchPost + ) // Delete a particular article - .delete(auth.verifyAccessToken, auth.verifyArticleAuth, deletePost); + .delete( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.deletePost + ); router .route("/:id/comments") // Add a comment - .post(auth.verifyAccessToken, postComment) + .post( + auth.verifyAccessToken, + auth.checkArticleExist, + articleController.postComment + ) // Inquery all comments - .get(getComments); + .get(auth.checkArticleExist, articleController.getComments); router .route("/:id/comments/:cid") // Modify comment - .patch(auth.verifyAccessToken, auth.verifyArticleCommentAuth, patchComment) + .patch( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.patchComment + ) // Delete comment - .delete(auth.verifyAccessToken, auth.verifyArticleCommentAuth, deleteComment); + .delete( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.deleteComment + ); export default router; diff --git a/mission_4/src/router/productRouter.js b/mission_4/src/router/productRouter.js index 5152df6a0..ebecb4166 100644 --- a/mission_4/src/router/productRouter.js +++ b/mission_4/src/router/productRouter.js @@ -25,25 +25,47 @@ router .get(productController.getProduct) // Modify a product property - .patch(productController.patchProduct) + .patch( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.patchProduct + ) // Delete a particular product - .delete(productController.deleteProduct); + .delete( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.deleteProduct + ); router .route("/:id/comments") // Add a comment - .post(productController.postComment) + .post( + auth.verifyAccessToken, + auth.checkProductExist, + productController.postComment + ) // Inquery all comments - .get(productController.getComments); + .get(auth.checkProductExist, productController.getComments); router .route("/:id/comments/:cid") - .patch(productController.patchComment) + .patch( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.patchComment + ) - .delete(productController.deleteComment); + .delete( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.deleteComment + ); export default router; From bf6f317c8220102296b149aabdd5306fc2e55643 Mon Sep 17 00:00:00 2001 From: intwocave Date: Tue, 9 Sep 2025 19:03:16 +0900 Subject: [PATCH 058/130] feat: get user's products --- mission_4/src/controller/userController.js | 64 ++++++++++++++++++- mission_4/src/repository/productRepository.js | 11 ++++ mission_4/src/repository/userRepository.js | 34 ++++++++-- mission_4/src/router/userRouter.js | 33 +++++++++- mission_4/src/services/userService.js | 46 ++++++++++++- 5 files changed, 178 insertions(+), 10 deletions(-) diff --git a/mission_4/src/controller/userController.js b/mission_4/src/controller/userController.js index fcde6b962..09c6fbd13 100644 --- a/mission_4/src/controller/userController.js +++ b/mission_4/src/controller/userController.js @@ -20,7 +20,7 @@ export async function createUser(req, res, next) { } // for Login -export async function getUser(req, res, next) { +export async function getAccessToken(req, res, next) { const { email, password } = req.body; if (!email || !password) { @@ -38,3 +38,65 @@ export async function getUser(req, res, next) { next(err); } } + +export async function getMyInfo(req, res, next) { + const userId = req.user.userId; + + try { + const user = await userService.getUserById(userId); + + return res.status(200).json(user); + } catch (err) { + next(err); + } +} + +export async function updateMyInfo(req, res, next) { + const userId = req.user.userId; + const { email, nickname } = req.body; + + if (!email && !nickname) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + next(err); + } + + try { + const updatedUser = await userService.updateUserInfo(userId, req.body); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +} + +export async function updateMyPassword(req, res, next) { + const userId = req.user.userId; + const { password } = req.body; + + if (!password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + next(err); + } + + try { + const updatedUser = await userService.updateUserPassword(userId, password); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +} + +export async function getMyProducts(req, res, next) { + const userId = req.user.userId; + + try { + const products = await userService.getMyProducts(userId); + + return res.status(200).json(products); + } catch (err) { + next(err); + } +} \ No newline at end of file diff --git a/mission_4/src/repository/productRepository.js b/mission_4/src/repository/productRepository.js index 940578285..7c009cf64 100644 --- a/mission_4/src/repository/productRepository.js +++ b/mission_4/src/repository/productRepository.js @@ -156,3 +156,14 @@ export async function deleteComment(cid) { return result; } + +export async function getProductsByUser(userId) { + const products = await prisma.user.findUnique({ + where: { id: userId }, + select: { + Product: true, + }, + }); + + return products; +} \ No newline at end of file diff --git a/mission_4/src/repository/userRepository.js b/mission_4/src/repository/userRepository.js index 4645399ea..2759be3cf 100644 --- a/mission_4/src/repository/userRepository.js +++ b/mission_4/src/repository/userRepository.js @@ -1,5 +1,6 @@ +import e from "express"; import prisma from "../../lib/prisma.js"; -import bcrypt from 'bcrypt'; +import bcrypt from "bcrypt"; export async function createUser(user) { const hashedPassword = await hashPassword(user.password); @@ -11,9 +12,7 @@ export async function createUser(user) { }, }); - const { id: createdUserId } = filterSensitiveUserData(createdUser); - - return createdUserId; + return createdUser; } export async function findByEmail(email) { @@ -26,9 +25,19 @@ export async function findByEmail(email) { return result; } -async function hashPassword(password) { +export async function findById(id) { + const result = await prisma.user.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function hashPassword(password) { const salt = await bcrypt.genSalt(10); - const hash = await bcrypt.hash(password, salt) + const hash = await bcrypt.hash(password, salt); return hash; } @@ -37,3 +46,16 @@ export function filterSensitiveUserData(user) { const { password, ...rest } = user; return rest; } + +export async function updateUser(id, toUpdate) { + if (toUpdate.password) { + toUpdate.password = await hashPassword(toUpdate.password); + } + + const updatedUser = await prisma.user.update({ + where: { id }, + data: toUpdate, + }); + + return updatedUser; +} diff --git a/mission_4/src/router/userRouter.js b/mission_4/src/router/userRouter.js index bc37d270e..d11170e97 100644 --- a/mission_4/src/router/userRouter.js +++ b/mission_4/src/router/userRouter.js @@ -1,10 +1,39 @@ import express from "express"; import * as userController from "../controller/userController.js"; +import auth from "../middleware/auth.js"; const userRouter = express.Router(); -userRouter.post('/users', userController.createUser); +userRouter + .route("/users") -userRouter.post('/login', userController.getUser); + // Create user + .post(userController.createUser) + + // Get my(user) info + .get(auth.verifyAccessToken, userController.getMyInfo); + +// Update user info (nickname, email) +userRouter.patch( + "/users/info", + auth.verifyAccessToken, + userController.updateMyInfo +); + +// Update user password +userRouter.patch( + "/users/password", + auth.verifyAccessToken, + userController.updateMyPassword +); + +// Get product lists uploaded by user +userRouter.get( + "/users/products", + auth.verifyAccessToken, + userController.getMyProducts +); + +userRouter.post("/login", userController.getAccessToken); export default userRouter; diff --git a/mission_4/src/services/userService.js b/mission_4/src/services/userService.js index 948e50da3..9927873f9 100644 --- a/mission_4/src/services/userService.js +++ b/mission_4/src/services/userService.js @@ -1,4 +1,5 @@ import * as userRepository from "../repository/userRepository.js"; +import * as productRepository from "../repository/productRepository.js"; import bcrypt from "bcrypt"; import jwt from "jsonwebtoken"; @@ -13,7 +14,10 @@ export async function createUser(user) { throw err; } - const createdUserId = await userRepository.createUser(user); + const createdUser = await userRepository.createUser(user); + const createdUserId = await userRepository.filterSensitiveUserData( + createdUser + ).id; return createdUserId; } @@ -35,6 +39,18 @@ export async function getUser({ email, password }) { return userRepository.filterSensitiveUserData(user); } +export async function getUserById(userId) { + const user = await userRepository.findById(userId); + + if (!user) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return userRepository.filterSensitiveUserData(user); +} + async function verifyPassword(inputPassword, password) { const isVerified = await bcrypt.compare(inputPassword, password); @@ -51,3 +67,31 @@ export function createToken(user) { return jwt.sign(payload, process.env.JWT_SECRET, options); } + +export async function updateUserInfo(userId, toUpdate) { + // 수정할 내용이 없다면 에러 처리 + if (Object.keys(toUpdate).length === 0) { + const err = new Error("No data to update"); + err.statusCode = 400; + throw err; + } + + const updatedUser = await userRepository.updateUser(userId, toUpdate); + + return userRepository.filterSensitiveUserData(updatedUser); +} + +export async function updateUserPassword(userId, newPassword) { + const hashedPassword = await userRepository.hashPassword(newPassword); + const user = await userRepository.updateUser(userId, { + password: hashedPassword, + }); + + return userRepository.filterSensitiveUserData(user); +} + +export async function getMyProducts(userId) { + const products = await productRepository.getProductsByUser(userId); + + return products.Product; +} \ No newline at end of file From 616dd9ac9ad9db5a7d5d43ae6d8bbbd06825ff2b Mon Sep 17 00:00:00 2001 From: intwocave Date: Wed, 10 Sep 2025 01:23:10 +0900 Subject: [PATCH 059/130] feat: add refreshToken column to User model --- mission_4/prisma/schema.prisma | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mission_4/prisma/schema.prisma b/mission_4/prisma/schema.prisma index 15b204a43..0e23cea27 100644 --- a/mission_4/prisma/schema.prisma +++ b/mission_4/prisma/schema.prisma @@ -53,14 +53,15 @@ model Comment { } model User { - id Int @id @default(autoincrement()) - email String @unique - nickname String - image String? - password String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - Article Article[] - Product Product[] - Comment Comment[] + id Int @id @default(autoincrement()) + email String @unique + nickname String + image String? + password String + refreshToken String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Article Article[] + Product Product[] + Comment Comment[] } From 06a1305238cc80d8755fe64809034bab1621ff11 Mon Sep 17 00:00:00 2001 From: intwocave Date: Wed, 10 Sep 2025 01:23:34 +0900 Subject: [PATCH 060/130] feat: install and use cookie-parser middleware --- mission_4/main.js | 2 ++ mission_4/package-lock.json | 20 ++++++++++++++++++++ mission_4/package.json | 1 + 3 files changed, 23 insertions(+) diff --git a/mission_4/main.js b/mission_4/main.js index eee8fda0d..9c104f0ed 100644 --- a/mission_4/main.js +++ b/mission_4/main.js @@ -1,5 +1,6 @@ import express from 'express'; import cors from 'cors'; +import cookieParser from 'cookie-parser'; import productRouter from './src/router/productRouter.js'; import articleRouter from './src/router/articleRouter.js'; import imageRouter from './src/router/imageRouter.js'; @@ -14,6 +15,7 @@ app.use(express.json()); app.use(cors({ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] })); +app.use(cookieParser()); function logRequest(req, _, next) { console.log(`[${req.method}] ${req.originalUrl}`) diff --git a/mission_4/package-lock.json b/mission_4/package-lock.json index d6538953e..8ef2beae4 100644 --- a/mission_4/package-lock.json +++ b/mission_4/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@prisma/client": "^6.13.0", "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", "cors": "^2.8.5", "express": "^5.1.0", "express-jwt": "^8.5.1", @@ -403,6 +404,25 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, "node_modules/cookie-signature": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", diff --git a/mission_4/package.json b/mission_4/package.json index e4eebb7e0..6fd1088aa 100644 --- a/mission_4/package.json +++ b/mission_4/package.json @@ -12,6 +12,7 @@ "dependencies": { "@prisma/client": "^6.13.0", "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", "cors": "^2.8.5", "express": "^5.1.0", "express-jwt": "^8.5.1", From c4b480c5ae70ab0918543b53a5706cee5077edf5 Mon Sep 17 00:00:00 2001 From: intwocave Date: Wed, 10 Sep 2025 01:23:57 +0900 Subject: [PATCH 061/130] feat: implement refresh token functionality --- mission_4/src/controller/userController.js | 28 +++++++++++++++++++++- mission_4/src/middleware/auth.js | 8 +++++++ mission_4/src/repository/userRepository.js | 2 +- mission_4/src/router/userRouter.js | 5 ++++ mission_4/src/services/userService.js | 19 ++++++++++++--- 5 files changed, 57 insertions(+), 5 deletions(-) diff --git a/mission_4/src/controller/userController.js b/mission_4/src/controller/userController.js index 09c6fbd13..afd020122 100644 --- a/mission_4/src/controller/userController.js +++ b/mission_4/src/controller/userController.js @@ -32,6 +32,13 @@ export async function getAccessToken(req, res, next) { try { const user = await userService.getUser(req.body); const accessToken = userService.createToken(user); + const refreshToken = userService.createToken(user, "refresh"); + await userService.updateUserInfo(user.id, { refreshToken }); + res.cookie("refreshToken", refreshToken, { + httpOnly: true, + sameSite: "None", + secure: true, + }); return res.status(200).json({ accessToken }); } catch (err) { @@ -99,4 +106,23 @@ export async function getMyProducts(req, res, next) { } catch (err) { next(err); } -} \ No newline at end of file +} + +export async function getRefreshToken(req, res, next) { + const userId = req.auth.userId; + const refreshToken = req.cookies.refreshToken; + + if (!refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + next(err); + } + + try { + const accessToken = await userService.refreshToken(userId, refreshToken); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +} diff --git a/mission_4/src/middleware/auth.js b/mission_4/src/middleware/auth.js index ec31c407e..9724e86e0 100644 --- a/mission_4/src/middleware/auth.js +++ b/mission_4/src/middleware/auth.js @@ -9,6 +9,13 @@ const verifyAccessToken = expressjwt({ requestProperty: "user", }); +// refresh 토큰 검증 +const verifyRefreshToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + getToken: (req) => req.cookies.refreshToken, +}); + // 게시글 유저 검증 const verifyArticleAuth = async (req, res, next) => { // Get article id @@ -143,6 +150,7 @@ const verifyProductCommentAuth = async (req, res, next) => { export default { verifyAccessToken, + verifyRefreshToken, verifyArticleAuth, verifyProductAuth, checkArticleExist, diff --git a/mission_4/src/repository/userRepository.js b/mission_4/src/repository/userRepository.js index 2759be3cf..24e0aec5e 100644 --- a/mission_4/src/repository/userRepository.js +++ b/mission_4/src/repository/userRepository.js @@ -43,7 +43,7 @@ export async function hashPassword(password) { } export function filterSensitiveUserData(user) { - const { password, ...rest } = user; + const { password, refreshToken, ...rest } = user; return rest; } diff --git a/mission_4/src/router/userRouter.js b/mission_4/src/router/userRouter.js index d11170e97..9ab871231 100644 --- a/mission_4/src/router/userRouter.js +++ b/mission_4/src/router/userRouter.js @@ -35,5 +35,10 @@ userRouter.get( ); userRouter.post("/login", userController.getAccessToken); +userRouter.post( + "/login/refresh", + auth.verifyRefreshToken, + userController.getRefreshToken +); export default userRouter; diff --git a/mission_4/src/services/userService.js b/mission_4/src/services/userService.js index 9927873f9..db7b24c5c 100644 --- a/mission_4/src/services/userService.js +++ b/mission_4/src/services/userService.js @@ -61,13 +61,26 @@ async function verifyPassword(inputPassword, password) { } } -export function createToken(user) { +export function createToken(user, token) { const payload = { userId: user.id }; - const options = { expiresIn: "1h" }; + const options = { expiresIn: token === "refresh" ? "2w" : "1h" }; return jwt.sign(payload, process.env.JWT_SECRET, options); } +export async function refreshToken(userId, refreshToken) { + const user = await userRepository.findById(userId); + + if (!user || user.refreshToken !== refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 404; + throw err; + } + + const accessToken = createToken(user); + return accessToken; +} + export async function updateUserInfo(userId, toUpdate) { // 수정할 내용이 없다면 에러 처리 if (Object.keys(toUpdate).length === 0) { @@ -94,4 +107,4 @@ export async function getMyProducts(userId) { const products = await productRepository.getProductsByUser(userId); return products.Product; -} \ No newline at end of file +} From 02fccfdb1d170e7fb1c6cd0402eeba6475a279b0 Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 11 Sep 2025 10:49:19 +0900 Subject: [PATCH 062/130] feat: new directory mission_5 with initial files --- mission_5/.gitignore | 8 + mission_5/lib/prisma.js | 5 + mission_5/main.js | 36 + mission_5/package-lock.json | 1938 +++++++++++++++++ mission_5/package.json | 31 + mission_5/prisma/schema.prisma | 67 + mission_5/prisma/seed.js | 95 + mission_5/src/container.js | 1 + mission_5/src/controller/articleController.js | 220 ++ mission_5/src/controller/index.js | 1 + mission_5/src/controller/productController.js | 243 +++ mission_5/src/controller/userController.js | 128 ++ mission_5/src/handler/errorHandler.js | 8 + mission_5/src/middleware/auth.js | 160 ++ mission_5/src/middleware/index.js | 1 + mission_5/src/middleware/validator.js | 35 + mission_5/src/repository/articleRepository.js | 155 ++ mission_5/src/repository/index.js | 1 + mission_5/src/repository/productRepository.js | 169 ++ mission_5/src/repository/userRepository.js | 61 + mission_5/src/router/articleRouter.js | 73 + mission_5/src/router/imageRouter.js | 15 + mission_5/src/router/index.js | 3 + mission_5/src/router/productRouter.js | 71 + mission_5/src/router/userRouter.js | 44 + mission_5/src/services/articleService.js | 57 + mission_5/src/services/index.js | 1 + mission_5/src/services/productService.js | 55 + mission_5/src/services/userService.js | 110 + 29 files changed, 3792 insertions(+) create mode 100644 mission_5/.gitignore create mode 100644 mission_5/lib/prisma.js create mode 100644 mission_5/main.js create mode 100644 mission_5/package-lock.json create mode 100644 mission_5/package.json create mode 100644 mission_5/prisma/schema.prisma create mode 100644 mission_5/prisma/seed.js create mode 100644 mission_5/src/container.js create mode 100644 mission_5/src/controller/articleController.js create mode 100644 mission_5/src/controller/index.js create mode 100644 mission_5/src/controller/productController.js create mode 100644 mission_5/src/controller/userController.js create mode 100644 mission_5/src/handler/errorHandler.js create mode 100644 mission_5/src/middleware/auth.js create mode 100644 mission_5/src/middleware/index.js create mode 100644 mission_5/src/middleware/validator.js create mode 100644 mission_5/src/repository/articleRepository.js create mode 100644 mission_5/src/repository/index.js create mode 100644 mission_5/src/repository/productRepository.js create mode 100644 mission_5/src/repository/userRepository.js create mode 100644 mission_5/src/router/articleRouter.js create mode 100644 mission_5/src/router/imageRouter.js create mode 100644 mission_5/src/router/index.js create mode 100644 mission_5/src/router/productRouter.js create mode 100644 mission_5/src/router/userRouter.js create mode 100644 mission_5/src/services/articleService.js create mode 100644 mission_5/src/services/index.js create mode 100644 mission_5/src/services/productService.js create mode 100644 mission_5/src/services/userService.js diff --git a/mission_5/.gitignore b/mission_5/.gitignore new file mode 100644 index 000000000..d42e3ca1d --- /dev/null +++ b/mission_5/.gitignore @@ -0,0 +1,8 @@ +node_modules +# Keep environment variables out of version control +.env + +/generated/prisma +/prisma/migrations + +todo.list \ No newline at end of file diff --git a/mission_5/lib/prisma.js b/mission_5/lib/prisma.js new file mode 100644 index 000000000..b904402d2 --- /dev/null +++ b/mission_5/lib/prisma.js @@ -0,0 +1,5 @@ +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +export default prisma; \ No newline at end of file diff --git a/mission_5/main.js b/mission_5/main.js new file mode 100644 index 000000000..9c104f0ed --- /dev/null +++ b/mission_5/main.js @@ -0,0 +1,36 @@ +import express from 'express'; +import cors from 'cors'; +import cookieParser from 'cookie-parser'; +import productRouter from './src/router/productRouter.js'; +import articleRouter from './src/router/articleRouter.js'; +import imageRouter from './src/router/imageRouter.js'; +import userRouter from './src/router/userRouter.js'; + +import errorHandler from './src/handler/errorHandler.js'; + +const PORT = process.env.PORT || 3000; + +const app = express(); +app.use(express.json()); +app.use(cors({ + methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] +})); +app.use(cookieParser()); + +function logRequest(req, _, next) { + console.log(`[${req.method}] ${req.originalUrl}`) + next(); +} + +// middleware for logging all http request +app.use(logRequest); + +app.use('/products', productRouter); +app.use('/articles', articleRouter); +app.use('/upload', imageRouter); +app.use(userRouter); + +app.use(errorHandler); +app.use('/upload', express.static('uploads')); + +app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file diff --git a/mission_5/package-lock.json b/mission_5/package-lock.json new file mode 100644 index 000000000..8ef2beae4 --- /dev/null +++ b/mission_5/package-lock.json @@ -0,0 +1,1938 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sprint_mission_3", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "express": "^5.1.0", + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1" + }, + "devDependencies": { + "prisma": "^6.13.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@prisma/client": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.13.0.tgz", + "integrity": "sha512-8m2+I3dQovkV8CkDMluiwEV1TxV9EXdT6xaCz39O6jYw7mkf5gwfmi+cL4LJsEPwz5tG7sreBwkRpEMJedGYUQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.13.0.tgz", + "integrity": "sha512-OYMM+pcrvj/NqNWCGESSxVG3O7kX6oWuGyvufTUNnDw740KIQvNyA4v0eILgkpuwsKIDU36beZCkUtIt0naTog==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.16.12", + "read-package-up": "11.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.13.0.tgz", + "integrity": "sha512-um+9pfKJW0ihmM83id9FXGi5qEbVJ0Vxi1Gm0xpYsjwUBnw6s2LdPBbrsG9QXRX46K4CLWCTNvskXBup4i9hlw==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.13.0.tgz", + "integrity": "sha512-D+1B79LFvtWA0KTt8ALekQ6A/glB9w10ETknH5Y9g1k2NYYQOQy93ffiuqLn3Pl6IPJG3EsK/YMROKEaq8KBrA==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/fetch-engine": "6.13.0", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd.tgz", + "integrity": "sha512-MpPyKSzBX7P/ZY9odp9TSegnS/yH3CSbchQE9f0yBg3l2QyN59I6vGXcoYcqKC9VTniS1s18AMmhyr1OWavjHg==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.13.0.tgz", + "integrity": "sha512-grmmq+4FeFKmaaytA8Ozc2+Tf3BC8xn/DVJos6LL022mfRlMZYjT3hZM0/xG7+5fO95zFG9CkDUs0m1S2rXs5Q==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.13.0.tgz", + "integrity": "sha512-Nii2pX50fY4QKKxQwm7/vvqT6Ku8yYJLZAFX4e2vzHwRdMqjugcOG5hOSLjxqoXb0cvOspV70TOhMzrw8kqAnw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.16.12", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", + "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-jwt": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.5.1.tgz", + "integrity": "sha512-Dv6QjDLpR2jmdb8M6XQXiCcpEom7mK8TOqnr0/TngDKsG2DHVkO8+XnVxkJVN7BuS1I3OrGw6N8j5DaaGgkDRQ==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "^9", + "express-unless": "^2.1.3", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express-unless": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz", + "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==", + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/index-to-position": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", + "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", + "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "mkdirp": "^0.5.6", + "object-assign": "^4.1.1", + "type-is": "^1.6.18", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", + "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "devOptional": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/nypm": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", + "integrity": "sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.2.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/pkg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz", + "integrity": "sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/prisma": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.13.0.tgz", + "integrity": "sha512-dfzORf0AbcEyyzxuv2lEwG8g+WRGF/qDQTpHf/6JoHsyF5MyzCEZwClVaEmw3WXcobgadosOboKUgQU0kFs9kw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.13.0", + "@prisma/engines": "6.13.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "devOptional": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "devOptional": true, + "license": "CC0-1.0" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "devOptional": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/mission_5/package.json b/mission_5/package.json new file mode 100644 index 000000000..6fd1088aa --- /dev/null +++ b/mission_5/package.json @@ -0,0 +1,31 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "express": "^5.1.0", + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1" + }, + "devDependencies": { + "prisma": "^6.13.0" + }, + "prisma": { + "seed": "node prisma/seed.js" + }, + "type": "module" +} diff --git a/mission_5/prisma/schema.prisma b/mission_5/prisma/schema.prisma new file mode 100644 index 000000000..0e23cea27 --- /dev/null +++ b/mission_5/prisma/schema.prisma @@ -0,0 +1,67 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" + // output = "../generated/prisma" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model Product { + id Int @id @default(autoincrement()) + name String + description String + price Int + tags String[] + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] +} + +model Article { + id Int @id @default(autoincrement()) + title String + content String + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] +} + +model Comment { + id Int @id @default(autoincrement()) + name String + content String + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int? + Article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) + articleId Int? +} + +model User { + id Int @id @default(autoincrement()) + email String @unique + nickname String + image String? + password String + refreshToken String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Article Article[] + Product Product[] + Comment Comment[] +} diff --git a/mission_5/prisma/seed.js b/mission_5/prisma/seed.js new file mode 100644 index 000000000..a5c1077d6 --- /dev/null +++ b/mission_5/prisma/seed.js @@ -0,0 +1,95 @@ +// prisma/seed.js +import { PrismaClient } from '@prisma/client'; +const prisma = new PrismaClient(); + +async function main() { + // ------------------------------ + // Product 더미 데이터 생성 + // ------------------------------ + const product1 = await prisma.product.create({ + data: { + name: "게이밍 노트북", + description: "고성능 게이밍 및 작업용 노트북", + price: 1800000, + tags: ["노트북", "게이밍", "고성능",], + comments: { + create: [ + { name: "홍길동", content: "배틀그라운드도 잘 돌아가네요!" }, + { name: "김철수", content: "팬 소음이 조금 있지만 성능은 최고입니다." } + ] + } + } + }); + + const product2 = await prisma.product.create({ + data: { + name: "기계식 키보드", + description: "청축 기계식 키보드, 타건감이 뛰어남", + price: 120000, + tags: ["키보드","기계식","청축",], + comments: { + create: [ + { name: "이영희", content: "타이핑할 맛이 납니다." } + ] + } + } + }); + + // ------------------------------ + // Article 더미 데이터 생성 + // ------------------------------ + const article1 = await prisma.article.create({ + data: { + title: "게이밍 PC 조립 가이드", + content: "부품 선택부터 조립까지 단계별 설명...", + comments: { + create: [ + { name: "박영수", content: "이 글 덕분에 처음으로 PC를 조립했습니다." }, + { name: "최민지", content: "부품 추천이 매우 유용했습니다." } + ] + } + } + }); + + const article2 = await prisma.article.create({ + data: { + title: "2025년 인기 프로그래밍 언어 TOP 10", + content: "올해 주목받는 프로그래밍 언어와 트렌드를 분석...", + comments: { + create: [ + { name: "장우진", content: "Rust가 상위권이라니 반갑네요!" } + ] + } + } + }); + + // ------------------------------ + // Comment 모델 개별 생성 (Product/Article와 직접 연결) + // ------------------------------ + await prisma.comment.create({ + data: { + name: "손흥민", + content: "이 제품은 가격 대비 성능이 좋습니다.", + productId: product1.id + } + }); + + await prisma.comment.create({ + data: { + name: "유재석", + content: "기사 내용이 깔끔하게 잘 정리되어 있네요.", + articleId: article2.id + } + }); + + console.log("시딩이 완료되었습니다."); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/mission_5/src/container.js b/mission_5/src/container.js new file mode 100644 index 000000000..711877055 --- /dev/null +++ b/mission_5/src/container.js @@ -0,0 +1 @@ +import prisma from '../lib/prisma.js'; \ No newline at end of file diff --git a/mission_5/src/controller/articleController.js b/mission_5/src/controller/articleController.js new file mode 100644 index 000000000..82e1042af --- /dev/null +++ b/mission_5/src/controller/articleController.js @@ -0,0 +1,220 @@ +import * as articleService from "../services/articleService.js"; + +export async function createPost(req, res, next) { + const { title, content } = req.body; + const userId = req.user.userId; + + if (!title || !content) { + const err = new Error(); + err.statusCode = 400; + err.message = "Required data is not sufficient"; + next(err); + } + + try { + const article = await articleService.createPost({ userId, title, content }); + res.status(201).json(article); + } catch (err) { + next(err); + } +} + +export async function getPosts(req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search } = req.query; + + try { + const articles = await articleService.getPosts({ + offset, + limit, + sort: sort === "old" ? "asc" : "desc", + search, + }); + + if (articles) res.status(200).json(articles); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function getPost(req, res, next) { + const { id } = req.params; + if (!id) return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const article = await articleService.getPost(id); + + if (article) res.status(200).json(article); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function patchPost(req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + // Columns in model Article + const articleCols = ["title", "content"]; + + // ? + const filteredBody = Object.entries(req.body) + .filter((e) => articleCols.includes(e[0])) + .reduce((obj, ele) => { + obj[ele[0]] = ele[1]; + return obj; + }, {}); + + try { + const article = await articleService.patchPost({ id, ...filteredBody }); + + if (article) res.status(200).json(article); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function deletePost(req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const deleted = await articleService.deletePost(id); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function postComment(req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user.userId; + + if (!name || !content || !pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const comment = await articleService.postComment({ + userId, + name, + content, + pid: Number(pid), + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +} + +export async function getComments(req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + const { cursor, limit = 10 } = req.query; + + const comments = await articleService.getComments({ pid, cursor, limit }); + + if (comments) + res.status(200).json({ + comments, + nextCursor, + }); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comments with board ${board}`; + next(err); + } +} + +export async function patchComment(req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id' and 'cid'"; + next(err); + } + + const { name, content } = req.body; + if (!name || !content) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid SQL Parameters"; + next(err); + } + + const comment = await articleService.patchComment({ + cid, + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comment with ID ${id}`; + next(err); + } +} + +export async function deleteComment(req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id' and 'cid'"; + next(err); + } + + const deleted = await articleService.deleteComment(cid); + + if (deleted) res.status(200).json(deleted); + else res.status(404).json({ message: `Cannot find article with ID ${id}` }); +} diff --git a/mission_5/src/controller/index.js b/mission_5/src/controller/index.js new file mode 100644 index 000000000..1d9c8cc37 --- /dev/null +++ b/mission_5/src/controller/index.js @@ -0,0 +1 @@ +export * from './articleController.js'; \ No newline at end of file diff --git a/mission_5/src/controller/productController.js b/mission_5/src/controller/productController.js new file mode 100644 index 000000000..85cfbcaea --- /dev/null +++ b/mission_5/src/controller/productController.js @@ -0,0 +1,243 @@ +import * as productService from "../services/productService.js"; + +export async function createProduct(req, res, next) { + // destructuring field data from request body + const { name, description, price, tags } = req.body; + const userId = req.user.userId; + + if (!name || !description || !price || !tags) { + const err = new Error(); + err.statusCode = 400; + err.message = "Required data is not sufficient"; + next(err); + } + + try { + // insert into Product table + const product = await productService.createProduct({ + userId, + name, + description, + price, + tags, + }); + + res.status(201).json(product); + } catch (err) { + next(err); + } +} + +export async function getProducts(req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search = "" } = req.query; + + try { + const products = await productService.getProducts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search, + }); + + if (products) res.status(200).json(products); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find products`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function getProduct(req, res, next) { + const { id } = req.params; + if (isNaN(id) || parseInt(id) < 0) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const product = await productService.getProduct(Number(id)); + + if (product) res.status(200).json(product); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find product with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function patchProduct(req, res, next) { + const { id } = req.params; + if (isNaN(id) || parseInt(id) < 0) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + // Attributes in model Product + const productCols = ["name", "description", "price", "tags"]; + + // Possible improvement? + const filteredBody = Object.entries(req.body) + .filter((e) => productCols.includes(e[0])) + .reduce((obj, ele) => { + obj[ele[0]] = ele[1]; + return obj; + }, {}); + + try { + const product = await productService.patchProduct({ id, ...filteredBody }); + + if (product) res.status(200).json(product); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find product with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function deleteProduct(req, res, next) { + const { id } = req.params; + if (isNaN(id) || parseInt(id) < 0) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const deleted = await productService.deleteProduct(id); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find product with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +} + +export async function postComment(req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user.userId; + + // validation + if (!name || !content || !pid) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Comment table + const comment = await productService.postComment({ + userId, + pid: Number(pid), + name, + content, + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +} + +export async function getComments(req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + try { + const comments = await productService.getComments({ + pid: Number(pid), + cursor, + limit: Number(limit), + }); + + // Cursor pagination + const nextCursor = + comments.length > 0 ? comments[comments.length - 1] : null; + + if (comments) + res.status(200).json({ + comments, + nextCursor, + }); + else { + const err = new Error(`Cannot find any comments with board ${board}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +} + +export async function patchComment(req, res, next) { + const { id: pid, cid } = req.params; + const { name, content } = req.body; + if (!pid || !cid || !name || !content) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(`Cannot find any comment with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +} + +export async function deleteComment(req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await productService.deleteComment(Number(cid)); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } +} diff --git a/mission_5/src/controller/userController.js b/mission_5/src/controller/userController.js new file mode 100644 index 000000000..afd020122 --- /dev/null +++ b/mission_5/src/controller/userController.js @@ -0,0 +1,128 @@ +import * as userService from "../services/userService.js"; + +// for Creating user +export async function createUser(req, res, next) { + const { email, nickname, password } = req.body; + + if (!email || !nickname || !password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + next(err); + } + + try { + const userId = await userService.createUser(req.body); + + return res.status(200).json(userId); + } catch (err) { + next(err); + } +} + +// for Login +export async function getAccessToken(req, res, next) { + const { email, password } = req.body; + + if (!email || !password) { + const err = new Error("Email or password is wrong"); + err.statusCode = 404; + next(err); + } + + try { + const user = await userService.getUser(req.body); + const accessToken = userService.createToken(user); + const refreshToken = userService.createToken(user, "refresh"); + await userService.updateUserInfo(user.id, { refreshToken }); + res.cookie("refreshToken", refreshToken, { + httpOnly: true, + sameSite: "None", + secure: true, + }); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +} + +export async function getMyInfo(req, res, next) { + const userId = req.user.userId; + + try { + const user = await userService.getUserById(userId); + + return res.status(200).json(user); + } catch (err) { + next(err); + } +} + +export async function updateMyInfo(req, res, next) { + const userId = req.user.userId; + const { email, nickname } = req.body; + + if (!email && !nickname) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + next(err); + } + + try { + const updatedUser = await userService.updateUserInfo(userId, req.body); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +} + +export async function updateMyPassword(req, res, next) { + const userId = req.user.userId; + const { password } = req.body; + + if (!password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + next(err); + } + + try { + const updatedUser = await userService.updateUserPassword(userId, password); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +} + +export async function getMyProducts(req, res, next) { + const userId = req.user.userId; + + try { + const products = await userService.getMyProducts(userId); + + return res.status(200).json(products); + } catch (err) { + next(err); + } +} + +export async function getRefreshToken(req, res, next) { + const userId = req.auth.userId; + const refreshToken = req.cookies.refreshToken; + + if (!refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + next(err); + } + + try { + const accessToken = await userService.refreshToken(userId, refreshToken); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +} diff --git a/mission_5/src/handler/errorHandler.js b/mission_5/src/handler/errorHandler.js new file mode 100644 index 000000000..0cc4f2a3d --- /dev/null +++ b/mission_5/src/handler/errorHandler.js @@ -0,0 +1,8 @@ +export default function errorHandler(err, req, res, next) { + console.error(`[ERROR] ${err.stack || err.message}`); + + const statusCode = err.statusCode || 500; + const message = err.message || 'Internal server error!'; + + res.status(statusCode).json({ message }); +} \ No newline at end of file diff --git a/mission_5/src/middleware/auth.js b/mission_5/src/middleware/auth.js new file mode 100644 index 000000000..9724e86e0 --- /dev/null +++ b/mission_5/src/middleware/auth.js @@ -0,0 +1,160 @@ +import { expressjwt } from "express-jwt"; +import * as articleRepository from "../repository/articleRepository.js"; +import * as productRepository from "../repository/productRepository.js"; + +// 토큰 검증 +const verifyAccessToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + requestProperty: "user", +}); + +// refresh 토큰 검증 +const verifyRefreshToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + getToken: (req) => req.cookies.refreshToken, +}); + +// 게시글 유저 검증 +const verifyArticleAuth = async (req, res, next) => { + // Get article id + const { id } = req.params; + + // Get article author's id + try { + const article = await articleRepository.getPost(id); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + next(err); + } + + // Call next if valid user + if (req.user.userId === article.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 유저 검증 +const verifyProductAuth = async (req, res, next) => { + // Get product id + const { id } = req.params; + + // Get product uploaders's id + try { + const product = await productRepository.getProduct(id); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + next(err); + } + + // Call next if valid user + if (req.user.userId === product.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + next(err); + } + } catch (err) { + next(err); + } +}; + +// 게시글 존재 여부 확인 +const checkArticleExist = async (req, res, next) => { + const { id } = req.params; + + try { + const article = await articleRepository.getPost(id); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 상품 존재 여부 확인 +const checkProductExist = async (req, res, next) => { + const { id } = req.params; + + try { + const product = await productRepository.getProduct(id); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 게시글 댓글 유저 검증 +const verifyArticleCommentAuth = async (req, res, next) => { + const { cid } = req.params; + + try { + const comment = await articleRepository.getComment(parseInt(cid)); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + next(err); + } + + if (req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 댓글 유저 검증 +const verifyProductCommentAuth = async (req, res, next) => { + const { cid } = req.params; + + try { + const comment = await productRepository.getComment(parseInt(cid)); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + next(err); + } + + if (req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + next(err); + } + } catch (err) { + next(err); + } +}; + +export default { + verifyAccessToken, + verifyRefreshToken, + verifyArticleAuth, + verifyProductAuth, + checkArticleExist, + checkProductExist, + verifyArticleCommentAuth, + verifyProductCommentAuth, +}; diff --git a/mission_5/src/middleware/index.js b/mission_5/src/middleware/index.js new file mode 100644 index 000000000..02584180c --- /dev/null +++ b/mission_5/src/middleware/index.js @@ -0,0 +1 @@ +export * from './validator.js'; \ No newline at end of file diff --git a/mission_5/src/middleware/validator.js b/mission_5/src/middleware/validator.js new file mode 100644 index 000000000..1b58eb14a --- /dev/null +++ b/mission_5/src/middleware/validator.js @@ -0,0 +1,35 @@ +// Verify required parameters are okay +export async function validateProduct (req, res, next) { + const { + name, + description, + price, + tags + } = req.body; + + // validation logic (possible improvements with Zod library in the future) + if ( !name || !description || !price || !tags ) + return res.status(400).json({ message: "Missing required fields" }); + + if (isNaN(price)) + return res.status(400).json({ message: "Price must be a number" }); + + if (!Array.isArray(tags) || !tags.every(tag => typeof tag === 'string')) + return res.status(400).json({ message: "Tags must be an array of string" }); + + next(); +}; + +// Verify required parameters are okay +export async function validateArticle (req, res, next) { + const { + title, + content + } = req.body; + + // validation + if ( !title || !content ) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + next(); +}; \ No newline at end of file diff --git a/mission_5/src/repository/articleRepository.js b/mission_5/src/repository/articleRepository.js new file mode 100644 index 000000000..15c41f0fe --- /dev/null +++ b/mission_5/src/repository/articleRepository.js @@ -0,0 +1,155 @@ +import prisma from "../../lib/prisma.js"; + +export async function createPost({ userId, title, content }) { + return await prisma.article.create({ + data: { + title, + content, + userId, + }, + }); +} + +export async function getPosts({ offset, limit, sort, search }) { + // search에 값이 있을 때만 where로 문자열 검색 + const where = search + ? { + OR: [ + { + title: { + contains: search, + mode: "insensitive", + }, + }, + { + content: { + contains: search, + mode: "insensitive", + }, + }, + ], + } + : {}; + + const result = await prisma.article.findMany({ + select: { + id: true, + title: true, + content: true, + createdAt: true, + }, + orderBy: { + createdAt: sort, + }, + where, + skip: offset * limit, + take: limit, + }); + + return result; +} + +export async function getPost(id) { + const result = await prisma.article.findUnique({ + where: { + id: parseInt(id), + }, + }); + + return result; +} + +export async function patchPost({ id, ...filteredBody }) { + const result = await prisma.article.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deletePost(id) { + const result = await prisma.article.delete({ + where: { + id: Number(id), + }, + }); + + return result; +} + +export async function postComment({ userId, pid, name, content }) { + const result = await prisma.comment.create({ + data: { + name, + content, + articleId: pid, + userId, + }, + }); + + return result; +} + +export async function getComments({ pid, cursor, limit }) { + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + articleId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(cid) { + const result = await prisma.comment.findUnique({ + where: { + id: cid, + }, + }); + + return result; +} + +export async function patchComment({ cid, name, content }) { + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(cid) { + const result = prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} diff --git a/mission_5/src/repository/index.js b/mission_5/src/repository/index.js new file mode 100644 index 000000000..a9bc4c15b --- /dev/null +++ b/mission_5/src/repository/index.js @@ -0,0 +1 @@ +export * from './articleRepository.js'; \ No newline at end of file diff --git a/mission_5/src/repository/productRepository.js b/mission_5/src/repository/productRepository.js new file mode 100644 index 000000000..7c009cf64 --- /dev/null +++ b/mission_5/src/repository/productRepository.js @@ -0,0 +1,169 @@ +import prisma from "../../lib/prisma.js"; + +export async function createProduct({ + userId, + name, + description, + price, + tags, +}) { + return await prisma.product.create({ + data: { + name, + description, + price, + tags, + userId, + }, + }); +} + +export async function getProducts({ offset, limit, sort, search }) { + const result = await prisma.product.findMany({ + select: { + id: true, + name: true, + price: true, + createdAt: true, + }, + orderBy: { + createdAt: sort, + }, + where: { + OR: [ + { + name: { + contains: search, + mode: "insensitive", + }, + }, + { + description: { + contains: search, + mode: "insensitive", + }, + }, + ], + }, + skip: offset * limit, + take: limit, + }); + + return result; +} + +export async function getProduct(id) { + const result = await prisma.product.findUnique({ + where: { + id: parseInt(id), + }, + }); + + return result; +} + +export async function patchProduct({ id, ...filteredBody }) { + const result = await prisma.product.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deleteProduct(id) { + const result = await prisma.product.delete({ + where: { + id: Number(id), + }, + }); + + return result; +} + +export async function postComment({ userId, pid, name, content }) { + const result = await prisma.comment.create({ + data: { + userId, + name, + content, + productId: pid, + }, + }); + + return result; +} + +export async function getComments({ pid, cursor, limit }) { + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + productId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(cid) { + const result = await prisma.comment.findUnique({ + where: { + id: cid, + }, + }); + + return result; +} + +export async function patchComment({ cid, name, content }) { + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(cid) { + const result = await prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} + +export async function getProductsByUser(userId) { + const products = await prisma.user.findUnique({ + where: { id: userId }, + select: { + Product: true, + }, + }); + + return products; +} \ No newline at end of file diff --git a/mission_5/src/repository/userRepository.js b/mission_5/src/repository/userRepository.js new file mode 100644 index 000000000..24e0aec5e --- /dev/null +++ b/mission_5/src/repository/userRepository.js @@ -0,0 +1,61 @@ +import e from "express"; +import prisma from "../../lib/prisma.js"; +import bcrypt from "bcrypt"; + +export async function createUser(user) { + const hashedPassword = await hashPassword(user.password); + + const createdUser = await prisma.user.create({ + data: { + ...user, + password: hashedPassword, // This line overwrites user.password + }, + }); + + return createdUser; +} + +export async function findByEmail(email) { + const result = await prisma.user.findFirst({ + where: { + email, + }, + }); + + return result; +} + +export async function findById(id) { + const result = await prisma.user.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function hashPassword(password) { + const salt = await bcrypt.genSalt(10); + const hash = await bcrypt.hash(password, salt); + + return hash; +} + +export function filterSensitiveUserData(user) { + const { password, refreshToken, ...rest } = user; + return rest; +} + +export async function updateUser(id, toUpdate) { + if (toUpdate.password) { + toUpdate.password = await hashPassword(toUpdate.password); + } + + const updatedUser = await prisma.user.update({ + where: { id }, + data: toUpdate, + }); + + return updatedUser; +} diff --git a/mission_5/src/router/articleRouter.js b/mission_5/src/router/articleRouter.js new file mode 100644 index 000000000..6599813b0 --- /dev/null +++ b/mission_5/src/router/articleRouter.js @@ -0,0 +1,73 @@ +import express from "express"; +import { validateArticle } from "../middleware/index.js"; +import auth from "../middleware/auth.js"; +import * as articleController from "../controller/articleController.js"; + +const router = express.Router(); + +router + .route("/") + + // Create a post + .post( + auth.verifyAccessToken, + validateArticle, + articleController.createPost + ) + + // Inquiry all articles + .get(articleController.getPosts); + +router + .route("/:id") + + // Get informations of a certain article + .get(articleController.getPost) + + // Modify a article property + .patch( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.patchPost + ) + + // Delete a particular article + .delete( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.deletePost + ); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkArticleExist, + articleController.postComment + ) + + // Inquery all comments + .get(auth.checkArticleExist, articleController.getComments); + +router + .route("/:id/comments/:cid") + + // Modify comment + .patch( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.patchComment + ) + + // Delete comment + .delete( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.deleteComment + ); + +export default router; diff --git a/mission_5/src/router/imageRouter.js b/mission_5/src/router/imageRouter.js new file mode 100644 index 000000000..467943419 --- /dev/null +++ b/mission_5/src/router/imageRouter.js @@ -0,0 +1,15 @@ +import express from 'express'; +import multer from "multer"; + +const router = express.Router(); + +const upload = multer({ dest: 'uploads/' }); + +// 이미지 리사이징 기능 구현 예정 +router.post('/', upload.single('image'), async (req, res) => { + // console.log(req.file); + res.status(201).json({ message: 'Upload OK', filePath: req.file.path }); +}); + + +export default router; \ No newline at end of file diff --git a/mission_5/src/router/index.js b/mission_5/src/router/index.js new file mode 100644 index 000000000..921cc19ab --- /dev/null +++ b/mission_5/src/router/index.js @@ -0,0 +1,3 @@ +export * from './articleRouter.js'; +export * from './productRouter.js'; +export * from './imageRouter.js'; \ No newline at end of file diff --git a/mission_5/src/router/productRouter.js b/mission_5/src/router/productRouter.js new file mode 100644 index 000000000..ebecb4166 --- /dev/null +++ b/mission_5/src/router/productRouter.js @@ -0,0 +1,71 @@ +import express from "express"; +import { validateProduct } from "../middleware/validator.js"; +import auth from "../middleware/auth.js"; +import * as productController from "../controller/productController.js"; + +const router = express.Router(); + +router + .route("/") + + // Upload a new product + .post( + auth.verifyAccessToken, + validateProduct, + productController.createProduct + ) + + // Inquiry all products + .get(productController.getProducts); + +router + .route("/:id") + + // Get informations of a certain product + .get(productController.getProduct) + + // Modify a product property + .patch( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.patchProduct + ) + + // Delete a particular product + .delete( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.deleteProduct + ); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkProductExist, + productController.postComment + ) + + // Inquery all comments + .get(auth.checkProductExist, productController.getComments); + +router + .route("/:id/comments/:cid") + + .patch( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.patchComment + ) + + .delete( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.deleteComment + ); + +export default router; diff --git a/mission_5/src/router/userRouter.js b/mission_5/src/router/userRouter.js new file mode 100644 index 000000000..9ab871231 --- /dev/null +++ b/mission_5/src/router/userRouter.js @@ -0,0 +1,44 @@ +import express from "express"; +import * as userController from "../controller/userController.js"; +import auth from "../middleware/auth.js"; + +const userRouter = express.Router(); + +userRouter + .route("/users") + + // Create user + .post(userController.createUser) + + // Get my(user) info + .get(auth.verifyAccessToken, userController.getMyInfo); + +// Update user info (nickname, email) +userRouter.patch( + "/users/info", + auth.verifyAccessToken, + userController.updateMyInfo +); + +// Update user password +userRouter.patch( + "/users/password", + auth.verifyAccessToken, + userController.updateMyPassword +); + +// Get product lists uploaded by user +userRouter.get( + "/users/products", + auth.verifyAccessToken, + userController.getMyProducts +); + +userRouter.post("/login", userController.getAccessToken); +userRouter.post( + "/login/refresh", + auth.verifyRefreshToken, + userController.getRefreshToken +); + +export default userRouter; diff --git a/mission_5/src/services/articleService.js b/mission_5/src/services/articleService.js new file mode 100644 index 000000000..c390e9ee5 --- /dev/null +++ b/mission_5/src/services/articleService.js @@ -0,0 +1,57 @@ +import * as articleRepository from "../repository/articleRepository.js"; + +export async function createPost(data) { + const result = await articleRepository.createPost(data); + + return result; +} + +export async function getPosts(data) { + // 기본 desc + data.sort = data.sort === "old" ? "asc" : "desc"; + + const result = await articleRepository.getPosts(data); + + return result; +} + +export async function getPost(id) { + const result = await articleRepository.getPost(id); + + return result; +} + +export async function patchPost(data) { + const result = await articleRepository.patchPost(data); + + return result; +} + +export async function deletePost(id) { + const result = await articleRepository.deletePost(id); + + return result; +} + +export async function postComment(data) { + const result = await articleRepository.postComment(data); + + return result; +} + +export async function getComments(data) { + const result = await articleRepository.getComments(data); + + return result; +} + +export async function patchComment(data) { + const result = await articleRepository.patchComment(data); + + return result; +} +export async function deleteComment(data) { + const result = await articleRepository.deleteComment(data); + + return result; +} diff --git a/mission_5/src/services/index.js b/mission_5/src/services/index.js new file mode 100644 index 000000000..ce045fa9e --- /dev/null +++ b/mission_5/src/services/index.js @@ -0,0 +1 @@ +export * from './articleService.js'; \ No newline at end of file diff --git a/mission_5/src/services/productService.js b/mission_5/src/services/productService.js new file mode 100644 index 000000000..74fa32db4 --- /dev/null +++ b/mission_5/src/services/productService.js @@ -0,0 +1,55 @@ +import * as productRepository from "../repository/productRepository.js"; + +export async function createProduct(data) { + const result = await productRepository.createProduct(data); + + return result; +} + +export async function getProducts(data) { + const result = await productRepository.getProducts(data); + + return result; +} + +export async function getProduct(data) { + const result = await productRepository.getProduct(data); + + return result; +} + +export async function patchProduct(data) { + const result = await productRepository.patchProduct(data); + + return result; +} + +export async function deleteProduct(data) { + const result = await productRepository.deleteProduct(data); + + return result; +} + +export async function postComment(data) { + const result = await productRepository.postComment(data); + + return result; +} + +export async function getComments(data) { + const result = await productRepository.getComments(data); + + return result; +} + +export async function patchComment(data) { + const result = await productRepository.patchComment(data); + + return result; +} + +export async function deleteComment(data) { + const result = await productRepository.deleteComment(data); + + return result; +} diff --git a/mission_5/src/services/userService.js b/mission_5/src/services/userService.js new file mode 100644 index 000000000..db7b24c5c --- /dev/null +++ b/mission_5/src/services/userService.js @@ -0,0 +1,110 @@ +import * as userRepository from "../repository/userRepository.js"; +import * as productRepository from "../repository/productRepository.js"; +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; + +export async function createUser(user) { + // 이미 가입된 이메일인지 검증 + const existedUser = await userRepository.findByEmail(user.email); + + if (existedUser) { + const err = new Error("User already exists"); + err.statusCode = 422; + err.data = { email: user.email }; + throw err; + } + + const createdUser = await userRepository.createUser(user); + const createdUserId = await userRepository.filterSensitiveUserData( + createdUser + ).id; + + return createdUserId; +} + +export async function getUser({ email, password }) { + const user = await userRepository.findByEmail(email); + + // If user is invalid + if (!user) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + throw err; + } + + // Verifying password + await verifyPassword(password, user.password); + + // Return without password + return userRepository.filterSensitiveUserData(user); +} + +export async function getUserById(userId) { + const user = await userRepository.findById(userId); + + if (!user) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return userRepository.filterSensitiveUserData(user); +} + +async function verifyPassword(inputPassword, password) { + const isVerified = await bcrypt.compare(inputPassword, password); + + if (!isVerified) { + const err = new Error("Password is wrong"); + err.statusCode = 401; + throw err; + } +} + +export function createToken(user, token) { + const payload = { userId: user.id }; + const options = { expiresIn: token === "refresh" ? "2w" : "1h" }; + + return jwt.sign(payload, process.env.JWT_SECRET, options); +} + +export async function refreshToken(userId, refreshToken) { + const user = await userRepository.findById(userId); + + if (!user || user.refreshToken !== refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 404; + throw err; + } + + const accessToken = createToken(user); + return accessToken; +} + +export async function updateUserInfo(userId, toUpdate) { + // 수정할 내용이 없다면 에러 처리 + if (Object.keys(toUpdate).length === 0) { + const err = new Error("No data to update"); + err.statusCode = 400; + throw err; + } + + const updatedUser = await userRepository.updateUser(userId, toUpdate); + + return userRepository.filterSensitiveUserData(updatedUser); +} + +export async function updateUserPassword(userId, newPassword) { + const hashedPassword = await userRepository.hashPassword(newPassword); + const user = await userRepository.updateUser(userId, { + password: hashedPassword, + }); + + return userRepository.filterSensitiveUserData(user); +} + +export async function getMyProducts(userId) { + const products = await productRepository.getProductsByUser(userId); + + return products.Product; +} From bd74d86b9b2a3efc9a61b7e4ab7b80204d164638 Mon Sep 17 00:00:00 2001 From: intwocave Date: Wed, 17 Sep 2025 18:41:10 +0900 Subject: [PATCH 063/130] refactor: rename extensions from .js to .ts --- mission_5/lib/prisma.js | 5 - mission_5/main.js | 36 --- mission_5/prisma/seed.js | 95 ------- mission_5/src/container.js | 1 - mission_5/src/controller/articleController.js | 220 ---------------- mission_5/src/controller/index.js | 1 - mission_5/src/controller/productController.js | 243 ------------------ mission_5/src/controller/userController.js | 128 --------- mission_5/src/handler/errorHandler.js | 8 - mission_5/src/middleware/auth.js | 160 ------------ mission_5/src/middleware/index.js | 1 - mission_5/src/middleware/validator.js | 35 --- mission_5/src/repository/articleRepository.js | 155 ----------- mission_5/src/repository/index.js | 1 - mission_5/src/repository/productRepository.js | 169 ------------ mission_5/src/repository/userRepository.js | 61 ----- mission_5/src/router/articleRouter.js | 73 ------ mission_5/src/router/imageRouter.js | 15 -- mission_5/src/router/index.js | 3 - mission_5/src/router/productRouter.js | 71 ----- mission_5/src/router/userRouter.js | 44 ---- mission_5/src/services/articleService.js | 57 ---- mission_5/src/services/index.js | 1 - mission_5/src/services/productService.js | 55 ---- mission_5/src/services/userService.js | 110 -------- 25 files changed, 1748 deletions(-) delete mode 100644 mission_5/lib/prisma.js delete mode 100644 mission_5/main.js delete mode 100644 mission_5/prisma/seed.js delete mode 100644 mission_5/src/container.js delete mode 100644 mission_5/src/controller/articleController.js delete mode 100644 mission_5/src/controller/index.js delete mode 100644 mission_5/src/controller/productController.js delete mode 100644 mission_5/src/controller/userController.js delete mode 100644 mission_5/src/handler/errorHandler.js delete mode 100644 mission_5/src/middleware/auth.js delete mode 100644 mission_5/src/middleware/index.js delete mode 100644 mission_5/src/middleware/validator.js delete mode 100644 mission_5/src/repository/articleRepository.js delete mode 100644 mission_5/src/repository/index.js delete mode 100644 mission_5/src/repository/productRepository.js delete mode 100644 mission_5/src/repository/userRepository.js delete mode 100644 mission_5/src/router/articleRouter.js delete mode 100644 mission_5/src/router/imageRouter.js delete mode 100644 mission_5/src/router/index.js delete mode 100644 mission_5/src/router/productRouter.js delete mode 100644 mission_5/src/router/userRouter.js delete mode 100644 mission_5/src/services/articleService.js delete mode 100644 mission_5/src/services/index.js delete mode 100644 mission_5/src/services/productService.js delete mode 100644 mission_5/src/services/userService.js diff --git a/mission_5/lib/prisma.js b/mission_5/lib/prisma.js deleted file mode 100644 index b904402d2..000000000 --- a/mission_5/lib/prisma.js +++ /dev/null @@ -1,5 +0,0 @@ -import { PrismaClient } from '@prisma/client'; - -const prisma = new PrismaClient(); - -export default prisma; \ No newline at end of file diff --git a/mission_5/main.js b/mission_5/main.js deleted file mode 100644 index 9c104f0ed..000000000 --- a/mission_5/main.js +++ /dev/null @@ -1,36 +0,0 @@ -import express from 'express'; -import cors from 'cors'; -import cookieParser from 'cookie-parser'; -import productRouter from './src/router/productRouter.js'; -import articleRouter from './src/router/articleRouter.js'; -import imageRouter from './src/router/imageRouter.js'; -import userRouter from './src/router/userRouter.js'; - -import errorHandler from './src/handler/errorHandler.js'; - -const PORT = process.env.PORT || 3000; - -const app = express(); -app.use(express.json()); -app.use(cors({ - methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] -})); -app.use(cookieParser()); - -function logRequest(req, _, next) { - console.log(`[${req.method}] ${req.originalUrl}`) - next(); -} - -// middleware for logging all http request -app.use(logRequest); - -app.use('/products', productRouter); -app.use('/articles', articleRouter); -app.use('/upload', imageRouter); -app.use(userRouter); - -app.use(errorHandler); -app.use('/upload', express.static('uploads')); - -app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); \ No newline at end of file diff --git a/mission_5/prisma/seed.js b/mission_5/prisma/seed.js deleted file mode 100644 index a5c1077d6..000000000 --- a/mission_5/prisma/seed.js +++ /dev/null @@ -1,95 +0,0 @@ -// prisma/seed.js -import { PrismaClient } from '@prisma/client'; -const prisma = new PrismaClient(); - -async function main() { - // ------------------------------ - // Product 더미 데이터 생성 - // ------------------------------ - const product1 = await prisma.product.create({ - data: { - name: "게이밍 노트북", - description: "고성능 게이밍 및 작업용 노트북", - price: 1800000, - tags: ["노트북", "게이밍", "고성능",], - comments: { - create: [ - { name: "홍길동", content: "배틀그라운드도 잘 돌아가네요!" }, - { name: "김철수", content: "팬 소음이 조금 있지만 성능은 최고입니다." } - ] - } - } - }); - - const product2 = await prisma.product.create({ - data: { - name: "기계식 키보드", - description: "청축 기계식 키보드, 타건감이 뛰어남", - price: 120000, - tags: ["키보드","기계식","청축",], - comments: { - create: [ - { name: "이영희", content: "타이핑할 맛이 납니다." } - ] - } - } - }); - - // ------------------------------ - // Article 더미 데이터 생성 - // ------------------------------ - const article1 = await prisma.article.create({ - data: { - title: "게이밍 PC 조립 가이드", - content: "부품 선택부터 조립까지 단계별 설명...", - comments: { - create: [ - { name: "박영수", content: "이 글 덕분에 처음으로 PC를 조립했습니다." }, - { name: "최민지", content: "부품 추천이 매우 유용했습니다." } - ] - } - } - }); - - const article2 = await prisma.article.create({ - data: { - title: "2025년 인기 프로그래밍 언어 TOP 10", - content: "올해 주목받는 프로그래밍 언어와 트렌드를 분석...", - comments: { - create: [ - { name: "장우진", content: "Rust가 상위권이라니 반갑네요!" } - ] - } - } - }); - - // ------------------------------ - // Comment 모델 개별 생성 (Product/Article와 직접 연결) - // ------------------------------ - await prisma.comment.create({ - data: { - name: "손흥민", - content: "이 제품은 가격 대비 성능이 좋습니다.", - productId: product1.id - } - }); - - await prisma.comment.create({ - data: { - name: "유재석", - content: "기사 내용이 깔끔하게 잘 정리되어 있네요.", - articleId: article2.id - } - }); - - console.log("시딩이 완료되었습니다."); -} - -main() - .catch((e) => { - console.error(e); - process.exit(1); - }) - .finally(async () => { - await prisma.$disconnect(); - }); diff --git a/mission_5/src/container.js b/mission_5/src/container.js deleted file mode 100644 index 711877055..000000000 --- a/mission_5/src/container.js +++ /dev/null @@ -1 +0,0 @@ -import prisma from '../lib/prisma.js'; \ No newline at end of file diff --git a/mission_5/src/controller/articleController.js b/mission_5/src/controller/articleController.js deleted file mode 100644 index 82e1042af..000000000 --- a/mission_5/src/controller/articleController.js +++ /dev/null @@ -1,220 +0,0 @@ -import * as articleService from "../services/articleService.js"; - -export async function createPost(req, res, next) { - const { title, content } = req.body; - const userId = req.user.userId; - - if (!title || !content) { - const err = new Error(); - err.statusCode = 400; - err.message = "Required data is not sufficient"; - next(err); - } - - try { - const article = await articleService.createPost({ userId, title, content }); - res.status(201).json(article); - } catch (err) { - next(err); - } -} - -export async function getPosts(req, res, next) { - const { offset = 0, limit = 10, sort = "recent", search } = req.query; - - try { - const articles = await articleService.getPosts({ - offset, - limit, - sort: sort === "old" ? "asc" : "desc", - search, - }); - - if (articles) res.status(200).json(articles); - else { - const err = new Error(); - err.statusCode = 404; - err.message = `Cannot find article with ID ${id}`; - next(err); - } - } catch (err) { - next(err); - } -} - -export async function getPost(req, res, next) { - const { id } = req.params; - if (!id) return res.status(400).json({ message: "Invalid parameter 'id'" }); - - try { - const article = await articleService.getPost(id); - - if (article) res.status(200).json(article); - else { - const err = new Error(); - err.statusCode = 404; - err.message = `Cannot find article with ID ${id}`; - next(err); - } - } catch (err) { - next(err); - } -} - -export async function patchPost(req, res, next) { - const { id } = req.params; - if (!id) { - const err = new Error(); - err.statusCode = 400; - err.message = "Invalid parameter 'id'"; - next(err); - } - - // Columns in model Article - const articleCols = ["title", "content"]; - - // ? - const filteredBody = Object.entries(req.body) - .filter((e) => articleCols.includes(e[0])) - .reduce((obj, ele) => { - obj[ele[0]] = ele[1]; - return obj; - }, {}); - - try { - const article = await articleService.patchPost({ id, ...filteredBody }); - - if (article) res.status(200).json(article); - else { - const err = new Error(); - err.statusCode = 404; - err.message = `Cannot find article with ID ${id}`; - next(err); - } - } catch (err) { - next(err); - } -} - -export async function deletePost(req, res, next) { - const { id } = req.params; - if (!id) { - const err = new Error(); - err.statusCode = 400; - err.message = "Invalid parameter 'id'"; - next(err); - } - - try { - const deleted = await articleService.deletePost(id); - - if (deleted) res.status(200).json(deleted); - else { - const err = new Error(); - err.statusCode = 404; - err.message = `Cannot find article with ID ${id}`; - next(err); - } - } catch (err) { - next(err); - } -} - -export async function postComment(req, res, next) { - const { id: pid } = req.params; - const { name, content } = req.body; - const userId = req.user.userId; - - if (!name || !content || !pid) { - const err = new Error(); - err.statusCode = 400; - err.message = "Invalid parameter 'id'"; - next(err); - } - - try { - const comment = await articleService.postComment({ - userId, - name, - content, - pid: Number(pid), - }); - - res.status(201).json(comment); - } catch (err) { - next(err); - } -} - -export async function getComments(req, res, next) { - const { id: pid } = req.params; - if (!pid) { - const err = new Error(); - err.statusCode = 400; - err.message = "Invalid parameter 'id'"; - next(err); - } - - const { cursor, limit = 10 } = req.query; - - const comments = await articleService.getComments({ pid, cursor, limit }); - - if (comments) - res.status(200).json({ - comments, - nextCursor, - }); - else { - const err = new Error(); - err.statusCode = 404; - err.message = `Cannot find any comments with board ${board}`; - next(err); - } -} - -export async function patchComment(req, res, next) { - const { id: pid, cid } = req.params; - if (!pid || !cid) { - const err = new Error(); - err.statusCode = 400; - err.message = "Invalid parameter 'id' and 'cid'"; - next(err); - } - - const { name, content } = req.body; - if (!name || !content) { - const err = new Error(); - err.statusCode = 400; - err.message = "Invalid SQL Parameters"; - next(err); - } - - const comment = await articleService.patchComment({ - cid, - name, - content, - }); - - if (comment) res.status(200).json(comment); - else { - const err = new Error(); - err.statusCode = 404; - err.message = `Cannot find any comment with ID ${id}`; - next(err); - } -} - -export async function deleteComment(req, res, next) { - const { id: pid, cid } = req.params; - if (!pid || !cid) { - const err = new Error(); - err.statusCode = 400; - err.message = "Invalid parameter 'id' and 'cid'"; - next(err); - } - - const deleted = await articleService.deleteComment(cid); - - if (deleted) res.status(200).json(deleted); - else res.status(404).json({ message: `Cannot find article with ID ${id}` }); -} diff --git a/mission_5/src/controller/index.js b/mission_5/src/controller/index.js deleted file mode 100644 index 1d9c8cc37..000000000 --- a/mission_5/src/controller/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './articleController.js'; \ No newline at end of file diff --git a/mission_5/src/controller/productController.js b/mission_5/src/controller/productController.js deleted file mode 100644 index 85cfbcaea..000000000 --- a/mission_5/src/controller/productController.js +++ /dev/null @@ -1,243 +0,0 @@ -import * as productService from "../services/productService.js"; - -export async function createProduct(req, res, next) { - // destructuring field data from request body - const { name, description, price, tags } = req.body; - const userId = req.user.userId; - - if (!name || !description || !price || !tags) { - const err = new Error(); - err.statusCode = 400; - err.message = "Required data is not sufficient"; - next(err); - } - - try { - // insert into Product table - const product = await productService.createProduct({ - userId, - name, - description, - price, - tags, - }); - - res.status(201).json(product); - } catch (err) { - next(err); - } -} - -export async function getProducts(req, res, next) { - const { offset = 0, limit = 10, sort = "recent", search = "" } = req.query; - - try { - const products = await productService.getProducts({ - offset: Number(offset), - limit: Number(limit), - sort: sort === "old" ? "asc" : "desc", - search, - }); - - if (products) res.status(200).json(products); - else { - const err = new Error(); - err.statusCode = 404; - err.message = `Cannot find products`; - next(err); - } - } catch (err) { - next(err); - } -} - -export async function getProduct(req, res, next) { - const { id } = req.params; - if (isNaN(id) || parseInt(id) < 0) { - const err = new Error(); - err.statusCode = 400; - err.message = "Invalid parameter 'id'"; - next(err); - } - - try { - const product = await productService.getProduct(Number(id)); - - if (product) res.status(200).json(product); - else { - const err = new Error(); - err.statusCode = 404; - err.message = `Cannot find product with ID ${id}`; - next(err); - } - } catch (err) { - next(err); - } -} - -export async function patchProduct(req, res, next) { - const { id } = req.params; - if (isNaN(id) || parseInt(id) < 0) { - const err = new Error(); - err.statusCode = 400; - err.message = "Invalid parameter 'id'"; - next(err); - } - - // Attributes in model Product - const productCols = ["name", "description", "price", "tags"]; - - // Possible improvement? - const filteredBody = Object.entries(req.body) - .filter((e) => productCols.includes(e[0])) - .reduce((obj, ele) => { - obj[ele[0]] = ele[1]; - return obj; - }, {}); - - try { - const product = await productService.patchProduct({ id, ...filteredBody }); - - if (product) res.status(200).json(product); - else { - const err = new Error(); - err.statusCode = 404; - err.message = `Cannot find product with ID ${id}`; - next(err); - } - } catch (err) { - next(err); - } -} - -export async function deleteProduct(req, res, next) { - const { id } = req.params; - if (isNaN(id) || parseInt(id) < 0) { - const err = new Error(); - err.statusCode = 400; - err.message = "Invalid parameter 'id'"; - next(err); - } - - try { - const deleted = await productService.deleteProduct(id); - - if (deleted) res.status(200).json(deleted); - else { - const err = new Error(); - err.statusCode = 404; - err.message = `Cannot find product with ID ${id}`; - next(err); - } - } catch (err) { - next(err); - } -} - -export async function postComment(req, res, next) { - const { id: pid } = req.params; - const { name, content } = req.body; - const userId = req.user.userId; - - // validation - if (!name || !content || !pid) { - const err = new Error("Required data is not sufficient"); - err.statusCode = 400; - return next(err); - } - - try { - // insert into Comment table - const comment = await productService.postComment({ - userId, - pid: Number(pid), - name, - content, - }); - - res.status(201).json(comment); - } catch (err) { - next(err); - } -} - -export async function getComments(req, res, next) { - const { id: pid } = req.params; - if (!pid) { - const err = new Error("Invalid parameter 'id'"); - err.statusCode = 400; - return next(err); - } - - const { cursor, limit = 10 } = req.query; - - try { - const comments = await productService.getComments({ - pid: Number(pid), - cursor, - limit: Number(limit), - }); - - // Cursor pagination - const nextCursor = - comments.length > 0 ? comments[comments.length - 1] : null; - - if (comments) - res.status(200).json({ - comments, - nextCursor, - }); - else { - const err = new Error(`Cannot find any comments with board ${board}`); - err.statusCode = 404; - return next(err); - } - } catch (err) { - next(err); - } -} - -export async function patchComment(req, res, next) { - const { id: pid, cid } = req.params; - const { name, content } = req.body; - if (!pid || !cid || !name || !content) { - const err = new Error("Invalid parameter 'id' and 'cid'"); - err.statusCode = 400; - return next(err); - } - - try { - const comment = await productService.patchComment({ - cid: Number(cid), - name, - content, - }); - - if (comment) res.status(200).json(comment); - else { - const err = new Error(`Cannot find any comment with ID ${id}`); - err.statusCode = 404; - return next(err); - } - } catch (err) { - next(err); - } -} - -export async function deleteComment(req, res, next) { - const { id: pid, cid } = req.params; - if (!pid || !cid) { - const err = new Error("Invalid parameter 'id' and 'cid'"); - err.statusCode = 400; - return next(err); - } - - const deleted = await productService.deleteComment(Number(cid)); - - if (deleted) res.status(200).json(deleted); - else { - const err = new Error(`Cannot find product with ID ${id}`); - err.statusCode = 404; - return next(err); - } -} diff --git a/mission_5/src/controller/userController.js b/mission_5/src/controller/userController.js deleted file mode 100644 index afd020122..000000000 --- a/mission_5/src/controller/userController.js +++ /dev/null @@ -1,128 +0,0 @@ -import * as userService from "../services/userService.js"; - -// for Creating user -export async function createUser(req, res, next) { - const { email, nickname, password } = req.body; - - if (!email || !nickname || !password) { - const err = new Error("Required parameter is missing"); - err.statusCode = 400; - next(err); - } - - try { - const userId = await userService.createUser(req.body); - - return res.status(200).json(userId); - } catch (err) { - next(err); - } -} - -// for Login -export async function getAccessToken(req, res, next) { - const { email, password } = req.body; - - if (!email || !password) { - const err = new Error("Email or password is wrong"); - err.statusCode = 404; - next(err); - } - - try { - const user = await userService.getUser(req.body); - const accessToken = userService.createToken(user); - const refreshToken = userService.createToken(user, "refresh"); - await userService.updateUserInfo(user.id, { refreshToken }); - res.cookie("refreshToken", refreshToken, { - httpOnly: true, - sameSite: "None", - secure: true, - }); - - return res.status(200).json({ accessToken }); - } catch (err) { - next(err); - } -} - -export async function getMyInfo(req, res, next) { - const userId = req.user.userId; - - try { - const user = await userService.getUserById(userId); - - return res.status(200).json(user); - } catch (err) { - next(err); - } -} - -export async function updateMyInfo(req, res, next) { - const userId = req.user.userId; - const { email, nickname } = req.body; - - if (!email && !nickname) { - const err = new Error("Required parameter is missing"); - err.statusCode = 400; - next(err); - } - - try { - const updatedUser = await userService.updateUserInfo(userId, req.body); - - return res.status(200).json(updatedUser); - } catch (err) { - next(err); - } -} - -export async function updateMyPassword(req, res, next) { - const userId = req.user.userId; - const { password } = req.body; - - if (!password) { - const err = new Error("Required parameter is missing"); - err.statusCode = 400; - next(err); - } - - try { - const updatedUser = await userService.updateUserPassword(userId, password); - - return res.status(200).json(updatedUser); - } catch (err) { - next(err); - } -} - -export async function getMyProducts(req, res, next) { - const userId = req.user.userId; - - try { - const products = await userService.getMyProducts(userId); - - return res.status(200).json(products); - } catch (err) { - next(err); - } -} - -export async function getRefreshToken(req, res, next) { - const userId = req.auth.userId; - const refreshToken = req.cookies.refreshToken; - - if (!refreshToken) { - const err = new Error("Unauthorized"); - err.statusCode = 401; - next(err); - } - - try { - const accessToken = await userService.refreshToken(userId, refreshToken); - - return res.status(200).json({ accessToken }); - } catch (err) { - next(err); - } -} diff --git a/mission_5/src/handler/errorHandler.js b/mission_5/src/handler/errorHandler.js deleted file mode 100644 index 0cc4f2a3d..000000000 --- a/mission_5/src/handler/errorHandler.js +++ /dev/null @@ -1,8 +0,0 @@ -export default function errorHandler(err, req, res, next) { - console.error(`[ERROR] ${err.stack || err.message}`); - - const statusCode = err.statusCode || 500; - const message = err.message || 'Internal server error!'; - - res.status(statusCode).json({ message }); -} \ No newline at end of file diff --git a/mission_5/src/middleware/auth.js b/mission_5/src/middleware/auth.js deleted file mode 100644 index 9724e86e0..000000000 --- a/mission_5/src/middleware/auth.js +++ /dev/null @@ -1,160 +0,0 @@ -import { expressjwt } from "express-jwt"; -import * as articleRepository from "../repository/articleRepository.js"; -import * as productRepository from "../repository/productRepository.js"; - -// 토큰 검증 -const verifyAccessToken = expressjwt({ - secret: process.env.JWT_SECRET, - algorithms: ["HS256"], - requestProperty: "user", -}); - -// refresh 토큰 검증 -const verifyRefreshToken = expressjwt({ - secret: process.env.JWT_SECRET, - algorithms: ["HS256"], - getToken: (req) => req.cookies.refreshToken, -}); - -// 게시글 유저 검증 -const verifyArticleAuth = async (req, res, next) => { - // Get article id - const { id } = req.params; - - // Get article author's id - try { - const article = await articleRepository.getPost(id); - if (!article) { - const err = new Error(`Article ${id} not found`); - err.statusCode = 404; - next(err); - } - - // Call next if valid user - if (req.user.userId === article.userId) next(); - else { - const err = new Error("Unauthorized"); - err.statusCode = 403; - next(err); - } - } catch (err) { - next(err); - } -}; - -// 상품 유저 검증 -const verifyProductAuth = async (req, res, next) => { - // Get product id - const { id } = req.params; - - // Get product uploaders's id - try { - const product = await productRepository.getProduct(id); - if (!product) { - const err = new Error(`Product ${id} not found`); - err.statusCode = 404; - next(err); - } - - // Call next if valid user - if (req.user.userId === product.userId) next(); - else { - const err = new Error("Unauthorized"); - err.statusCode = 403; - next(err); - } - } catch (err) { - next(err); - } -}; - -// 게시글 존재 여부 확인 -const checkArticleExist = async (req, res, next) => { - const { id } = req.params; - - try { - const article = await articleRepository.getPost(id); - if (!article) { - const err = new Error(`Article ${id} not found`); - err.statusCode = 404; - next(err); - } else next(); - } catch (err) { - next(err); - } -}; - -// 상품 존재 여부 확인 -const checkProductExist = async (req, res, next) => { - const { id } = req.params; - - try { - const product = await productRepository.getProduct(id); - if (!product) { - const err = new Error(`Product ${id} not found`); - err.statusCode = 404; - next(err); - } else next(); - } catch (err) { - next(err); - } -}; - -// 게시글 댓글 유저 검증 -const verifyArticleCommentAuth = async (req, res, next) => { - const { cid } = req.params; - - try { - const comment = await articleRepository.getComment(parseInt(cid)); - - if (!comment) { - const err = new Error(`Comment ${cid} not found`); - err.statusCode = 404; - next(err); - } - - if (req.user.userId === comment.userId) next(); - else { - const err = new Error("Unauthorized"); - err.statusCode = 403; - next(err); - } - } catch (err) { - next(err); - } -}; - -// 상품 댓글 유저 검증 -const verifyProductCommentAuth = async (req, res, next) => { - const { cid } = req.params; - - try { - const comment = await productRepository.getComment(parseInt(cid)); - - if (!comment) { - const err = new Error(`Comment ${cid} not found`); - err.statusCode = 404; - next(err); - } - - if (req.user.userId === comment.userId) next(); - else { - const err = new Error("Unauthorized"); - err.statusCode = 403; - next(err); - } - } catch (err) { - next(err); - } -}; - -export default { - verifyAccessToken, - verifyRefreshToken, - verifyArticleAuth, - verifyProductAuth, - checkArticleExist, - checkProductExist, - verifyArticleCommentAuth, - verifyProductCommentAuth, -}; diff --git a/mission_5/src/middleware/index.js b/mission_5/src/middleware/index.js deleted file mode 100644 index 02584180c..000000000 --- a/mission_5/src/middleware/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './validator.js'; \ No newline at end of file diff --git a/mission_5/src/middleware/validator.js b/mission_5/src/middleware/validator.js deleted file mode 100644 index 1b58eb14a..000000000 --- a/mission_5/src/middleware/validator.js +++ /dev/null @@ -1,35 +0,0 @@ -// Verify required parameters are okay -export async function validateProduct (req, res, next) { - const { - name, - description, - price, - tags - } = req.body; - - // validation logic (possible improvements with Zod library in the future) - if ( !name || !description || !price || !tags ) - return res.status(400).json({ message: "Missing required fields" }); - - if (isNaN(price)) - return res.status(400).json({ message: "Price must be a number" }); - - if (!Array.isArray(tags) || !tags.every(tag => typeof tag === 'string')) - return res.status(400).json({ message: "Tags must be an array of string" }); - - next(); -}; - -// Verify required parameters are okay -export async function validateArticle (req, res, next) { - const { - title, - content - } = req.body; - - // validation - if ( !title || !content ) - return res.status(400).json({ message: "Invalid SQL Parameters" }); - - next(); -}; \ No newline at end of file diff --git a/mission_5/src/repository/articleRepository.js b/mission_5/src/repository/articleRepository.js deleted file mode 100644 index 15c41f0fe..000000000 --- a/mission_5/src/repository/articleRepository.js +++ /dev/null @@ -1,155 +0,0 @@ -import prisma from "../../lib/prisma.js"; - -export async function createPost({ userId, title, content }) { - return await prisma.article.create({ - data: { - title, - content, - userId, - }, - }); -} - -export async function getPosts({ offset, limit, sort, search }) { - // search에 값이 있을 때만 where로 문자열 검색 - const where = search - ? { - OR: [ - { - title: { - contains: search, - mode: "insensitive", - }, - }, - { - content: { - contains: search, - mode: "insensitive", - }, - }, - ], - } - : {}; - - const result = await prisma.article.findMany({ - select: { - id: true, - title: true, - content: true, - createdAt: true, - }, - orderBy: { - createdAt: sort, - }, - where, - skip: offset * limit, - take: limit, - }); - - return result; -} - -export async function getPost(id) { - const result = await prisma.article.findUnique({ - where: { - id: parseInt(id), - }, - }); - - return result; -} - -export async function patchPost({ id, ...filteredBody }) { - const result = await prisma.article.update({ - where: { - id: Number(id), - }, - data: { - ...filteredBody, - }, - }); - - return result; -} - -export async function deletePost(id) { - const result = await prisma.article.delete({ - where: { - id: Number(id), - }, - }); - - return result; -} - -export async function postComment({ userId, pid, name, content }) { - const result = await prisma.comment.create({ - data: { - name, - content, - articleId: pid, - userId, - }, - }); - - return result; -} - -export async function getComments({ pid, cursor, limit }) { - const result = await prisma.comment.findMany({ - select: { - id: true, - content: true, - createdAt: true, - }, - where: { - articleId: Number(pid), - }, - orderBy: { - id: "asc", - }, - take: Number(limit), - ...(cursor - ? { - skip: 1, - cursor: { id: Number(cursor) }, - } - : {}), - }); - - return result; -} - -export async function getComment(cid) { - const result = await prisma.comment.findUnique({ - where: { - id: cid, - }, - }); - - return result; -} - -export async function patchComment({ cid, name, content }) { - const result = await prisma.comment.update({ - where: { - id: Number(cid), - }, - data: { - name, - content, - }, - }); - - return result; -} - -export async function deleteComment(cid) { - const result = prisma.comment.delete({ - where: { - id: Number(cid), - }, - }); - - return result; -} diff --git a/mission_5/src/repository/index.js b/mission_5/src/repository/index.js deleted file mode 100644 index a9bc4c15b..000000000 --- a/mission_5/src/repository/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './articleRepository.js'; \ No newline at end of file diff --git a/mission_5/src/repository/productRepository.js b/mission_5/src/repository/productRepository.js deleted file mode 100644 index 7c009cf64..000000000 --- a/mission_5/src/repository/productRepository.js +++ /dev/null @@ -1,169 +0,0 @@ -import prisma from "../../lib/prisma.js"; - -export async function createProduct({ - userId, - name, - description, - price, - tags, -}) { - return await prisma.product.create({ - data: { - name, - description, - price, - tags, - userId, - }, - }); -} - -export async function getProducts({ offset, limit, sort, search }) { - const result = await prisma.product.findMany({ - select: { - id: true, - name: true, - price: true, - createdAt: true, - }, - orderBy: { - createdAt: sort, - }, - where: { - OR: [ - { - name: { - contains: search, - mode: "insensitive", - }, - }, - { - description: { - contains: search, - mode: "insensitive", - }, - }, - ], - }, - skip: offset * limit, - take: limit, - }); - - return result; -} - -export async function getProduct(id) { - const result = await prisma.product.findUnique({ - where: { - id: parseInt(id), - }, - }); - - return result; -} - -export async function patchProduct({ id, ...filteredBody }) { - const result = await prisma.product.update({ - where: { - id: Number(id), - }, - data: { - ...filteredBody, - }, - }); - - return result; -} - -export async function deleteProduct(id) { - const result = await prisma.product.delete({ - where: { - id: Number(id), - }, - }); - - return result; -} - -export async function postComment({ userId, pid, name, content }) { - const result = await prisma.comment.create({ - data: { - userId, - name, - content, - productId: pid, - }, - }); - - return result; -} - -export async function getComments({ pid, cursor, limit }) { - const result = await prisma.comment.findMany({ - select: { - id: true, - content: true, - createdAt: true, - }, - where: { - productId: Number(pid), - }, - orderBy: { - id: "asc", - }, - take: Number(limit), - ...(cursor - ? { - skip: 1, - cursor: { id: Number(cursor) }, - } - : {}), - }); - - return result; -} - -export async function getComment(cid) { - const result = await prisma.comment.findUnique({ - where: { - id: cid, - }, - }); - - return result; -} - -export async function patchComment({ cid, name, content }) { - const result = await prisma.comment.update({ - where: { - id: Number(cid), - }, - data: { - name, - content, - }, - }); - - return result; -} - -export async function deleteComment(cid) { - const result = await prisma.comment.delete({ - where: { - id: Number(cid), - }, - }); - - return result; -} - -export async function getProductsByUser(userId) { - const products = await prisma.user.findUnique({ - where: { id: userId }, - select: { - Product: true, - }, - }); - - return products; -} \ No newline at end of file diff --git a/mission_5/src/repository/userRepository.js b/mission_5/src/repository/userRepository.js deleted file mode 100644 index 24e0aec5e..000000000 --- a/mission_5/src/repository/userRepository.js +++ /dev/null @@ -1,61 +0,0 @@ -import e from "express"; -import prisma from "../../lib/prisma.js"; -import bcrypt from "bcrypt"; - -export async function createUser(user) { - const hashedPassword = await hashPassword(user.password); - - const createdUser = await prisma.user.create({ - data: { - ...user, - password: hashedPassword, // This line overwrites user.password - }, - }); - - return createdUser; -} - -export async function findByEmail(email) { - const result = await prisma.user.findFirst({ - where: { - email, - }, - }); - - return result; -} - -export async function findById(id) { - const result = await prisma.user.findUnique({ - where: { - id, - }, - }); - - return result; -} - -export async function hashPassword(password) { - const salt = await bcrypt.genSalt(10); - const hash = await bcrypt.hash(password, salt); - - return hash; -} - -export function filterSensitiveUserData(user) { - const { password, refreshToken, ...rest } = user; - return rest; -} - -export async function updateUser(id, toUpdate) { - if (toUpdate.password) { - toUpdate.password = await hashPassword(toUpdate.password); - } - - const updatedUser = await prisma.user.update({ - where: { id }, - data: toUpdate, - }); - - return updatedUser; -} diff --git a/mission_5/src/router/articleRouter.js b/mission_5/src/router/articleRouter.js deleted file mode 100644 index 6599813b0..000000000 --- a/mission_5/src/router/articleRouter.js +++ /dev/null @@ -1,73 +0,0 @@ -import express from "express"; -import { validateArticle } from "../middleware/index.js"; -import auth from "../middleware/auth.js"; -import * as articleController from "../controller/articleController.js"; - -const router = express.Router(); - -router - .route("/") - - // Create a post - .post( - auth.verifyAccessToken, - validateArticle, - articleController.createPost - ) - - // Inquiry all articles - .get(articleController.getPosts); - -router - .route("/:id") - - // Get informations of a certain article - .get(articleController.getPost) - - // Modify a article property - .patch( - auth.verifyAccessToken, - auth.verifyArticleAuth, - articleController.patchPost - ) - - // Delete a particular article - .delete( - auth.verifyAccessToken, - auth.verifyArticleAuth, - articleController.deletePost - ); - -router - .route("/:id/comments") - - // Add a comment - .post( - auth.verifyAccessToken, - auth.checkArticleExist, - articleController.postComment - ) - - // Inquery all comments - .get(auth.checkArticleExist, articleController.getComments); - -router - .route("/:id/comments/:cid") - - // Modify comment - .patch( - auth.verifyAccessToken, - auth.checkArticleExist, - auth.verifyArticleCommentAuth, - articleController.patchComment - ) - - // Delete comment - .delete( - auth.verifyAccessToken, - auth.checkArticleExist, - auth.verifyArticleCommentAuth, - articleController.deleteComment - ); - -export default router; diff --git a/mission_5/src/router/imageRouter.js b/mission_5/src/router/imageRouter.js deleted file mode 100644 index 467943419..000000000 --- a/mission_5/src/router/imageRouter.js +++ /dev/null @@ -1,15 +0,0 @@ -import express from 'express'; -import multer from "multer"; - -const router = express.Router(); - -const upload = multer({ dest: 'uploads/' }); - -// 이미지 리사이징 기능 구현 예정 -router.post('/', upload.single('image'), async (req, res) => { - // console.log(req.file); - res.status(201).json({ message: 'Upload OK', filePath: req.file.path }); -}); - - -export default router; \ No newline at end of file diff --git a/mission_5/src/router/index.js b/mission_5/src/router/index.js deleted file mode 100644 index 921cc19ab..000000000 --- a/mission_5/src/router/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './articleRouter.js'; -export * from './productRouter.js'; -export * from './imageRouter.js'; \ No newline at end of file diff --git a/mission_5/src/router/productRouter.js b/mission_5/src/router/productRouter.js deleted file mode 100644 index ebecb4166..000000000 --- a/mission_5/src/router/productRouter.js +++ /dev/null @@ -1,71 +0,0 @@ -import express from "express"; -import { validateProduct } from "../middleware/validator.js"; -import auth from "../middleware/auth.js"; -import * as productController from "../controller/productController.js"; - -const router = express.Router(); - -router - .route("/") - - // Upload a new product - .post( - auth.verifyAccessToken, - validateProduct, - productController.createProduct - ) - - // Inquiry all products - .get(productController.getProducts); - -router - .route("/:id") - - // Get informations of a certain product - .get(productController.getProduct) - - // Modify a product property - .patch( - auth.verifyAccessToken, - auth.verifyProductAuth, - productController.patchProduct - ) - - // Delete a particular product - .delete( - auth.verifyAccessToken, - auth.verifyProductAuth, - productController.deleteProduct - ); - -router - .route("/:id/comments") - - // Add a comment - .post( - auth.verifyAccessToken, - auth.checkProductExist, - productController.postComment - ) - - // Inquery all comments - .get(auth.checkProductExist, productController.getComments); - -router - .route("/:id/comments/:cid") - - .patch( - auth.verifyAccessToken, - auth.checkProductExist, - auth.verifyProductCommentAuth, - productController.patchComment - ) - - .delete( - auth.verifyAccessToken, - auth.checkProductExist, - auth.verifyProductCommentAuth, - productController.deleteComment - ); - -export default router; diff --git a/mission_5/src/router/userRouter.js b/mission_5/src/router/userRouter.js deleted file mode 100644 index 9ab871231..000000000 --- a/mission_5/src/router/userRouter.js +++ /dev/null @@ -1,44 +0,0 @@ -import express from "express"; -import * as userController from "../controller/userController.js"; -import auth from "../middleware/auth.js"; - -const userRouter = express.Router(); - -userRouter - .route("/users") - - // Create user - .post(userController.createUser) - - // Get my(user) info - .get(auth.verifyAccessToken, userController.getMyInfo); - -// Update user info (nickname, email) -userRouter.patch( - "/users/info", - auth.verifyAccessToken, - userController.updateMyInfo -); - -// Update user password -userRouter.patch( - "/users/password", - auth.verifyAccessToken, - userController.updateMyPassword -); - -// Get product lists uploaded by user -userRouter.get( - "/users/products", - auth.verifyAccessToken, - userController.getMyProducts -); - -userRouter.post("/login", userController.getAccessToken); -userRouter.post( - "/login/refresh", - auth.verifyRefreshToken, - userController.getRefreshToken -); - -export default userRouter; diff --git a/mission_5/src/services/articleService.js b/mission_5/src/services/articleService.js deleted file mode 100644 index c390e9ee5..000000000 --- a/mission_5/src/services/articleService.js +++ /dev/null @@ -1,57 +0,0 @@ -import * as articleRepository from "../repository/articleRepository.js"; - -export async function createPost(data) { - const result = await articleRepository.createPost(data); - - return result; -} - -export async function getPosts(data) { - // 기본 desc - data.sort = data.sort === "old" ? "asc" : "desc"; - - const result = await articleRepository.getPosts(data); - - return result; -} - -export async function getPost(id) { - const result = await articleRepository.getPost(id); - - return result; -} - -export async function patchPost(data) { - const result = await articleRepository.patchPost(data); - - return result; -} - -export async function deletePost(id) { - const result = await articleRepository.deletePost(id); - - return result; -} - -export async function postComment(data) { - const result = await articleRepository.postComment(data); - - return result; -} - -export async function getComments(data) { - const result = await articleRepository.getComments(data); - - return result; -} - -export async function patchComment(data) { - const result = await articleRepository.patchComment(data); - - return result; -} -export async function deleteComment(data) { - const result = await articleRepository.deleteComment(data); - - return result; -} diff --git a/mission_5/src/services/index.js b/mission_5/src/services/index.js deleted file mode 100644 index ce045fa9e..000000000 --- a/mission_5/src/services/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './articleService.js'; \ No newline at end of file diff --git a/mission_5/src/services/productService.js b/mission_5/src/services/productService.js deleted file mode 100644 index 74fa32db4..000000000 --- a/mission_5/src/services/productService.js +++ /dev/null @@ -1,55 +0,0 @@ -import * as productRepository from "../repository/productRepository.js"; - -export async function createProduct(data) { - const result = await productRepository.createProduct(data); - - return result; -} - -export async function getProducts(data) { - const result = await productRepository.getProducts(data); - - return result; -} - -export async function getProduct(data) { - const result = await productRepository.getProduct(data); - - return result; -} - -export async function patchProduct(data) { - const result = await productRepository.patchProduct(data); - - return result; -} - -export async function deleteProduct(data) { - const result = await productRepository.deleteProduct(data); - - return result; -} - -export async function postComment(data) { - const result = await productRepository.postComment(data); - - return result; -} - -export async function getComments(data) { - const result = await productRepository.getComments(data); - - return result; -} - -export async function patchComment(data) { - const result = await productRepository.patchComment(data); - - return result; -} - -export async function deleteComment(data) { - const result = await productRepository.deleteComment(data); - - return result; -} diff --git a/mission_5/src/services/userService.js b/mission_5/src/services/userService.js deleted file mode 100644 index db7b24c5c..000000000 --- a/mission_5/src/services/userService.js +++ /dev/null @@ -1,110 +0,0 @@ -import * as userRepository from "../repository/userRepository.js"; -import * as productRepository from "../repository/productRepository.js"; -import bcrypt from "bcrypt"; -import jwt from "jsonwebtoken"; - -export async function createUser(user) { - // 이미 가입된 이메일인지 검증 - const existedUser = await userRepository.findByEmail(user.email); - - if (existedUser) { - const err = new Error("User already exists"); - err.statusCode = 422; - err.data = { email: user.email }; - throw err; - } - - const createdUser = await userRepository.createUser(user); - const createdUserId = await userRepository.filterSensitiveUserData( - createdUser - ).id; - - return createdUserId; -} - -export async function getUser({ email, password }) { - const user = await userRepository.findByEmail(email); - - // If user is invalid - if (!user) { - const err = new Error("Unauthorized"); - err.statusCode = 401; - throw err; - } - - // Verifying password - await verifyPassword(password, user.password); - - // Return without password - return userRepository.filterSensitiveUserData(user); -} - -export async function getUserById(userId) { - const user = await userRepository.findById(userId); - - if (!user) { - const err = new Error("User not found"); - err.statusCode = 404; - throw err; - } - - return userRepository.filterSensitiveUserData(user); -} - -async function verifyPassword(inputPassword, password) { - const isVerified = await bcrypt.compare(inputPassword, password); - - if (!isVerified) { - const err = new Error("Password is wrong"); - err.statusCode = 401; - throw err; - } -} - -export function createToken(user, token) { - const payload = { userId: user.id }; - const options = { expiresIn: token === "refresh" ? "2w" : "1h" }; - - return jwt.sign(payload, process.env.JWT_SECRET, options); -} - -export async function refreshToken(userId, refreshToken) { - const user = await userRepository.findById(userId); - - if (!user || user.refreshToken !== refreshToken) { - const err = new Error("Unauthorized"); - err.statusCode = 404; - throw err; - } - - const accessToken = createToken(user); - return accessToken; -} - -export async function updateUserInfo(userId, toUpdate) { - // 수정할 내용이 없다면 에러 처리 - if (Object.keys(toUpdate).length === 0) { - const err = new Error("No data to update"); - err.statusCode = 400; - throw err; - } - - const updatedUser = await userRepository.updateUser(userId, toUpdate); - - return userRepository.filterSensitiveUserData(updatedUser); -} - -export async function updateUserPassword(userId, newPassword) { - const hashedPassword = await userRepository.hashPassword(newPassword); - const user = await userRepository.updateUser(userId, { - password: hashedPassword, - }); - - return userRepository.filterSensitiveUserData(user); -} - -export async function getMyProducts(userId) { - const products = await productRepository.getProductsByUser(userId); - - return products.Product; -} From 26ce198d2181ffaed99a062a81ecd347f23e97d8 Mon Sep 17 00:00:00 2001 From: intwocave Date: Wed, 17 Sep 2025 18:42:02 +0900 Subject: [PATCH 064/130] feat: update .gitignore to exclude dist --- mission_5/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mission_5/.gitignore b/mission_5/.gitignore index d42e3ca1d..d58e9d958 100644 --- a/mission_5/.gitignore +++ b/mission_5/.gitignore @@ -1,4 +1,6 @@ node_modules +/dist + # Keep environment variables out of version control .env From e438e9e59a206a14c89435d5dbde90e24848c49c Mon Sep 17 00:00:00 2001 From: intwocave Date: Wed, 17 Sep 2025 18:42:34 +0900 Subject: [PATCH 065/130] feat: update packages and npm scripts --- mission_5/package-lock.json | 706 +++++++++++++++++++++++++++++++++++- mission_5/package.json | 17 +- 2 files changed, 720 insertions(+), 3 deletions(-) diff --git a/mission_5/package-lock.json b/mission_5/package-lock.json index 8ef2beae4..0c9c8f9af 100644 --- a/mission_5/package-lock.json +++ b/mission_5/package-lock.json @@ -21,7 +21,17 @@ "passport-jwt": "^4.0.1" }, "devDependencies": { - "prisma": "^6.13.0" + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.9", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.3", + "@types/express-jwt": "^6.0.4", + "@types/multer": "^2.0.0", + "@types/node": "^24.3.1", + "nodemon": "^3.1.10", + "prisma": "^6.13.0", + "ts-node": "^10.9.2", + "typescript": "^5.9.2" } }, "node_modules/@babel/code-frame": { @@ -49,6 +59,47 @@ "node": ">=6.9.0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@prisma/client": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.13.0.tgz", @@ -141,6 +192,138 @@ "devOptional": true, "license": "MIT" }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie-parser": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.9.tgz", + "integrity": "sha512-tGZiZ2Gtc4m3wIdLkZ8mkj1T6CEHb35+VApbL2T14Dew8HA7c+04dmKqsKRNC+8RJPm16JEK0tFSwdZqubfc4g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", + "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-jwt": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-6.0.4.tgz", + "integrity": "sha512-I53KRQ9D0eTA6hVCN9S73iOeprKS3JNWK+Cp2mDPB6uOIkTVpkgSkX394kHQzb5cd0U02I0adRmsMxHk+zX8tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/express-unless": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz", + "integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express-unless": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.3.tgz", + "integrity": "sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/jsonwebtoken": { "version": "9.0.10", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", @@ -151,12 +334,29 @@ "@types/node": "*" } }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, + "node_modules/@types/multer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", + "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/node": { "version": "24.3.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", @@ -173,6 +373,43 @@ "devOptional": true, "license": "MIT" }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -186,12 +423,66 @@ "node": ">= 0.6" } }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", "license": "MIT" }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/bcrypt": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", @@ -206,6 +497,19 @@ "node": ">= 18" } }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/body-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", @@ -226,6 +530,30 @@ "node": ">=18" } }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -342,6 +670,13 @@ "consola": "^3.2.3" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, "node_modules/concat-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", @@ -445,6 +780,13 @@ "node": ">= 0.10" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", @@ -495,6 +837,16 @@ "devOptional": true, "license": "MIT" }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dotenv": { "version": "16.6.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", @@ -694,6 +1046,19 @@ "node": ">=8.0.0" } }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/finalhandler": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", @@ -742,6 +1107,21 @@ "node": ">= 0.8" } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -806,6 +1186,19 @@ "giget": "dist/cli.mjs" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -818,6 +1211,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -892,6 +1295,13 @@ "node": ">=0.10.0" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, "node_modules/index-to-position": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", @@ -920,6 +1330,52 @@ "node": ">= 0.10" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -1035,6 +1491,13 @@ "devOptional": true, "license": "ISC" }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1086,6 +1549,19 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -1210,6 +1686,73 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/nodemon": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "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/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/normalize-package-data": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", @@ -1225,6 +1768,16 @@ "node": "^16.14.0 || >=18.0.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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/nypm": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", @@ -1392,6 +1945,19 @@ "devOptional": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pkg-types": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz", @@ -1443,6 +2009,13 @@ "node": ">= 0.10" } }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", @@ -1745,6 +2318,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -1807,6 +2393,19 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/tinyexec": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", @@ -1814,6 +2413,19 @@ "devOptional": true, "license": "MIT" }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -1823,6 +2435,60 @@ "node": ">=0.6" } }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/type-fest": { "version": "4.41.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", @@ -1856,6 +2522,27 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "license": "MIT" }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, "node_modules/undici-types": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", @@ -1899,6 +2586,13 @@ "node": ">= 0.4.0" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -1933,6 +2627,16 @@ "engines": { "node": ">=0.4" } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } } } } diff --git a/mission_5/package.json b/mission_5/package.json index 6fd1088aa..a9c01c4d5 100644 --- a/mission_5/package.json +++ b/mission_5/package.json @@ -3,7 +3,10 @@ "version": "1.0.0", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc", + "start": "NODE_ENV=production node dist/main.js", + "dev": "nodemon" }, "keywords": [], "author": "", @@ -22,7 +25,17 @@ "passport-jwt": "^4.0.1" }, "devDependencies": { - "prisma": "^6.13.0" + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.9", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.3", + "@types/express-jwt": "^6.0.4", + "@types/multer": "^2.0.0", + "@types/node": "^24.3.1", + "nodemon": "^3.1.10", + "prisma": "^6.13.0", + "ts-node": "^10.9.2", + "typescript": "^5.9.2" }, "prisma": { "seed": "node prisma/seed.js" From e4764f6febf3d834e51148214cab38e4f0942036 Mon Sep 17 00:00:00 2001 From: intwocave Date: Wed, 17 Sep 2025 18:42:52 +0900 Subject: [PATCH 066/130] refactor: migrate from js to ts --- mission_5/env.d.ts | 13 + mission_5/nodemon.json | 5 + mission_5/prisma/seed.ts | 94 ++++++ mission_5/src/container.ts | 1 + mission_5/src/controller/articleController.ts | 253 +++++++++++++++++ mission_5/src/controller/index.ts | 1 + mission_5/src/controller/productController.ts | 267 ++++++++++++++++++ mission_5/src/controller/userController.ts | 156 ++++++++++ mission_5/src/handler/errorHandler.ts | 12 + mission_5/src/lib/prisma.ts | 5 + mission_5/src/main.ts | 41 +++ mission_5/src/middleware/auth.ts | 173 ++++++++++++ mission_5/src/middleware/index.ts | 1 + mission_5/src/middleware/validator.ts | 31 ++ mission_5/src/repository/articleRepository.ts | 177 ++++++++++++ mission_5/src/repository/index.ts | 1 + mission_5/src/repository/productRepository.ts | 197 +++++++++++++ mission_5/src/repository/userRepository.ts | 61 ++++ mission_5/src/router/articleRouter.ts | 73 +++++ mission_5/src/router/imageRouter.ts | 19 ++ mission_5/src/router/index.ts | 3 + mission_5/src/router/productRouter.ts | 72 +++++ mission_5/src/router/userRouter.ts | 44 +++ mission_5/src/services/articleService.ts | 65 +++++ mission_5/src/services/index.ts | 1 + mission_5/src/services/productService.ts | 66 +++++ mission_5/src/services/userService.ts | 121 ++++++++ mission_5/src/types/article.ts | 54 ++++ mission_5/src/types/auth.d.ts | 5 + mission_5/src/types/express/index.d.ts | 10 + mission_5/src/types/global.ts | 5 + mission_5/src/types/product.ts | 63 +++++ mission_5/src/types/user.ts | 21 ++ mission_5/tsconfig.json | 48 ++++ 34 files changed, 2159 insertions(+) create mode 100644 mission_5/env.d.ts create mode 100644 mission_5/nodemon.json create mode 100644 mission_5/prisma/seed.ts create mode 100644 mission_5/src/container.ts create mode 100644 mission_5/src/controller/articleController.ts create mode 100644 mission_5/src/controller/index.ts create mode 100644 mission_5/src/controller/productController.ts create mode 100644 mission_5/src/controller/userController.ts create mode 100644 mission_5/src/handler/errorHandler.ts create mode 100644 mission_5/src/lib/prisma.ts create mode 100644 mission_5/src/main.ts create mode 100644 mission_5/src/middleware/auth.ts create mode 100644 mission_5/src/middleware/index.ts create mode 100644 mission_5/src/middleware/validator.ts create mode 100644 mission_5/src/repository/articleRepository.ts create mode 100644 mission_5/src/repository/index.ts create mode 100644 mission_5/src/repository/productRepository.ts create mode 100644 mission_5/src/repository/userRepository.ts create mode 100644 mission_5/src/router/articleRouter.ts create mode 100644 mission_5/src/router/imageRouter.ts create mode 100644 mission_5/src/router/index.ts create mode 100644 mission_5/src/router/productRouter.ts create mode 100644 mission_5/src/router/userRouter.ts create mode 100644 mission_5/src/services/articleService.ts create mode 100644 mission_5/src/services/index.ts create mode 100644 mission_5/src/services/productService.ts create mode 100644 mission_5/src/services/userService.ts create mode 100644 mission_5/src/types/article.ts create mode 100644 mission_5/src/types/auth.d.ts create mode 100644 mission_5/src/types/express/index.d.ts create mode 100644 mission_5/src/types/global.ts create mode 100644 mission_5/src/types/product.ts create mode 100644 mission_5/src/types/user.ts create mode 100644 mission_5/tsconfig.json diff --git a/mission_5/env.d.ts b/mission_5/env.d.ts new file mode 100644 index 000000000..f4b3b91de --- /dev/null +++ b/mission_5/env.d.ts @@ -0,0 +1,13 @@ +declare namespace NodeJS { + interface ProcessEnv { + NODE_ENV: "development" | "production"; + PORT?: string; + DATABASE_URL?: string; + /* DB_HOST: string; + DB_PORT: string; + DB_USERNAME: string; + DB_PASSWORD: string; + DB_NAME: string; */ + JWT_SECRET: string; + } +} diff --git a/mission_5/nodemon.json b/mission_5/nodemon.json new file mode 100644 index 000000000..647b3dd15 --- /dev/null +++ b/mission_5/nodemon.json @@ -0,0 +1,5 @@ +{ + "watch": ["src"], + "ext": "ts", + "exec": "ts-node ./src/main.ts" +} \ No newline at end of file diff --git a/mission_5/prisma/seed.ts b/mission_5/prisma/seed.ts new file mode 100644 index 000000000..0d39f9c2f --- /dev/null +++ b/mission_5/prisma/seed.ts @@ -0,0 +1,94 @@ +import { PrismaClient } from "@prisma/client"; +const prisma = new PrismaClient(); + +async function main() { + // ------------------------------ + // Product 더미 데이터 생성 + // ------------------------------ + const product1 = await prisma.product.create({ + data: { + name: "게이밍 노트북", + description: "고성능 게이밍 및 작업용 노트북", + price: 1800000, + tags: ["노트북", "게이밍", "고성능",], + comments: { + create: [ + { name: "홍길동", content: "배틀그라운드도 잘 돌아가네요!" }, + { name: "김철수", content: "팬 소음이 조금 있지만 성능은 최고입니다." } + ] + } + } + }); + + const product2 = await prisma.product.create({ + data: { + name: "기계식 키보드", + description: "청축 기계식 키보드, 타건감이 뛰어남", + price: 120000, + tags: ["키보드","기계식","청축",], + comments: { + create: [ + { name: "이영희", content: "타이핑할 맛이 납니다." } + ] + } + } + }); + + // ------------------------------ + // Article 더미 데이터 생성 + // ------------------------------ + const article1 = await prisma.article.create({ + data: { + title: "게이밍 PC 조립 가이드", + content: "부품 선택부터 조립까지 단계별 설명...", + comments: { + create: [ + { name: "박영수", content: "이 글 덕분에 처음으로 PC를 조립했습니다." }, + { name: "최민지", content: "부품 추천이 매우 유용했습니다." } + ] + } + } + }); + + const article2 = await prisma.article.create({ + data: { + title: "2025년 인기 프로그래밍 언어 TOP 10", + content: "올해 주목받는 프로그래밍 언어와 트렌드를 분석...", + comments: { + create: [ + { name: "장우진", content: "Rust가 상위권이라니 반갑네요!" } + ] + } + } + }); + + // ------------------------------ + // Comment 모델 개별 생성 (Product/Article와 직접 연결) + // ------------------------------ + await prisma.comment.create({ + data: { + name: "손흥민", + content: "이 제품은 가격 대비 성능이 좋습니다.", + productId: product1.id + } + }); + + await prisma.comment.create({ + data: { + name: "유재석", + content: "기사 내용이 깔끔하게 잘 정리되어 있네요.", + articleId: article2.id + } + }); + + console.log("시딩이 완료되었습니다."); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/mission_5/src/container.ts b/mission_5/src/container.ts new file mode 100644 index 000000000..ba0183f59 --- /dev/null +++ b/mission_5/src/container.ts @@ -0,0 +1 @@ +import prisma from './lib/prisma.js'; \ No newline at end of file diff --git a/mission_5/src/controller/articleController.ts b/mission_5/src/controller/articleController.ts new file mode 100644 index 000000000..2f603387d --- /dev/null +++ b/mission_5/src/controller/articleController.ts @@ -0,0 +1,253 @@ +import * as articleService from "../services/articleService.js"; +import type { RequestHandler } from "express"; + +const createPost: RequestHandler = async function (req, res, next) { + const { title, content } = req.body; + + const userId = req.user ? req.user.userId : null; + if (userId === null) { + const err = new Error("Access token is missing or invalid"); + err.statusCode = 401; + return next(err); + } + + if (!title || !content) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + const article = await articleService.createPost({ userId, title, content }); + res.status(201).json(article); + } catch (err) { + next(err); + } +}; + +const getPosts: RequestHandler = async function (req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search } = req.query; + + try { + const articles = await articleService.getPosts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search: String(search), + }); + + if (articles) res.status(200).json(articles); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with given parameters`; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const getPost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const article = await articleService.getPost({ id: Number(id) }); + + if (article) res.status(200).json(article); + else { + const err = new Error(`Cannot find article with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchPost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + // Columns in model Article + const articleCols = ["title", "content"]; + + // ? + const filteredBody = Object.entries(req.body) + .filter(([key]) => articleCols.includes(key)) + .reduce>((obj, [key, value]) => { + obj[key] = value; + return obj; + }, {}); + + try { + const article = await articleService.patchPost({ + id: Number(id), + ...filteredBody, + }); + + if (article) res.status(200).json(article); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const deletePost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const deleted = await articleService.deletePost({ id: Number(id) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const postComment: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Access token is missing or invalid"); + err.statusCode = 401; + return next(err); + } + + if (!name || !content || !pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + return next(err); + } + + try { + const comment = await articleService.postComment({ + userId, + name, + content, + pid: Number(pid), + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +}; + +const getComments: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + const comments = await articleService.getComments({ + pid: Number(pid), + cursor: Number(cursor), + limit: Number(limit), + }); + + if (comments) + res.status(200).json({ + comments, + nextCursor: + comments.length === Number(limit) ? comments.at(-1)?.id : null, // llm + }); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comments with id ${pid}`; + return next(err); + } +}; + +const patchComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id' and 'cid'"; + return next(err); + } + + const { name, content } = req.body; + if (!name || !content) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid SQL Parameters"; + return next(err); + } + + const comment = await articleService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comment with ID ${pid}`; + return next(err); + } +}; + +const deleteComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await articleService.deleteComment({ cid: Number(cid) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find any comment with ID ${cid}`); + err.statusCode = 404; + return next(err); + } +}; + +export { + createPost, + getPosts, + getPost, + patchPost, + deletePost, + postComment, + getComments, + patchComment, + deleteComment, +}; diff --git a/mission_5/src/controller/index.ts b/mission_5/src/controller/index.ts new file mode 100644 index 000000000..1d9c8cc37 --- /dev/null +++ b/mission_5/src/controller/index.ts @@ -0,0 +1 @@ +export * from './articleController.js'; \ No newline at end of file diff --git a/mission_5/src/controller/productController.ts b/mission_5/src/controller/productController.ts new file mode 100644 index 000000000..6466d2548 --- /dev/null +++ b/mission_5/src/controller/productController.ts @@ -0,0 +1,267 @@ +import * as productService from "../services/productService.js"; +import type { RequestHandler } from "express"; + +const createProduct: RequestHandler = async function createProduct( + req, + res, + next +) { + // destructuring field data from request body + const { name, description, price, tags } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!name || !description || !price || !tags) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Product table + const product = await productService.createProduct({ + userId, + name, + description, + price, + tags, + }); + + res.status(201).json(product); + } catch (err) { + next(err); + } +}; + +const getProducts: RequestHandler = async function (req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search = "" } = req.query; + + try { + const products = await productService.getProducts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search: String(search), + }); + + if (products) res.status(200).json(products); + else { + const err = new Error("Cannot find products"); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const getProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const product = await productService.getProduct({ id }); + + if (product) res.status(200).json(product); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + // Attributes in model Product + const productCols = ["name", "description", "price", "tags"]; + + // Possible improvement? + const filteredBody = Object.entries(req.body) + .filter(([key]) => productCols.includes(key)) + .reduce>((obj, [key, value]) => { + obj[key] = value; + return obj; + }, {}); + + try { + const product = await productService.patchProduct({ id, ...filteredBody }); + + if (product) res.status(200).json(product); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find product with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const deleteProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const deleted = await productService.deleteProduct({ id }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const postComment: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + // validation + if (!name || !content || !pid) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Comment table + const comment = await productService.postComment({ + userId, + pid: Number(pid), + name, + content, + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +}; + +const getComments: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + try { + const comments = await productService.getComments({ + pid: Number(pid), + cursor: cursor ? Number(cursor) : null, + limit: Number(limit), + }); + + // Cursor pagination + const nextCursor = + comments.length > 0 ? comments[comments.length - 1] : null; + + if (comments) + res.status(200).json({ + comments, + nextCursor, + }); + else { + const err = new Error(`Cannot find any comments`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + const { name, content } = req.body; + + if (!pid || !cid || !name || !content) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(`Cannot find any comment with ID ${cid}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const deleteComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await productService.deleteComment({ cid: Number(cid) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${pid}`); + err.statusCode = 404; + return next(err); + } +}; + +export { + createProduct, + getProducts, + getProduct, + patchProduct, + deleteProduct, + postComment, + getComments, + patchComment, + deleteComment, +}; diff --git a/mission_5/src/controller/userController.ts b/mission_5/src/controller/userController.ts new file mode 100644 index 000000000..397fed1ad --- /dev/null +++ b/mission_5/src/controller/userController.ts @@ -0,0 +1,156 @@ +import * as userService from "../services/userService.js"; +import type { RequestHandler } from "express"; + +// for Creating user +const createUser: RequestHandler = async function (req, res, next) { + const { email, nickname, password } = req.body; + + if (!email || !nickname || !password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const userId = await userService.createUser({ email, nickname, password }); + + return res.status(200).json(userId); + } catch (err) { + next(err); + } +}; + +// for Login +const getAccessToken: RequestHandler = async function (req, res, next) { + const { email, password } = req.body; + + if (!email || !password) { + const err = new Error("Email or password is wrong"); + err.statusCode = 404; + return next(err); + } + + try { + const user = await userService.getUser(req.body); + const accessToken = userService.createToken(user); + const refreshToken = userService.createToken(user, "refresh"); + await userService.updateUserInfo(user.id, { refreshToken }); + res.cookie("refreshToken", refreshToken, { + httpOnly: true, + sameSite: "none", + secure: true, + }); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +}; + +const getMyInfo: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + + if (!userId) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + try { + const user = await userService.getUserById(userId); + + return res.status(200).json(user); + } catch (err) { + next(err); + } +}; + +const updateMyInfo: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + const { email, nickname } = req.body; + + if (!email && !nickname || userId === null) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const updatedUser = await userService.updateUserInfo(userId, req.body); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +}; + +const updateMyPassword: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + const { password } = req.body; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const updatedUser = await userService.updateUserPassword(userId, password); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +}; + +const getMyProducts: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + try { + const products = await userService.getMyProducts(userId); + + return res.status(200).json(products); + } catch (err) { + next(err); + } +}; + +const getRefreshToken: RequestHandler = async function (req, res, next) { + const userId = req.auth ? req.auth.userId : null; + const refreshToken = req.cookies.refreshToken; + + if (!refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + next(err); + } + + try { + const accessToken = await userService.refreshToken(Number(userId), refreshToken); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +}; + +export { + createUser, + getAccessToken, + getMyInfo, + updateMyInfo, + updateMyPassword, + getMyProducts, + getRefreshToken, +}; diff --git a/mission_5/src/handler/errorHandler.ts b/mission_5/src/handler/errorHandler.ts new file mode 100644 index 000000000..ed4c35489 --- /dev/null +++ b/mission_5/src/handler/errorHandler.ts @@ -0,0 +1,12 @@ +import type { ErrorRequestHandler } from "express"; + +const errorHandler: ErrorRequestHandler = function (err, req, res, next) { + console.error(`[ERROR] ${err.stack || err.message}`); + + const statusCode = err.statusCode || 500; + const message = err.message || "Internal server error!"; + + res.status(statusCode).json({ message }); +} + +export default errorHandler; \ No newline at end of file diff --git a/mission_5/src/lib/prisma.ts b/mission_5/src/lib/prisma.ts new file mode 100644 index 000000000..b904402d2 --- /dev/null +++ b/mission_5/src/lib/prisma.ts @@ -0,0 +1,5 @@ +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +export default prisma; \ No newline at end of file diff --git a/mission_5/src/main.ts b/mission_5/src/main.ts new file mode 100644 index 000000000..6dd21b529 --- /dev/null +++ b/mission_5/src/main.ts @@ -0,0 +1,41 @@ +import path from "path"; + +import express from "express"; +import type { Request, Response, NextFunction } from "express"; +import cors from "cors"; +import cookieParser from "cookie-parser"; +import productRouter from "./router/productRouter.js"; +import articleRouter from "./router/articleRouter.js"; +import imageRouter from "./router/imageRouter.js"; +import userRouter from "./router/userRouter.js"; + +import errorHandler from "./handler/errorHandler.js"; + +const PORT = Number(process.env.PORT) || 3000; + +const app = express(); +app.use(express.json()); +app.use( + cors({ + methods: ["GET", "POST", "PUT", "PATCH", "DELETE"], + }) +); +app.use(cookieParser()); + +function logRequest(req: Request, _: Response, next: NextFunction) { + console.log(`[${req.method}] ${req.originalUrl}`); + next(); +} + +// middleware for logging all http request +app.use(logRequest); + +app.use("/products", productRouter); +app.use("/articles", articleRouter); +app.use("/upload", imageRouter); +app.use(userRouter); + +app.use(errorHandler); +app.use("/upload", express.static(path.resolve("uploads"))); + +app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); diff --git a/mission_5/src/middleware/auth.ts b/mission_5/src/middleware/auth.ts new file mode 100644 index 000000000..0d040e8c6 --- /dev/null +++ b/mission_5/src/middleware/auth.ts @@ -0,0 +1,173 @@ +import type { RequestHandler } from "express"; +import { expressjwt } from "express-jwt"; +import * as articleRepository from "../repository/articleRepository.js"; +import * as productRepository from "../repository/productRepository.js"; + +// 토큰 검증 +const verifyAccessToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + requestProperty: "user", +}); + +// refresh 토큰 검증 +const verifyRefreshToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + getToken: (req) => req.cookies.refreshToken, +}); + +// 게시글 유저 검증 +const verifyArticleAuth: RequestHandler = async (req, res, next) => { + // Get article id + const { id } = req.params; + + // Get article author's id + try { + const article = await articleRepository.getPost({ id: Number(id) }); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + return next(err); + } + + // Call next if valid user + if (req.user && req.user.userId === article.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 유저 검증 +const verifyProductAuth: RequestHandler = async (req, res, next) => { + // Get product id + const { id } = req.params; + + // Get product uploaders's id + try { + const product = await productRepository.getProduct({ id: Number(id) }); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + return next(err); + } + + // Call next if valid user + if (req.user && req.user.userId === product.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 게시글 존재 여부 확인 +const checkArticleExist: RequestHandler = async (req, res, next) => { + const { id } = req.params; + + try { + const article = await articleRepository.getPost({ id: Number(id) }); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + return next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 상품 존재 여부 확인 +const checkProductExist: RequestHandler = async (req, res, next) => { + const { id } = req.params; + + try { + const product = await productRepository.getProduct({ id: Number(id) }); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + return next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 게시글 댓글 유저 검증 +const verifyArticleCommentAuth: RequestHandler = async (req, res, next) => { + const { cid } = req.params; + + if (!cid) { + const err = new Error("Comment id is required"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await articleRepository.getComment({ cid: parseInt(cid) }); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + return next(err); + } + + if (req.user && req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 댓글 유저 검증 +const verifyProductCommentAuth: RequestHandler = async (req, res, next) => { + const { cid } = req.params; + + if (!cid) { + const err = new Error("Comment id is required"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productRepository.getComment({ cid: parseInt(cid) }); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + return next(err); + } + + if (req.user && req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +export default { + verifyAccessToken, + verifyRefreshToken, + verifyArticleAuth, + verifyProductAuth, + checkArticleExist, + checkProductExist, + verifyArticleCommentAuth, + verifyProductCommentAuth, +}; diff --git a/mission_5/src/middleware/index.ts b/mission_5/src/middleware/index.ts new file mode 100644 index 000000000..02584180c --- /dev/null +++ b/mission_5/src/middleware/index.ts @@ -0,0 +1 @@ +export * from './validator.js'; \ No newline at end of file diff --git a/mission_5/src/middleware/validator.ts b/mission_5/src/middleware/validator.ts new file mode 100644 index 000000000..48cf69245 --- /dev/null +++ b/mission_5/src/middleware/validator.ts @@ -0,0 +1,31 @@ +import type { RequestHandler } from "express"; + +// Verify required parameters are okay +const validateProduct: RequestHandler = async function (req, res, next) { + const { name, description, price, tags } = req.body; + + // validation logic (possible improvements with Zod library in the future) + if (!name || !description || !price || !tags) + return res.status(400).json({ message: "Missing required fields" }); + + if (isNaN(price)) + return res.status(400).json({ message: "Price must be a number" }); + + if (!Array.isArray(tags) || !tags.every((tag) => typeof tag === "string")) + return res.status(400).json({ message: "Tags must be an array of string" }); + + next(); +}; + +// Verify required parameters are okay +const validateArticle: RequestHandler = async function (req, res, next) { + const { title, content } = req.body; + + // validation + if (!title || !content) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + next(); +}; + +export { validateProduct, validateArticle }; diff --git a/mission_5/src/repository/articleRepository.ts b/mission_5/src/repository/articleRepository.ts new file mode 100644 index 000000000..a3a79f670 --- /dev/null +++ b/mission_5/src/repository/articleRepository.ts @@ -0,0 +1,177 @@ +import prisma from "../lib/prisma.js"; +import type { + CreatePostDTO, + GetPostsDTO, + GetPostDTO, + PatchPostDTO, + DeletePostDTO, + PostCommentDTO, + GetCommentsDTO, + GetCommentDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/article.js"; + +export async function createPost(data: CreatePostDTO) { + return await prisma.article.create({ + data, + }); +} + +export async function getPosts(data: GetPostsDTO) { + // search에 값이 있을 때만 where로 문자열 검색 + const where = data.search + ? { + OR: [ + { + title: { + contains: data.search, + mode: "insensitive" as const, + }, + }, + { + content: { + contains: data.search, + mode: "insensitive" as const, + }, + }, + ], + } + : {}; + + const result = await prisma.article.findMany({ + select: { + id: true, + title: true, + content: true, + createdAt: true, + }, + orderBy: { + createdAt: data.sort, + }, + where, + skip: data.offset * data.limit, + take: data.limit, + }); + + return result; +} + +export async function getPost(data: GetPostDTO) { + const result = await prisma.article.findUnique({ + where: { + id: data.id, + }, + }); + + return result; +} + +export async function patchPost(data: PatchPostDTO) { + const { id, ...filteredBody } = data; + + const result = await prisma.article.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deletePost(data: DeletePostDTO) { + const { id } = data; + + const result = await prisma.article.delete({ + where: { + id, + }, + }); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const { pid: articleId, name, content, userId } = data; + + const result = await prisma.comment.create({ + data: { + name, + content, + articleId, + userId, + }, + }); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const { pid, cursor, limit } = data; + + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + articleId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(data: GetCommentDTO) { + const { cid: id } = data; + + const result = await prisma.comment.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const { cid, name, content } = data; + + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const { cid } = data; + + const result = prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} diff --git a/mission_5/src/repository/index.ts b/mission_5/src/repository/index.ts new file mode 100644 index 000000000..a9bc4c15b --- /dev/null +++ b/mission_5/src/repository/index.ts @@ -0,0 +1 @@ +export * from './articleRepository.js'; \ No newline at end of file diff --git a/mission_5/src/repository/productRepository.ts b/mission_5/src/repository/productRepository.ts new file mode 100644 index 000000000..9d5dafb2f --- /dev/null +++ b/mission_5/src/repository/productRepository.ts @@ -0,0 +1,197 @@ +import prisma from "../lib/prisma.js"; +import type { + CreateProductDTO, + GetProductsDTO, + GetProductDTO, + PatchProductDTO, + DeleteProductDTO, + PostCommentDTO, + GetCommentsDTO, + GetCommentDTO, + PatchCommentDTO, + DeleteCommentDTO, + GetProductsByUserDTO, +} from "../types/product.js"; + +export async function createProduct(data: CreateProductDTO) { + const { userId, name, description, price, tags } = data; + + return await prisma.product.create({ + data: { + name, + description, + price, + tags, + userId, + }, + }); +} + +export async function getProducts(data: GetProductsDTO) { + const { offset, limit, sort, search } = data; + + const result = await prisma.product.findMany({ + select: { + id: true, + name: true, + price: true, + createdAt: true, + }, + orderBy: { + createdAt: sort, + }, + where: { + OR: [ + { + name: { + contains: search, + mode: "insensitive", + }, + }, + { + description: { + contains: search, + mode: "insensitive", + }, + }, + ], + }, + skip: offset * limit, + take: limit, + }); + + return result; +} + +export async function getProduct(data: GetProductDTO) { + const { id } = data; + const result = await prisma.product.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchProduct(data: PatchProductDTO) { + const { id, ...filteredBody } = data; + + const result = await prisma.product.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deleteProduct(data: DeleteProductDTO) { + const { id } = data; + + const result = await prisma.product.delete({ + where: { + id, + }, + }); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const { pid, userId, name, content } = data; + + const result = await prisma.comment.create({ + data: { + userId, + name, + content, + productId: pid, + }, + }); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const { pid, cursor, limit } = data; + + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + productId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(data: GetCommentDTO) { + const { cid: id } = data; + + const result = await prisma.comment.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const { cid, name, content } = data; + + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const { cid } = data; + + const result = await prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} + +export async function getProductsByUser(data: GetProductsByUserDTO) { + const { userId: id } = data; + + const products = await prisma.user.findUnique({ + where: { id }, + select: { + Product: true, + }, + }); + + return products; +} diff --git a/mission_5/src/repository/userRepository.ts b/mission_5/src/repository/userRepository.ts new file mode 100644 index 000000000..3ec40d685 --- /dev/null +++ b/mission_5/src/repository/userRepository.ts @@ -0,0 +1,61 @@ +import prisma from "../lib/prisma.js"; +import bcrypt from "bcrypt"; +import type { CreateUserDTO, UserInfoDTO, GetUserDTO } from "../types/user.js"; + +export async function createUser(user: CreateUserDTO) { + const hashedPassword = await hashPassword(user.password); + + const createdUser = await prisma.user.create({ + data: { + ...user, + password: hashedPassword, // This line overwrites user.password + }, + }); + + return createdUser; +} + +export async function findByEmail(email: string) { + const result = await prisma.user.findFirst({ + where: { + email, + }, + }); + + return result; +} + +export async function findById(id: number) { + const result = await prisma.user.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function hashPassword(password: string) { + const salt = await bcrypt.genSalt(10); + const hash = await bcrypt.hash(password, salt); + + return hash; +} + +export function filterSensitiveUserData(user: UserInfoDTO) { + const { password, refreshToken, ...rest } = user; + return rest; +} + +export async function updateUser(id: number, toUpdate: any) { + if (toUpdate.password) { + toUpdate.password = await hashPassword(toUpdate.password); + } + + const updatedUser = await prisma.user.update({ + where: { id }, + data: toUpdate, + }); + + return updatedUser; +} diff --git a/mission_5/src/router/articleRouter.ts b/mission_5/src/router/articleRouter.ts new file mode 100644 index 000000000..07b603722 --- /dev/null +++ b/mission_5/src/router/articleRouter.ts @@ -0,0 +1,73 @@ +import express from "express"; +import { validateArticle } from "../middleware/index.js"; +import auth from "../middleware/auth.js"; +import * as articleController from "../controller/articleController.js"; + +const router = express.Router(); + +router + .route("/") + + // Create a post + .post( + auth.verifyAccessToken, + validateArticle, + articleController.createPost + ) + + // Retrieve all articles + .get(articleController.getPosts); + +router + .route("/:id") + + // Get informations of a specific article + .get(articleController.getPost) + + // Modify a article property + .patch( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.patchPost + ) + + // Delete a particular article + .delete( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.deletePost + ); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkArticleExist, + articleController.postComment + ) + + // Inquery all comments + .get(auth.checkArticleExist, articleController.getComments); + +router + .route("/:id/comments/:cid") + + // Modify comment + .patch( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.patchComment + ) + + // Delete comment + .delete( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.deleteComment + ); + +export default router; diff --git a/mission_5/src/router/imageRouter.ts b/mission_5/src/router/imageRouter.ts new file mode 100644 index 000000000..e73d6d5fd --- /dev/null +++ b/mission_5/src/router/imageRouter.ts @@ -0,0 +1,19 @@ +import express from 'express'; +import multer from "multer"; + +const router = express.Router(); + +const upload = multer({ dest: 'uploads/' }); + +// 이미지 리사이징 기능 구현 예정 +router.post('/', upload.single('image'), async (req, res) => { + // console.log(req.file); + if (!req.file) { + return res.status(400).json({ message: 'No file uploaded' }); + } + + res.status(201).json({ message: 'Upload OK', filePath: req.file.path }); +}); + + +export default router; \ No newline at end of file diff --git a/mission_5/src/router/index.ts b/mission_5/src/router/index.ts new file mode 100644 index 000000000..921cc19ab --- /dev/null +++ b/mission_5/src/router/index.ts @@ -0,0 +1,3 @@ +export * from './articleRouter.js'; +export * from './productRouter.js'; +export * from './imageRouter.js'; \ No newline at end of file diff --git a/mission_5/src/router/productRouter.ts b/mission_5/src/router/productRouter.ts new file mode 100644 index 000000000..8b9a5813f --- /dev/null +++ b/mission_5/src/router/productRouter.ts @@ -0,0 +1,72 @@ +import express from "express"; +import type { Router } from "express"; +import { validateProduct } from "../middleware/validator.js"; +import auth from "../middleware/auth.js"; +import * as productController from "../controller/productController.js"; + +const router = express.Router(); + +router + .route("/") + + // Upload a new product + .post( + auth.verifyAccessToken, + validateProduct, + productController.createProduct + ) + + // Retrieve all products + .get(productController.getProducts); + +router + .route("/:id") + + // Get informations of a specific product + .get(productController.getProduct) + + // Modify a product property + .patch( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.patchProduct + ) + + // Delete a particular product + .delete( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.deleteProduct + ); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkProductExist, + productController.postComment + ) + + // Inquery all comments + .get(auth.checkProductExist, productController.getComments); + +router + .route("/:id/comments/:cid") + + .patch( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.patchComment + ) + + .delete( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.deleteComment + ); + +export default router; diff --git a/mission_5/src/router/userRouter.ts b/mission_5/src/router/userRouter.ts new file mode 100644 index 000000000..9ab871231 --- /dev/null +++ b/mission_5/src/router/userRouter.ts @@ -0,0 +1,44 @@ +import express from "express"; +import * as userController from "../controller/userController.js"; +import auth from "../middleware/auth.js"; + +const userRouter = express.Router(); + +userRouter + .route("/users") + + // Create user + .post(userController.createUser) + + // Get my(user) info + .get(auth.verifyAccessToken, userController.getMyInfo); + +// Update user info (nickname, email) +userRouter.patch( + "/users/info", + auth.verifyAccessToken, + userController.updateMyInfo +); + +// Update user password +userRouter.patch( + "/users/password", + auth.verifyAccessToken, + userController.updateMyPassword +); + +// Get product lists uploaded by user +userRouter.get( + "/users/products", + auth.verifyAccessToken, + userController.getMyProducts +); + +userRouter.post("/login", userController.getAccessToken); +userRouter.post( + "/login/refresh", + auth.verifyRefreshToken, + userController.getRefreshToken +); + +export default userRouter; diff --git a/mission_5/src/services/articleService.ts b/mission_5/src/services/articleService.ts new file mode 100644 index 000000000..f57c263dd --- /dev/null +++ b/mission_5/src/services/articleService.ts @@ -0,0 +1,65 @@ +import * as articleRepository from "../repository/articleRepository.js"; +import type { + CreatePostDTO, + GetPostsDTO, + GetPostDTO, + PatchPostDTO, + DeletePostDTO, + PostCommentDTO, + GetCommentsDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/article.js"; + +export async function createPost(data: CreatePostDTO) { + const result = await articleRepository.createPost(data); + + return result; +} + +export async function getPosts(data: GetPostsDTO) { + const result = await articleRepository.getPosts(data); + + return result; +} + +export async function getPost(id: GetPostDTO) { + const result = await articleRepository.getPost(id); + + return result; +} + +export async function patchPost(data: PatchPostDTO) { + const result = await articleRepository.patchPost(data); + + return result; +} + +export async function deletePost(id: DeletePostDTO) { + const result = await articleRepository.deletePost(id); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const result = await articleRepository.postComment(data); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const result = await articleRepository.getComments(data); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const result = await articleRepository.patchComment(data); + + return result; +} +export async function deleteComment(data: DeleteCommentDTO) { + const result = await articleRepository.deleteComment(data); + + return result; +} diff --git a/mission_5/src/services/index.ts b/mission_5/src/services/index.ts new file mode 100644 index 000000000..ce045fa9e --- /dev/null +++ b/mission_5/src/services/index.ts @@ -0,0 +1 @@ +export * from './articleService.js'; \ No newline at end of file diff --git a/mission_5/src/services/productService.ts b/mission_5/src/services/productService.ts new file mode 100644 index 000000000..918726321 --- /dev/null +++ b/mission_5/src/services/productService.ts @@ -0,0 +1,66 @@ +import * as productRepository from "../repository/productRepository.js"; +import type { + CreateProductDTO, + GetProductsDTO, + GetProductDTO, + PatchProductDTO, + DeleteProductDTO, + PostCommentDTO, + GetCommentsDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/product.js"; + +export async function createProduct(data: CreateProductDTO) { + const result = await productRepository.createProduct(data); + + return result; +} + +export async function getProducts(data: GetProductsDTO) { + const result = await productRepository.getProducts(data); + + return result; +} + +export async function getProduct(data: GetProductDTO) { + const result = await productRepository.getProduct(data); + + return result; +} + +export async function patchProduct(data: PatchProductDTO) { + const result = await productRepository.patchProduct(data); + + return result; +} + +export async function deleteProduct(data: DeleteProductDTO) { + const result = await productRepository.deleteProduct(data); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const result = await productRepository.postComment(data); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const result = await productRepository.getComments(data); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const result = await productRepository.patchComment(data); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const result = await productRepository.deleteComment(data); + + return result; +} diff --git a/mission_5/src/services/userService.ts b/mission_5/src/services/userService.ts new file mode 100644 index 000000000..2060ef614 --- /dev/null +++ b/mission_5/src/services/userService.ts @@ -0,0 +1,121 @@ +import * as userRepository from "../repository/userRepository.js"; +import * as productRepository from "../repository/productRepository.js"; +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; +import type { CreateUserDTO, GetUserDTO, UserInfoDTO } from "../types/user.js"; + +export async function createUser(user: CreateUserDTO) { + // 이미 가입된 이메일인지 검증 + const existedUser = await userRepository.findByEmail(user.email); + + if (existedUser) { + const err = new Error("User already exists"); + err.statusCode = 422; + throw err; + } + + const createdUser = await userRepository.createUser(user); + const createdUserId = await userRepository.filterSensitiveUserData( + createdUser + ).id; + + return createdUserId; +} + +export async function getUser({ email, password }: GetUserDTO) { + const user: UserInfoDTO | null = await userRepository.findByEmail(email); + + // If user is invalid + if (!user || !user.password) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + throw err; + } + + // Verifying password + await verifyPassword(password, user.password); + + // Return without password + return userRepository.filterSensitiveUserData(user); +} + +export async function getUserById(userId: number) { + const user = await userRepository.findById(userId); + + if (!user) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return userRepository.filterSensitiveUserData(user); +} + +async function verifyPassword(inputPassword: string, password: string) { + const isVerified = await bcrypt.compare(inputPassword, password); + + if (!isVerified) { + const err = new Error("Password is wrong"); + err.statusCode = 401; + throw err; + } +} + +export function createToken(user: UserInfoDTO, token: string | null = null) { + const payload = { userId: user.id }; + const options: jwt.SignOptions = { + expiresIn: token === "refresh" ? "2W" : "1H", + }; + + if (!process.env.JWT_SECRET) { + throw new Error("JWT_SECRET is not defined"); + } + + return jwt.sign(payload, process.env.JWT_SECRET, options); +} + +export async function refreshToken(userId: number, refreshToken: string) { + const user = await userRepository.findById(userId); + + if (!user || user.refreshToken !== refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 404; + throw err; + } + + const accessToken = createToken(user); + return accessToken; +} + +export async function updateUserInfo(userId: number, toUpdate: any) { + // 수정할 내용이 없다면 에러 처리 + if (Object.keys(toUpdate).length === 0) { + const err = new Error("No data to update"); + err.statusCode = 400; + throw err; + } + + const updatedUser = await userRepository.updateUser(userId, toUpdate); + + return userRepository.filterSensitiveUserData(updatedUser); +} + +export async function updateUserPassword(userId: number, newPassword: string) { + const hashedPassword = await userRepository.hashPassword(newPassword); + const user = await userRepository.updateUser(userId, { + password: hashedPassword, + }); + + return userRepository.filterSensitiveUserData(user); +} + +export async function getMyProducts(userId: number) { + const products = await productRepository.getProductsByUser({ userId }); + if (!products) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return products.Product; +} diff --git a/mission_5/src/types/article.ts b/mission_5/src/types/article.ts new file mode 100644 index 000000000..1398c1c95 --- /dev/null +++ b/mission_5/src/types/article.ts @@ -0,0 +1,54 @@ +export interface CreatePostDTO { + title: string; + content: string; + userId: number; +} + +export interface GetPostsDTO { + cursor?: number; + limit: number; + sort: "asc" | "desc"; + offset: number; + search?: string; +} + +export interface GetPostDTO { + id: number; +} + +export interface PatchPostDTO { + id: number; + title?: string; + content?: string; +} + +export interface DeletePostDTO { + id: number; +} + +export interface PostCommentDTO { + pid: number; + name: string; + content: string; + userId: number; +} + +export interface GetCommentsDTO { + pid: number; + cursor: number; + limit: number; +} + +export interface GetCommentDTO { + cid: number; +} + +export interface PatchCommentDTO { + cid: number; + name: string; + content: string; +} + +export interface DeleteCommentDTO { + cid: number; +} diff --git a/mission_5/src/types/auth.d.ts b/mission_5/src/types/auth.d.ts new file mode 100644 index 000000000..7353fbba8 --- /dev/null +++ b/mission_5/src/types/auth.d.ts @@ -0,0 +1,5 @@ +export interface JwtPayload { + userId: number; + iat?: number; + exp?: number; +} diff --git a/mission_5/src/types/express/index.d.ts b/mission_5/src/types/express/index.d.ts new file mode 100644 index 000000000..25cbc8d62 --- /dev/null +++ b/mission_5/src/types/express/index.d.ts @@ -0,0 +1,10 @@ +import "express"; +import type { JwtPayload } from "../auth.d.js"; + +declare module "express-serve-static-core" { + interface Request { + // user?: import("../types/auth").JwtPayload; + user?: JwtPayload; + auth?: JwtPayload; + } +} diff --git a/mission_5/src/types/global.ts b/mission_5/src/types/global.ts new file mode 100644 index 000000000..452228e41 --- /dev/null +++ b/mission_5/src/types/global.ts @@ -0,0 +1,5 @@ +declare global { + interface Error { + statusCode?: number; + } +} \ No newline at end of file diff --git a/mission_5/src/types/product.ts b/mission_5/src/types/product.ts new file mode 100644 index 000000000..52d1aa2f2 --- /dev/null +++ b/mission_5/src/types/product.ts @@ -0,0 +1,63 @@ +export interface CreateProductDTO { + userId: number; + name: string; + description: string; + price: number; + tags: string[]; +} + +export interface GetProductsDTO { + offset: number; + limit: number; + sort: "asc" | "desc"; + search: string; +} + +export interface GetProductDTO { + id: number; +} + +export interface PatchProductDTO { + id: number; + name?: string; + description?: string; + price?: number; + tags?: string[]; +} + +export interface DeleteProductDTO { + id: number; +} + +export interface PostCommentDTO { + pid: number; + userId: number; + content: string; + name: string; +} + +export interface GetCommentsDTO { + pid: number; + cursor: number | null; + limit: number; +} + +export interface GetCommentDTO { + cid: number; +} + +export interface PatchCommentDTO { + cid: number; + name: string; + content: string; +} + +export interface DeleteCommentDTO { + cid: number; +} + +export interface GetProductsByUserDTO { + userId: number; + offset?: number; + limit?: number; +} diff --git a/mission_5/src/types/user.ts b/mission_5/src/types/user.ts new file mode 100644 index 000000000..adf66d149 --- /dev/null +++ b/mission_5/src/types/user.ts @@ -0,0 +1,21 @@ +export interface CreateUserDTO { + email: string; + nickname: string; + password: string; +} + +export interface GetUserDTO { + email: string; + password: string; +} + +export interface UserInfoDTO { + password?: string; + email: string; + nickname: string; + image: string | null; + refreshToken?: string | null; + createdAt: Date; + updatedAt: Date; + id: number; +} diff --git a/mission_5/tsconfig.json b/mission_5/tsconfig.json new file mode 100644 index 000000000..cbfb43efb --- /dev/null +++ b/mission_5/tsconfig.json @@ -0,0 +1,48 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "moduleResolution": "nodenext", + "target": "es2022", + // "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, + + "esModuleInterop": true + }, + "include": ["src", "env.d.ts"] +} From 57c505a6fc26cd29105e7a882072225a145b4ff6 Mon Sep 17 00:00:00 2001 From: intwocave Date: Wed, 17 Sep 2025 21:12:17 +0900 Subject: [PATCH 067/130] feat: add dev script for development --- mission_5/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mission_5/package.json b/mission_5/package.json index a9c01c4d5..2a9b1d8bd 100644 --- a/mission_5/package.json +++ b/mission_5/package.json @@ -6,7 +6,8 @@ "test": "echo \"Error: no test specified\" && exit 1", "build": "tsc", "start": "NODE_ENV=production node dist/main.js", - "dev": "nodemon" + "dev": "ts-node src/main.ts", + "dev:server": "nodemon" }, "keywords": [], "author": "", From fcd1e69deb21ad41f1a2259e71da002cc9233367 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 15:06:02 +0900 Subject: [PATCH 068/130] init: copy mission 5 to mission 8 --- mission_8/.gitignore | 10 + mission_8/env.d.ts | 13 + mission_8/nodemon.json | 5 + mission_8/package-lock.json | 2642 +++++++++++++++++ mission_8/package.json | 45 + mission_8/prisma/schema.prisma | 67 + mission_8/prisma/seed.ts | 94 + mission_8/src/container.ts | 1 + mission_8/src/controller/articleController.ts | 253 ++ mission_8/src/controller/index.ts | 1 + mission_8/src/controller/productController.ts | 267 ++ mission_8/src/controller/userController.ts | 156 + mission_8/src/handler/errorHandler.ts | 12 + mission_8/src/lib/prisma.ts | 5 + mission_8/src/main.ts | 41 + mission_8/src/middleware/auth.ts | 173 ++ mission_8/src/middleware/index.ts | 1 + mission_8/src/middleware/validator.ts | 31 + mission_8/src/repository/articleRepository.ts | 177 ++ mission_8/src/repository/index.ts | 1 + mission_8/src/repository/productRepository.ts | 197 ++ mission_8/src/repository/userRepository.ts | 61 + mission_8/src/router/articleRouter.ts | 73 + mission_8/src/router/imageRouter.ts | 19 + mission_8/src/router/index.ts | 3 + mission_8/src/router/productRouter.ts | 72 + mission_8/src/router/userRouter.ts | 44 + mission_8/src/services/articleService.ts | 65 + mission_8/src/services/index.ts | 1 + mission_8/src/services/productService.ts | 66 + mission_8/src/services/userService.ts | 121 + mission_8/src/types/article.ts | 54 + mission_8/src/types/auth.d.ts | 5 + mission_8/src/types/express/index.d.ts | 10 + mission_8/src/types/global.ts | 5 + mission_8/src/types/product.ts | 63 + mission_8/src/types/user.ts | 21 + mission_8/tsconfig.json | 48 + 38 files changed, 4923 insertions(+) create mode 100644 mission_8/.gitignore create mode 100644 mission_8/env.d.ts create mode 100644 mission_8/nodemon.json create mode 100644 mission_8/package-lock.json create mode 100644 mission_8/package.json create mode 100644 mission_8/prisma/schema.prisma create mode 100644 mission_8/prisma/seed.ts create mode 100644 mission_8/src/container.ts create mode 100644 mission_8/src/controller/articleController.ts create mode 100644 mission_8/src/controller/index.ts create mode 100644 mission_8/src/controller/productController.ts create mode 100644 mission_8/src/controller/userController.ts create mode 100644 mission_8/src/handler/errorHandler.ts create mode 100644 mission_8/src/lib/prisma.ts create mode 100644 mission_8/src/main.ts create mode 100644 mission_8/src/middleware/auth.ts create mode 100644 mission_8/src/middleware/index.ts create mode 100644 mission_8/src/middleware/validator.ts create mode 100644 mission_8/src/repository/articleRepository.ts create mode 100644 mission_8/src/repository/index.ts create mode 100644 mission_8/src/repository/productRepository.ts create mode 100644 mission_8/src/repository/userRepository.ts create mode 100644 mission_8/src/router/articleRouter.ts create mode 100644 mission_8/src/router/imageRouter.ts create mode 100644 mission_8/src/router/index.ts create mode 100644 mission_8/src/router/productRouter.ts create mode 100644 mission_8/src/router/userRouter.ts create mode 100644 mission_8/src/services/articleService.ts create mode 100644 mission_8/src/services/index.ts create mode 100644 mission_8/src/services/productService.ts create mode 100644 mission_8/src/services/userService.ts create mode 100644 mission_8/src/types/article.ts create mode 100644 mission_8/src/types/auth.d.ts create mode 100644 mission_8/src/types/express/index.d.ts create mode 100644 mission_8/src/types/global.ts create mode 100644 mission_8/src/types/product.ts create mode 100644 mission_8/src/types/user.ts create mode 100644 mission_8/tsconfig.json diff --git a/mission_8/.gitignore b/mission_8/.gitignore new file mode 100644 index 000000000..d58e9d958 --- /dev/null +++ b/mission_8/.gitignore @@ -0,0 +1,10 @@ +node_modules +/dist + +# Keep environment variables out of version control +.env + +/generated/prisma +/prisma/migrations + +todo.list \ No newline at end of file diff --git a/mission_8/env.d.ts b/mission_8/env.d.ts new file mode 100644 index 000000000..f4b3b91de --- /dev/null +++ b/mission_8/env.d.ts @@ -0,0 +1,13 @@ +declare namespace NodeJS { + interface ProcessEnv { + NODE_ENV: "development" | "production"; + PORT?: string; + DATABASE_URL?: string; + /* DB_HOST: string; + DB_PORT: string; + DB_USERNAME: string; + DB_PASSWORD: string; + DB_NAME: string; */ + JWT_SECRET: string; + } +} diff --git a/mission_8/nodemon.json b/mission_8/nodemon.json new file mode 100644 index 000000000..647b3dd15 --- /dev/null +++ b/mission_8/nodemon.json @@ -0,0 +1,5 @@ +{ + "watch": ["src"], + "ext": "ts", + "exec": "ts-node ./src/main.ts" +} \ No newline at end of file diff --git a/mission_8/package-lock.json b/mission_8/package-lock.json new file mode 100644 index 000000000..0c9c8f9af --- /dev/null +++ b/mission_8/package-lock.json @@ -0,0 +1,2642 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sprint_mission_3", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "express": "^5.1.0", + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1" + }, + "devDependencies": { + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.9", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.3", + "@types/express-jwt": "^6.0.4", + "@types/multer": "^2.0.0", + "@types/node": "^24.3.1", + "nodemon": "^3.1.10", + "prisma": "^6.13.0", + "ts-node": "^10.9.2", + "typescript": "^5.9.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@prisma/client": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.13.0.tgz", + "integrity": "sha512-8m2+I3dQovkV8CkDMluiwEV1TxV9EXdT6xaCz39O6jYw7mkf5gwfmi+cL4LJsEPwz5tG7sreBwkRpEMJedGYUQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.13.0.tgz", + "integrity": "sha512-OYMM+pcrvj/NqNWCGESSxVG3O7kX6oWuGyvufTUNnDw740KIQvNyA4v0eILgkpuwsKIDU36beZCkUtIt0naTog==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.16.12", + "read-package-up": "11.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.13.0.tgz", + "integrity": "sha512-um+9pfKJW0ihmM83id9FXGi5qEbVJ0Vxi1Gm0xpYsjwUBnw6s2LdPBbrsG9QXRX46K4CLWCTNvskXBup4i9hlw==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.13.0.tgz", + "integrity": "sha512-D+1B79LFvtWA0KTt8ALekQ6A/glB9w10ETknH5Y9g1k2NYYQOQy93ffiuqLn3Pl6IPJG3EsK/YMROKEaq8KBrA==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/fetch-engine": "6.13.0", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd.tgz", + "integrity": "sha512-MpPyKSzBX7P/ZY9odp9TSegnS/yH3CSbchQE9f0yBg3l2QyN59I6vGXcoYcqKC9VTniS1s18AMmhyr1OWavjHg==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.13.0.tgz", + "integrity": "sha512-grmmq+4FeFKmaaytA8Ozc2+Tf3BC8xn/DVJos6LL022mfRlMZYjT3hZM0/xG7+5fO95zFG9CkDUs0m1S2rXs5Q==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.13.0.tgz", + "integrity": "sha512-Nii2pX50fY4QKKxQwm7/vvqT6Ku8yYJLZAFX4e2vzHwRdMqjugcOG5hOSLjxqoXb0cvOspV70TOhMzrw8kqAnw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie-parser": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.9.tgz", + "integrity": "sha512-tGZiZ2Gtc4m3wIdLkZ8mkj1T6CEHb35+VApbL2T14Dew8HA7c+04dmKqsKRNC+8RJPm16JEK0tFSwdZqubfc4g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", + "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-jwt": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-6.0.4.tgz", + "integrity": "sha512-I53KRQ9D0eTA6hVCN9S73iOeprKS3JNWK+Cp2mDPB6uOIkTVpkgSkX394kHQzb5cd0U02I0adRmsMxHk+zX8tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/express-unless": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz", + "integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express-unless": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.3.tgz", + "integrity": "sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/multer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", + "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/node": { + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">= 18" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.16.12", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", + "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-jwt": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.5.1.tgz", + "integrity": "sha512-Dv6QjDLpR2jmdb8M6XQXiCcpEom7mK8TOqnr0/TngDKsG2DHVkO8+XnVxkJVN7BuS1I3OrGw6N8j5DaaGgkDRQ==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "^9", + "express-unless": "^2.1.3", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express-unless": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz", + "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==", + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/index-to-position": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", + "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", + "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "mkdirp": "^0.5.6", + "object-assign": "^4.1.1", + "type-is": "^1.6.18", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", + "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/nodemon": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "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/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "devOptional": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nypm": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", + "integrity": "sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.2.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz", + "integrity": "sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/prisma": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.13.0.tgz", + "integrity": "sha512-dfzORf0AbcEyyzxuv2lEwG8g+WRGF/qDQTpHf/6JoHsyF5MyzCEZwClVaEmw3WXcobgadosOboKUgQU0kFs9kw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.13.0", + "@prisma/engines": "6.13.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "devOptional": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "devOptional": true, + "license": "CC0-1.0" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "devOptional": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + } + } +} diff --git a/mission_8/package.json b/mission_8/package.json new file mode 100644 index 000000000..2a9b1d8bd --- /dev/null +++ b/mission_8/package.json @@ -0,0 +1,45 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc", + "start": "NODE_ENV=production node dist/main.js", + "dev": "ts-node src/main.ts", + "dev:server": "nodemon" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "express": "^5.1.0", + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1" + }, + "devDependencies": { + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.9", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.3", + "@types/express-jwt": "^6.0.4", + "@types/multer": "^2.0.0", + "@types/node": "^24.3.1", + "nodemon": "^3.1.10", + "prisma": "^6.13.0", + "ts-node": "^10.9.2", + "typescript": "^5.9.2" + }, + "prisma": { + "seed": "node prisma/seed.js" + }, + "type": "module" +} diff --git a/mission_8/prisma/schema.prisma b/mission_8/prisma/schema.prisma new file mode 100644 index 000000000..0e23cea27 --- /dev/null +++ b/mission_8/prisma/schema.prisma @@ -0,0 +1,67 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" + // output = "../generated/prisma" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model Product { + id Int @id @default(autoincrement()) + name String + description String + price Int + tags String[] + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] +} + +model Article { + id Int @id @default(autoincrement()) + title String + content String + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] +} + +model Comment { + id Int @id @default(autoincrement()) + name String + content String + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int? + Article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) + articleId Int? +} + +model User { + id Int @id @default(autoincrement()) + email String @unique + nickname String + image String? + password String + refreshToken String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Article Article[] + Product Product[] + Comment Comment[] +} diff --git a/mission_8/prisma/seed.ts b/mission_8/prisma/seed.ts new file mode 100644 index 000000000..0d39f9c2f --- /dev/null +++ b/mission_8/prisma/seed.ts @@ -0,0 +1,94 @@ +import { PrismaClient } from "@prisma/client"; +const prisma = new PrismaClient(); + +async function main() { + // ------------------------------ + // Product 더미 데이터 생성 + // ------------------------------ + const product1 = await prisma.product.create({ + data: { + name: "게이밍 노트북", + description: "고성능 게이밍 및 작업용 노트북", + price: 1800000, + tags: ["노트북", "게이밍", "고성능",], + comments: { + create: [ + { name: "홍길동", content: "배틀그라운드도 잘 돌아가네요!" }, + { name: "김철수", content: "팬 소음이 조금 있지만 성능은 최고입니다." } + ] + } + } + }); + + const product2 = await prisma.product.create({ + data: { + name: "기계식 키보드", + description: "청축 기계식 키보드, 타건감이 뛰어남", + price: 120000, + tags: ["키보드","기계식","청축",], + comments: { + create: [ + { name: "이영희", content: "타이핑할 맛이 납니다." } + ] + } + } + }); + + // ------------------------------ + // Article 더미 데이터 생성 + // ------------------------------ + const article1 = await prisma.article.create({ + data: { + title: "게이밍 PC 조립 가이드", + content: "부품 선택부터 조립까지 단계별 설명...", + comments: { + create: [ + { name: "박영수", content: "이 글 덕분에 처음으로 PC를 조립했습니다." }, + { name: "최민지", content: "부품 추천이 매우 유용했습니다." } + ] + } + } + }); + + const article2 = await prisma.article.create({ + data: { + title: "2025년 인기 프로그래밍 언어 TOP 10", + content: "올해 주목받는 프로그래밍 언어와 트렌드를 분석...", + comments: { + create: [ + { name: "장우진", content: "Rust가 상위권이라니 반갑네요!" } + ] + } + } + }); + + // ------------------------------ + // Comment 모델 개별 생성 (Product/Article와 직접 연결) + // ------------------------------ + await prisma.comment.create({ + data: { + name: "손흥민", + content: "이 제품은 가격 대비 성능이 좋습니다.", + productId: product1.id + } + }); + + await prisma.comment.create({ + data: { + name: "유재석", + content: "기사 내용이 깔끔하게 잘 정리되어 있네요.", + articleId: article2.id + } + }); + + console.log("시딩이 완료되었습니다."); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/mission_8/src/container.ts b/mission_8/src/container.ts new file mode 100644 index 000000000..ba0183f59 --- /dev/null +++ b/mission_8/src/container.ts @@ -0,0 +1 @@ +import prisma from './lib/prisma.js'; \ No newline at end of file diff --git a/mission_8/src/controller/articleController.ts b/mission_8/src/controller/articleController.ts new file mode 100644 index 000000000..2f603387d --- /dev/null +++ b/mission_8/src/controller/articleController.ts @@ -0,0 +1,253 @@ +import * as articleService from "../services/articleService.js"; +import type { RequestHandler } from "express"; + +const createPost: RequestHandler = async function (req, res, next) { + const { title, content } = req.body; + + const userId = req.user ? req.user.userId : null; + if (userId === null) { + const err = new Error("Access token is missing or invalid"); + err.statusCode = 401; + return next(err); + } + + if (!title || !content) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + const article = await articleService.createPost({ userId, title, content }); + res.status(201).json(article); + } catch (err) { + next(err); + } +}; + +const getPosts: RequestHandler = async function (req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search } = req.query; + + try { + const articles = await articleService.getPosts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search: String(search), + }); + + if (articles) res.status(200).json(articles); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with given parameters`; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const getPost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const article = await articleService.getPost({ id: Number(id) }); + + if (article) res.status(200).json(article); + else { + const err = new Error(`Cannot find article with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchPost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + // Columns in model Article + const articleCols = ["title", "content"]; + + // ? + const filteredBody = Object.entries(req.body) + .filter(([key]) => articleCols.includes(key)) + .reduce>((obj, [key, value]) => { + obj[key] = value; + return obj; + }, {}); + + try { + const article = await articleService.patchPost({ + id: Number(id), + ...filteredBody, + }); + + if (article) res.status(200).json(article); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const deletePost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const deleted = await articleService.deletePost({ id: Number(id) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const postComment: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Access token is missing or invalid"); + err.statusCode = 401; + return next(err); + } + + if (!name || !content || !pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + return next(err); + } + + try { + const comment = await articleService.postComment({ + userId, + name, + content, + pid: Number(pid), + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +}; + +const getComments: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + const comments = await articleService.getComments({ + pid: Number(pid), + cursor: Number(cursor), + limit: Number(limit), + }); + + if (comments) + res.status(200).json({ + comments, + nextCursor: + comments.length === Number(limit) ? comments.at(-1)?.id : null, // llm + }); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comments with id ${pid}`; + return next(err); + } +}; + +const patchComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id' and 'cid'"; + return next(err); + } + + const { name, content } = req.body; + if (!name || !content) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid SQL Parameters"; + return next(err); + } + + const comment = await articleService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comment with ID ${pid}`; + return next(err); + } +}; + +const deleteComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await articleService.deleteComment({ cid: Number(cid) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find any comment with ID ${cid}`); + err.statusCode = 404; + return next(err); + } +}; + +export { + createPost, + getPosts, + getPost, + patchPost, + deletePost, + postComment, + getComments, + patchComment, + deleteComment, +}; diff --git a/mission_8/src/controller/index.ts b/mission_8/src/controller/index.ts new file mode 100644 index 000000000..1d9c8cc37 --- /dev/null +++ b/mission_8/src/controller/index.ts @@ -0,0 +1 @@ +export * from './articleController.js'; \ No newline at end of file diff --git a/mission_8/src/controller/productController.ts b/mission_8/src/controller/productController.ts new file mode 100644 index 000000000..6466d2548 --- /dev/null +++ b/mission_8/src/controller/productController.ts @@ -0,0 +1,267 @@ +import * as productService from "../services/productService.js"; +import type { RequestHandler } from "express"; + +const createProduct: RequestHandler = async function createProduct( + req, + res, + next +) { + // destructuring field data from request body + const { name, description, price, tags } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!name || !description || !price || !tags) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Product table + const product = await productService.createProduct({ + userId, + name, + description, + price, + tags, + }); + + res.status(201).json(product); + } catch (err) { + next(err); + } +}; + +const getProducts: RequestHandler = async function (req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search = "" } = req.query; + + try { + const products = await productService.getProducts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search: String(search), + }); + + if (products) res.status(200).json(products); + else { + const err = new Error("Cannot find products"); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const getProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const product = await productService.getProduct({ id }); + + if (product) res.status(200).json(product); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + // Attributes in model Product + const productCols = ["name", "description", "price", "tags"]; + + // Possible improvement? + const filteredBody = Object.entries(req.body) + .filter(([key]) => productCols.includes(key)) + .reduce>((obj, [key, value]) => { + obj[key] = value; + return obj; + }, {}); + + try { + const product = await productService.patchProduct({ id, ...filteredBody }); + + if (product) res.status(200).json(product); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find product with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const deleteProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const deleted = await productService.deleteProduct({ id }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const postComment: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + // validation + if (!name || !content || !pid) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Comment table + const comment = await productService.postComment({ + userId, + pid: Number(pid), + name, + content, + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +}; + +const getComments: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + try { + const comments = await productService.getComments({ + pid: Number(pid), + cursor: cursor ? Number(cursor) : null, + limit: Number(limit), + }); + + // Cursor pagination + const nextCursor = + comments.length > 0 ? comments[comments.length - 1] : null; + + if (comments) + res.status(200).json({ + comments, + nextCursor, + }); + else { + const err = new Error(`Cannot find any comments`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + const { name, content } = req.body; + + if (!pid || !cid || !name || !content) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(`Cannot find any comment with ID ${cid}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const deleteComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await productService.deleteComment({ cid: Number(cid) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${pid}`); + err.statusCode = 404; + return next(err); + } +}; + +export { + createProduct, + getProducts, + getProduct, + patchProduct, + deleteProduct, + postComment, + getComments, + patchComment, + deleteComment, +}; diff --git a/mission_8/src/controller/userController.ts b/mission_8/src/controller/userController.ts new file mode 100644 index 000000000..397fed1ad --- /dev/null +++ b/mission_8/src/controller/userController.ts @@ -0,0 +1,156 @@ +import * as userService from "../services/userService.js"; +import type { RequestHandler } from "express"; + +// for Creating user +const createUser: RequestHandler = async function (req, res, next) { + const { email, nickname, password } = req.body; + + if (!email || !nickname || !password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const userId = await userService.createUser({ email, nickname, password }); + + return res.status(200).json(userId); + } catch (err) { + next(err); + } +}; + +// for Login +const getAccessToken: RequestHandler = async function (req, res, next) { + const { email, password } = req.body; + + if (!email || !password) { + const err = new Error("Email or password is wrong"); + err.statusCode = 404; + return next(err); + } + + try { + const user = await userService.getUser(req.body); + const accessToken = userService.createToken(user); + const refreshToken = userService.createToken(user, "refresh"); + await userService.updateUserInfo(user.id, { refreshToken }); + res.cookie("refreshToken", refreshToken, { + httpOnly: true, + sameSite: "none", + secure: true, + }); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +}; + +const getMyInfo: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + + if (!userId) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + try { + const user = await userService.getUserById(userId); + + return res.status(200).json(user); + } catch (err) { + next(err); + } +}; + +const updateMyInfo: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + const { email, nickname } = req.body; + + if (!email && !nickname || userId === null) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const updatedUser = await userService.updateUserInfo(userId, req.body); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +}; + +const updateMyPassword: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + const { password } = req.body; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const updatedUser = await userService.updateUserPassword(userId, password); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +}; + +const getMyProducts: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + try { + const products = await userService.getMyProducts(userId); + + return res.status(200).json(products); + } catch (err) { + next(err); + } +}; + +const getRefreshToken: RequestHandler = async function (req, res, next) { + const userId = req.auth ? req.auth.userId : null; + const refreshToken = req.cookies.refreshToken; + + if (!refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + next(err); + } + + try { + const accessToken = await userService.refreshToken(Number(userId), refreshToken); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +}; + +export { + createUser, + getAccessToken, + getMyInfo, + updateMyInfo, + updateMyPassword, + getMyProducts, + getRefreshToken, +}; diff --git a/mission_8/src/handler/errorHandler.ts b/mission_8/src/handler/errorHandler.ts new file mode 100644 index 000000000..ed4c35489 --- /dev/null +++ b/mission_8/src/handler/errorHandler.ts @@ -0,0 +1,12 @@ +import type { ErrorRequestHandler } from "express"; + +const errorHandler: ErrorRequestHandler = function (err, req, res, next) { + console.error(`[ERROR] ${err.stack || err.message}`); + + const statusCode = err.statusCode || 500; + const message = err.message || "Internal server error!"; + + res.status(statusCode).json({ message }); +} + +export default errorHandler; \ No newline at end of file diff --git a/mission_8/src/lib/prisma.ts b/mission_8/src/lib/prisma.ts new file mode 100644 index 000000000..b904402d2 --- /dev/null +++ b/mission_8/src/lib/prisma.ts @@ -0,0 +1,5 @@ +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +export default prisma; \ No newline at end of file diff --git a/mission_8/src/main.ts b/mission_8/src/main.ts new file mode 100644 index 000000000..6dd21b529 --- /dev/null +++ b/mission_8/src/main.ts @@ -0,0 +1,41 @@ +import path from "path"; + +import express from "express"; +import type { Request, Response, NextFunction } from "express"; +import cors from "cors"; +import cookieParser from "cookie-parser"; +import productRouter from "./router/productRouter.js"; +import articleRouter from "./router/articleRouter.js"; +import imageRouter from "./router/imageRouter.js"; +import userRouter from "./router/userRouter.js"; + +import errorHandler from "./handler/errorHandler.js"; + +const PORT = Number(process.env.PORT) || 3000; + +const app = express(); +app.use(express.json()); +app.use( + cors({ + methods: ["GET", "POST", "PUT", "PATCH", "DELETE"], + }) +); +app.use(cookieParser()); + +function logRequest(req: Request, _: Response, next: NextFunction) { + console.log(`[${req.method}] ${req.originalUrl}`); + next(); +} + +// middleware for logging all http request +app.use(logRequest); + +app.use("/products", productRouter); +app.use("/articles", articleRouter); +app.use("/upload", imageRouter); +app.use(userRouter); + +app.use(errorHandler); +app.use("/upload", express.static(path.resolve("uploads"))); + +app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); diff --git a/mission_8/src/middleware/auth.ts b/mission_8/src/middleware/auth.ts new file mode 100644 index 000000000..0d040e8c6 --- /dev/null +++ b/mission_8/src/middleware/auth.ts @@ -0,0 +1,173 @@ +import type { RequestHandler } from "express"; +import { expressjwt } from "express-jwt"; +import * as articleRepository from "../repository/articleRepository.js"; +import * as productRepository from "../repository/productRepository.js"; + +// 토큰 검증 +const verifyAccessToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + requestProperty: "user", +}); + +// refresh 토큰 검증 +const verifyRefreshToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + getToken: (req) => req.cookies.refreshToken, +}); + +// 게시글 유저 검증 +const verifyArticleAuth: RequestHandler = async (req, res, next) => { + // Get article id + const { id } = req.params; + + // Get article author's id + try { + const article = await articleRepository.getPost({ id: Number(id) }); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + return next(err); + } + + // Call next if valid user + if (req.user && req.user.userId === article.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 유저 검증 +const verifyProductAuth: RequestHandler = async (req, res, next) => { + // Get product id + const { id } = req.params; + + // Get product uploaders's id + try { + const product = await productRepository.getProduct({ id: Number(id) }); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + return next(err); + } + + // Call next if valid user + if (req.user && req.user.userId === product.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 게시글 존재 여부 확인 +const checkArticleExist: RequestHandler = async (req, res, next) => { + const { id } = req.params; + + try { + const article = await articleRepository.getPost({ id: Number(id) }); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + return next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 상품 존재 여부 확인 +const checkProductExist: RequestHandler = async (req, res, next) => { + const { id } = req.params; + + try { + const product = await productRepository.getProduct({ id: Number(id) }); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + return next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 게시글 댓글 유저 검증 +const verifyArticleCommentAuth: RequestHandler = async (req, res, next) => { + const { cid } = req.params; + + if (!cid) { + const err = new Error("Comment id is required"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await articleRepository.getComment({ cid: parseInt(cid) }); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + return next(err); + } + + if (req.user && req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 댓글 유저 검증 +const verifyProductCommentAuth: RequestHandler = async (req, res, next) => { + const { cid } = req.params; + + if (!cid) { + const err = new Error("Comment id is required"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productRepository.getComment({ cid: parseInt(cid) }); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + return next(err); + } + + if (req.user && req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +export default { + verifyAccessToken, + verifyRefreshToken, + verifyArticleAuth, + verifyProductAuth, + checkArticleExist, + checkProductExist, + verifyArticleCommentAuth, + verifyProductCommentAuth, +}; diff --git a/mission_8/src/middleware/index.ts b/mission_8/src/middleware/index.ts new file mode 100644 index 000000000..02584180c --- /dev/null +++ b/mission_8/src/middleware/index.ts @@ -0,0 +1 @@ +export * from './validator.js'; \ No newline at end of file diff --git a/mission_8/src/middleware/validator.ts b/mission_8/src/middleware/validator.ts new file mode 100644 index 000000000..48cf69245 --- /dev/null +++ b/mission_8/src/middleware/validator.ts @@ -0,0 +1,31 @@ +import type { RequestHandler } from "express"; + +// Verify required parameters are okay +const validateProduct: RequestHandler = async function (req, res, next) { + const { name, description, price, tags } = req.body; + + // validation logic (possible improvements with Zod library in the future) + if (!name || !description || !price || !tags) + return res.status(400).json({ message: "Missing required fields" }); + + if (isNaN(price)) + return res.status(400).json({ message: "Price must be a number" }); + + if (!Array.isArray(tags) || !tags.every((tag) => typeof tag === "string")) + return res.status(400).json({ message: "Tags must be an array of string" }); + + next(); +}; + +// Verify required parameters are okay +const validateArticle: RequestHandler = async function (req, res, next) { + const { title, content } = req.body; + + // validation + if (!title || !content) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + next(); +}; + +export { validateProduct, validateArticle }; diff --git a/mission_8/src/repository/articleRepository.ts b/mission_8/src/repository/articleRepository.ts new file mode 100644 index 000000000..a3a79f670 --- /dev/null +++ b/mission_8/src/repository/articleRepository.ts @@ -0,0 +1,177 @@ +import prisma from "../lib/prisma.js"; +import type { + CreatePostDTO, + GetPostsDTO, + GetPostDTO, + PatchPostDTO, + DeletePostDTO, + PostCommentDTO, + GetCommentsDTO, + GetCommentDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/article.js"; + +export async function createPost(data: CreatePostDTO) { + return await prisma.article.create({ + data, + }); +} + +export async function getPosts(data: GetPostsDTO) { + // search에 값이 있을 때만 where로 문자열 검색 + const where = data.search + ? { + OR: [ + { + title: { + contains: data.search, + mode: "insensitive" as const, + }, + }, + { + content: { + contains: data.search, + mode: "insensitive" as const, + }, + }, + ], + } + : {}; + + const result = await prisma.article.findMany({ + select: { + id: true, + title: true, + content: true, + createdAt: true, + }, + orderBy: { + createdAt: data.sort, + }, + where, + skip: data.offset * data.limit, + take: data.limit, + }); + + return result; +} + +export async function getPost(data: GetPostDTO) { + const result = await prisma.article.findUnique({ + where: { + id: data.id, + }, + }); + + return result; +} + +export async function patchPost(data: PatchPostDTO) { + const { id, ...filteredBody } = data; + + const result = await prisma.article.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deletePost(data: DeletePostDTO) { + const { id } = data; + + const result = await prisma.article.delete({ + where: { + id, + }, + }); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const { pid: articleId, name, content, userId } = data; + + const result = await prisma.comment.create({ + data: { + name, + content, + articleId, + userId, + }, + }); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const { pid, cursor, limit } = data; + + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + articleId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(data: GetCommentDTO) { + const { cid: id } = data; + + const result = await prisma.comment.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const { cid, name, content } = data; + + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const { cid } = data; + + const result = prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} diff --git a/mission_8/src/repository/index.ts b/mission_8/src/repository/index.ts new file mode 100644 index 000000000..a9bc4c15b --- /dev/null +++ b/mission_8/src/repository/index.ts @@ -0,0 +1 @@ +export * from './articleRepository.js'; \ No newline at end of file diff --git a/mission_8/src/repository/productRepository.ts b/mission_8/src/repository/productRepository.ts new file mode 100644 index 000000000..9d5dafb2f --- /dev/null +++ b/mission_8/src/repository/productRepository.ts @@ -0,0 +1,197 @@ +import prisma from "../lib/prisma.js"; +import type { + CreateProductDTO, + GetProductsDTO, + GetProductDTO, + PatchProductDTO, + DeleteProductDTO, + PostCommentDTO, + GetCommentsDTO, + GetCommentDTO, + PatchCommentDTO, + DeleteCommentDTO, + GetProductsByUserDTO, +} from "../types/product.js"; + +export async function createProduct(data: CreateProductDTO) { + const { userId, name, description, price, tags } = data; + + return await prisma.product.create({ + data: { + name, + description, + price, + tags, + userId, + }, + }); +} + +export async function getProducts(data: GetProductsDTO) { + const { offset, limit, sort, search } = data; + + const result = await prisma.product.findMany({ + select: { + id: true, + name: true, + price: true, + createdAt: true, + }, + orderBy: { + createdAt: sort, + }, + where: { + OR: [ + { + name: { + contains: search, + mode: "insensitive", + }, + }, + { + description: { + contains: search, + mode: "insensitive", + }, + }, + ], + }, + skip: offset * limit, + take: limit, + }); + + return result; +} + +export async function getProduct(data: GetProductDTO) { + const { id } = data; + const result = await prisma.product.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchProduct(data: PatchProductDTO) { + const { id, ...filteredBody } = data; + + const result = await prisma.product.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deleteProduct(data: DeleteProductDTO) { + const { id } = data; + + const result = await prisma.product.delete({ + where: { + id, + }, + }); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const { pid, userId, name, content } = data; + + const result = await prisma.comment.create({ + data: { + userId, + name, + content, + productId: pid, + }, + }); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const { pid, cursor, limit } = data; + + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + productId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(data: GetCommentDTO) { + const { cid: id } = data; + + const result = await prisma.comment.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const { cid, name, content } = data; + + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const { cid } = data; + + const result = await prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} + +export async function getProductsByUser(data: GetProductsByUserDTO) { + const { userId: id } = data; + + const products = await prisma.user.findUnique({ + where: { id }, + select: { + Product: true, + }, + }); + + return products; +} diff --git a/mission_8/src/repository/userRepository.ts b/mission_8/src/repository/userRepository.ts new file mode 100644 index 000000000..3ec40d685 --- /dev/null +++ b/mission_8/src/repository/userRepository.ts @@ -0,0 +1,61 @@ +import prisma from "../lib/prisma.js"; +import bcrypt from "bcrypt"; +import type { CreateUserDTO, UserInfoDTO, GetUserDTO } from "../types/user.js"; + +export async function createUser(user: CreateUserDTO) { + const hashedPassword = await hashPassword(user.password); + + const createdUser = await prisma.user.create({ + data: { + ...user, + password: hashedPassword, // This line overwrites user.password + }, + }); + + return createdUser; +} + +export async function findByEmail(email: string) { + const result = await prisma.user.findFirst({ + where: { + email, + }, + }); + + return result; +} + +export async function findById(id: number) { + const result = await prisma.user.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function hashPassword(password: string) { + const salt = await bcrypt.genSalt(10); + const hash = await bcrypt.hash(password, salt); + + return hash; +} + +export function filterSensitiveUserData(user: UserInfoDTO) { + const { password, refreshToken, ...rest } = user; + return rest; +} + +export async function updateUser(id: number, toUpdate: any) { + if (toUpdate.password) { + toUpdate.password = await hashPassword(toUpdate.password); + } + + const updatedUser = await prisma.user.update({ + where: { id }, + data: toUpdate, + }); + + return updatedUser; +} diff --git a/mission_8/src/router/articleRouter.ts b/mission_8/src/router/articleRouter.ts new file mode 100644 index 000000000..07b603722 --- /dev/null +++ b/mission_8/src/router/articleRouter.ts @@ -0,0 +1,73 @@ +import express from "express"; +import { validateArticle } from "../middleware/index.js"; +import auth from "../middleware/auth.js"; +import * as articleController from "../controller/articleController.js"; + +const router = express.Router(); + +router + .route("/") + + // Create a post + .post( + auth.verifyAccessToken, + validateArticle, + articleController.createPost + ) + + // Retrieve all articles + .get(articleController.getPosts); + +router + .route("/:id") + + // Get informations of a specific article + .get(articleController.getPost) + + // Modify a article property + .patch( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.patchPost + ) + + // Delete a particular article + .delete( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.deletePost + ); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkArticleExist, + articleController.postComment + ) + + // Inquery all comments + .get(auth.checkArticleExist, articleController.getComments); + +router + .route("/:id/comments/:cid") + + // Modify comment + .patch( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.patchComment + ) + + // Delete comment + .delete( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.deleteComment + ); + +export default router; diff --git a/mission_8/src/router/imageRouter.ts b/mission_8/src/router/imageRouter.ts new file mode 100644 index 000000000..e73d6d5fd --- /dev/null +++ b/mission_8/src/router/imageRouter.ts @@ -0,0 +1,19 @@ +import express from 'express'; +import multer from "multer"; + +const router = express.Router(); + +const upload = multer({ dest: 'uploads/' }); + +// 이미지 리사이징 기능 구현 예정 +router.post('/', upload.single('image'), async (req, res) => { + // console.log(req.file); + if (!req.file) { + return res.status(400).json({ message: 'No file uploaded' }); + } + + res.status(201).json({ message: 'Upload OK', filePath: req.file.path }); +}); + + +export default router; \ No newline at end of file diff --git a/mission_8/src/router/index.ts b/mission_8/src/router/index.ts new file mode 100644 index 000000000..921cc19ab --- /dev/null +++ b/mission_8/src/router/index.ts @@ -0,0 +1,3 @@ +export * from './articleRouter.js'; +export * from './productRouter.js'; +export * from './imageRouter.js'; \ No newline at end of file diff --git a/mission_8/src/router/productRouter.ts b/mission_8/src/router/productRouter.ts new file mode 100644 index 000000000..8b9a5813f --- /dev/null +++ b/mission_8/src/router/productRouter.ts @@ -0,0 +1,72 @@ +import express from "express"; +import type { Router } from "express"; +import { validateProduct } from "../middleware/validator.js"; +import auth from "../middleware/auth.js"; +import * as productController from "../controller/productController.js"; + +const router = express.Router(); + +router + .route("/") + + // Upload a new product + .post( + auth.verifyAccessToken, + validateProduct, + productController.createProduct + ) + + // Retrieve all products + .get(productController.getProducts); + +router + .route("/:id") + + // Get informations of a specific product + .get(productController.getProduct) + + // Modify a product property + .patch( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.patchProduct + ) + + // Delete a particular product + .delete( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.deleteProduct + ); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkProductExist, + productController.postComment + ) + + // Inquery all comments + .get(auth.checkProductExist, productController.getComments); + +router + .route("/:id/comments/:cid") + + .patch( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.patchComment + ) + + .delete( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.deleteComment + ); + +export default router; diff --git a/mission_8/src/router/userRouter.ts b/mission_8/src/router/userRouter.ts new file mode 100644 index 000000000..9ab871231 --- /dev/null +++ b/mission_8/src/router/userRouter.ts @@ -0,0 +1,44 @@ +import express from "express"; +import * as userController from "../controller/userController.js"; +import auth from "../middleware/auth.js"; + +const userRouter = express.Router(); + +userRouter + .route("/users") + + // Create user + .post(userController.createUser) + + // Get my(user) info + .get(auth.verifyAccessToken, userController.getMyInfo); + +// Update user info (nickname, email) +userRouter.patch( + "/users/info", + auth.verifyAccessToken, + userController.updateMyInfo +); + +// Update user password +userRouter.patch( + "/users/password", + auth.verifyAccessToken, + userController.updateMyPassword +); + +// Get product lists uploaded by user +userRouter.get( + "/users/products", + auth.verifyAccessToken, + userController.getMyProducts +); + +userRouter.post("/login", userController.getAccessToken); +userRouter.post( + "/login/refresh", + auth.verifyRefreshToken, + userController.getRefreshToken +); + +export default userRouter; diff --git a/mission_8/src/services/articleService.ts b/mission_8/src/services/articleService.ts new file mode 100644 index 000000000..f57c263dd --- /dev/null +++ b/mission_8/src/services/articleService.ts @@ -0,0 +1,65 @@ +import * as articleRepository from "../repository/articleRepository.js"; +import type { + CreatePostDTO, + GetPostsDTO, + GetPostDTO, + PatchPostDTO, + DeletePostDTO, + PostCommentDTO, + GetCommentsDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/article.js"; + +export async function createPost(data: CreatePostDTO) { + const result = await articleRepository.createPost(data); + + return result; +} + +export async function getPosts(data: GetPostsDTO) { + const result = await articleRepository.getPosts(data); + + return result; +} + +export async function getPost(id: GetPostDTO) { + const result = await articleRepository.getPost(id); + + return result; +} + +export async function patchPost(data: PatchPostDTO) { + const result = await articleRepository.patchPost(data); + + return result; +} + +export async function deletePost(id: DeletePostDTO) { + const result = await articleRepository.deletePost(id); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const result = await articleRepository.postComment(data); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const result = await articleRepository.getComments(data); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const result = await articleRepository.patchComment(data); + + return result; +} +export async function deleteComment(data: DeleteCommentDTO) { + const result = await articleRepository.deleteComment(data); + + return result; +} diff --git a/mission_8/src/services/index.ts b/mission_8/src/services/index.ts new file mode 100644 index 000000000..ce045fa9e --- /dev/null +++ b/mission_8/src/services/index.ts @@ -0,0 +1 @@ +export * from './articleService.js'; \ No newline at end of file diff --git a/mission_8/src/services/productService.ts b/mission_8/src/services/productService.ts new file mode 100644 index 000000000..918726321 --- /dev/null +++ b/mission_8/src/services/productService.ts @@ -0,0 +1,66 @@ +import * as productRepository from "../repository/productRepository.js"; +import type { + CreateProductDTO, + GetProductsDTO, + GetProductDTO, + PatchProductDTO, + DeleteProductDTO, + PostCommentDTO, + GetCommentsDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/product.js"; + +export async function createProduct(data: CreateProductDTO) { + const result = await productRepository.createProduct(data); + + return result; +} + +export async function getProducts(data: GetProductsDTO) { + const result = await productRepository.getProducts(data); + + return result; +} + +export async function getProduct(data: GetProductDTO) { + const result = await productRepository.getProduct(data); + + return result; +} + +export async function patchProduct(data: PatchProductDTO) { + const result = await productRepository.patchProduct(data); + + return result; +} + +export async function deleteProduct(data: DeleteProductDTO) { + const result = await productRepository.deleteProduct(data); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const result = await productRepository.postComment(data); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const result = await productRepository.getComments(data); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const result = await productRepository.patchComment(data); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const result = await productRepository.deleteComment(data); + + return result; +} diff --git a/mission_8/src/services/userService.ts b/mission_8/src/services/userService.ts new file mode 100644 index 000000000..2060ef614 --- /dev/null +++ b/mission_8/src/services/userService.ts @@ -0,0 +1,121 @@ +import * as userRepository from "../repository/userRepository.js"; +import * as productRepository from "../repository/productRepository.js"; +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; +import type { CreateUserDTO, GetUserDTO, UserInfoDTO } from "../types/user.js"; + +export async function createUser(user: CreateUserDTO) { + // 이미 가입된 이메일인지 검증 + const existedUser = await userRepository.findByEmail(user.email); + + if (existedUser) { + const err = new Error("User already exists"); + err.statusCode = 422; + throw err; + } + + const createdUser = await userRepository.createUser(user); + const createdUserId = await userRepository.filterSensitiveUserData( + createdUser + ).id; + + return createdUserId; +} + +export async function getUser({ email, password }: GetUserDTO) { + const user: UserInfoDTO | null = await userRepository.findByEmail(email); + + // If user is invalid + if (!user || !user.password) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + throw err; + } + + // Verifying password + await verifyPassword(password, user.password); + + // Return without password + return userRepository.filterSensitiveUserData(user); +} + +export async function getUserById(userId: number) { + const user = await userRepository.findById(userId); + + if (!user) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return userRepository.filterSensitiveUserData(user); +} + +async function verifyPassword(inputPassword: string, password: string) { + const isVerified = await bcrypt.compare(inputPassword, password); + + if (!isVerified) { + const err = new Error("Password is wrong"); + err.statusCode = 401; + throw err; + } +} + +export function createToken(user: UserInfoDTO, token: string | null = null) { + const payload = { userId: user.id }; + const options: jwt.SignOptions = { + expiresIn: token === "refresh" ? "2W" : "1H", + }; + + if (!process.env.JWT_SECRET) { + throw new Error("JWT_SECRET is not defined"); + } + + return jwt.sign(payload, process.env.JWT_SECRET, options); +} + +export async function refreshToken(userId: number, refreshToken: string) { + const user = await userRepository.findById(userId); + + if (!user || user.refreshToken !== refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 404; + throw err; + } + + const accessToken = createToken(user); + return accessToken; +} + +export async function updateUserInfo(userId: number, toUpdate: any) { + // 수정할 내용이 없다면 에러 처리 + if (Object.keys(toUpdate).length === 0) { + const err = new Error("No data to update"); + err.statusCode = 400; + throw err; + } + + const updatedUser = await userRepository.updateUser(userId, toUpdate); + + return userRepository.filterSensitiveUserData(updatedUser); +} + +export async function updateUserPassword(userId: number, newPassword: string) { + const hashedPassword = await userRepository.hashPassword(newPassword); + const user = await userRepository.updateUser(userId, { + password: hashedPassword, + }); + + return userRepository.filterSensitiveUserData(user); +} + +export async function getMyProducts(userId: number) { + const products = await productRepository.getProductsByUser({ userId }); + if (!products) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return products.Product; +} diff --git a/mission_8/src/types/article.ts b/mission_8/src/types/article.ts new file mode 100644 index 000000000..1398c1c95 --- /dev/null +++ b/mission_8/src/types/article.ts @@ -0,0 +1,54 @@ +export interface CreatePostDTO { + title: string; + content: string; + userId: number; +} + +export interface GetPostsDTO { + cursor?: number; + limit: number; + sort: "asc" | "desc"; + offset: number; + search?: string; +} + +export interface GetPostDTO { + id: number; +} + +export interface PatchPostDTO { + id: number; + title?: string; + content?: string; +} + +export interface DeletePostDTO { + id: number; +} + +export interface PostCommentDTO { + pid: number; + name: string; + content: string; + userId: number; +} + +export interface GetCommentsDTO { + pid: number; + cursor: number; + limit: number; +} + +export interface GetCommentDTO { + cid: number; +} + +export interface PatchCommentDTO { + cid: number; + name: string; + content: string; +} + +export interface DeleteCommentDTO { + cid: number; +} diff --git a/mission_8/src/types/auth.d.ts b/mission_8/src/types/auth.d.ts new file mode 100644 index 000000000..7353fbba8 --- /dev/null +++ b/mission_8/src/types/auth.d.ts @@ -0,0 +1,5 @@ +export interface JwtPayload { + userId: number; + iat?: number; + exp?: number; +} diff --git a/mission_8/src/types/express/index.d.ts b/mission_8/src/types/express/index.d.ts new file mode 100644 index 000000000..25cbc8d62 --- /dev/null +++ b/mission_8/src/types/express/index.d.ts @@ -0,0 +1,10 @@ +import "express"; +import type { JwtPayload } from "../auth.d.js"; + +declare module "express-serve-static-core" { + interface Request { + // user?: import("../types/auth").JwtPayload; + user?: JwtPayload; + auth?: JwtPayload; + } +} diff --git a/mission_8/src/types/global.ts b/mission_8/src/types/global.ts new file mode 100644 index 000000000..452228e41 --- /dev/null +++ b/mission_8/src/types/global.ts @@ -0,0 +1,5 @@ +declare global { + interface Error { + statusCode?: number; + } +} \ No newline at end of file diff --git a/mission_8/src/types/product.ts b/mission_8/src/types/product.ts new file mode 100644 index 000000000..52d1aa2f2 --- /dev/null +++ b/mission_8/src/types/product.ts @@ -0,0 +1,63 @@ +export interface CreateProductDTO { + userId: number; + name: string; + description: string; + price: number; + tags: string[]; +} + +export interface GetProductsDTO { + offset: number; + limit: number; + sort: "asc" | "desc"; + search: string; +} + +export interface GetProductDTO { + id: number; +} + +export interface PatchProductDTO { + id: number; + name?: string; + description?: string; + price?: number; + tags?: string[]; +} + +export interface DeleteProductDTO { + id: number; +} + +export interface PostCommentDTO { + pid: number; + userId: number; + content: string; + name: string; +} + +export interface GetCommentsDTO { + pid: number; + cursor: number | null; + limit: number; +} + +export interface GetCommentDTO { + cid: number; +} + +export interface PatchCommentDTO { + cid: number; + name: string; + content: string; +} + +export interface DeleteCommentDTO { + cid: number; +} + +export interface GetProductsByUserDTO { + userId: number; + offset?: number; + limit?: number; +} diff --git a/mission_8/src/types/user.ts b/mission_8/src/types/user.ts new file mode 100644 index 000000000..adf66d149 --- /dev/null +++ b/mission_8/src/types/user.ts @@ -0,0 +1,21 @@ +export interface CreateUserDTO { + email: string; + nickname: string; + password: string; +} + +export interface GetUserDTO { + email: string; + password: string; +} + +export interface UserInfoDTO { + password?: string; + email: string; + nickname: string; + image: string | null; + refreshToken?: string | null; + createdAt: Date; + updatedAt: Date; + id: number; +} diff --git a/mission_8/tsconfig.json b/mission_8/tsconfig.json new file mode 100644 index 000000000..cbfb43efb --- /dev/null +++ b/mission_8/tsconfig.json @@ -0,0 +1,48 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "moduleResolution": "nodenext", + "target": "es2022", + // "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, + + "esModuleInterop": true + }, + "include": ["src", "env.d.ts"] +} From 914afa1607de545545610e3060ccff4e7cbef877 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 15:12:18 +0900 Subject: [PATCH 069/130] chore: use "tsx watch " instead of ts-node and nodemon --- mission_8/nodemon.json | 5 - mission_8/package-lock.json | 970 ++++++++++++++++++------------------ mission_8/package.json | 8 +- 3 files changed, 482 insertions(+), 501 deletions(-) delete mode 100644 mission_8/nodemon.json diff --git a/mission_8/nodemon.json b/mission_8/nodemon.json deleted file mode 100644 index 647b3dd15..000000000 --- a/mission_8/nodemon.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "watch": ["src"], - "ext": "ts", - "exec": "ts-node ./src/main.ts" -} \ No newline at end of file diff --git a/mission_8/package-lock.json b/mission_8/package-lock.json index 0c9c8f9af..744239b51 100644 --- a/mission_8/package-lock.json +++ b/mission_8/package-lock.json @@ -18,7 +18,8 @@ "jsonwebtoken": "^9.0.2", "multer": "^2.0.2", "passport": "^0.7.0", - "passport-jwt": "^4.0.1" + "passport-jwt": "^4.0.1", + "tsx": "^4.20.6" }, "devDependencies": { "@types/bcrypt": "^6.0.0", @@ -28,9 +29,7 @@ "@types/express-jwt": "^6.0.4", "@types/multer": "^2.0.0", "@types/node": "^24.3.1", - "nodemon": "^3.1.10", "prisma": "^6.13.0", - "ts-node": "^10.9.2", "typescript": "^5.9.2" } }, @@ -59,45 +58,420 @@ "node": ">=6.9.0" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, "node_modules/@prisma/client": { @@ -192,34 +566,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/bcrypt": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", @@ -423,66 +769,12 @@ "node": ">= 0.6" } }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", "license": "MIT" }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, "node_modules/bcrypt": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", @@ -497,19 +789,6 @@ "node": ">= 18" } }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/body-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", @@ -530,30 +809,6 @@ "node": ">=18" } }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -670,13 +925,6 @@ "consola": "^3.2.3" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, "node_modules/concat-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", @@ -780,13 +1028,6 @@ "node": ">= 0.10" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" - }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", @@ -837,16 +1078,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/dotenv": { "version": "16.6.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", @@ -939,6 +1170,47 @@ "node": ">= 0.4" } }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1046,19 +1318,6 @@ "node": ">=8.0.0" } }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/finalhandler": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", @@ -1111,7 +1370,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -1168,6 +1426,18 @@ "node": ">= 0.4" } }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/giget": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", @@ -1186,19 +1456,6 @@ "giget": "dist/cli.mjs" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -1211,16 +1468,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -1295,13 +1542,6 @@ "node": ">=0.10.0" } }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true, - "license": "ISC" - }, "node_modules/index-to-position": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", @@ -1330,52 +1570,6 @@ "node": ">= 0.10" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -1491,13 +1685,6 @@ "devOptional": true, "license": "ISC" }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1549,19 +1736,6 @@ "node": ">= 0.6" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -1686,73 +1860,6 @@ "node-gyp-build-test": "build-test.js" } }, - "node_modules/nodemon": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", - "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^4", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "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/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/normalize-package-data": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", @@ -1768,16 +1875,6 @@ "node": "^16.14.0 || >=18.0.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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/nypm": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", @@ -1945,19 +2042,6 @@ "devOptional": true, "license": "ISC" }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/pkg-types": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz", @@ -2009,13 +2093,6 @@ "node": ">= 0.10" } }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true, - "license": "MIT" - }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", @@ -2149,6 +2226,15 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -2318,19 +2404,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -2393,19 +2466,6 @@ "safe-buffer": "~5.2.0" } }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/tinyexec": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", @@ -2413,19 +2473,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -2435,58 +2482,23 @@ "node": ">=0.6" } }, - "node_modules/touch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", - "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", - "dev": true, - "license": "ISC", - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", "license": "MIT", "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" }, "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" + "tsx": "dist/cli.mjs" }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" + "engines": { + "node": ">=18.0.0" }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } + "optionalDependencies": { + "fsevents": "~2.3.3" } }, "node_modules/type-fest": { @@ -2536,13 +2548,6 @@ "node": ">=14.17" } }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true, - "license": "MIT" - }, "node_modules/undici-types": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", @@ -2586,13 +2591,6 @@ "node": ">= 0.4.0" } }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -2627,16 +2625,6 @@ "engines": { "node": ">=0.4" } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } } } } diff --git a/mission_8/package.json b/mission_8/package.json index 2a9b1d8bd..1b51ffaa9 100644 --- a/mission_8/package.json +++ b/mission_8/package.json @@ -6,8 +6,7 @@ "test": "echo \"Error: no test specified\" && exit 1", "build": "tsc", "start": "NODE_ENV=production node dist/main.js", - "dev": "ts-node src/main.ts", - "dev:server": "nodemon" + "dev": "tsx watch src/main.ts" }, "keywords": [], "author": "", @@ -23,7 +22,8 @@ "jsonwebtoken": "^9.0.2", "multer": "^2.0.2", "passport": "^0.7.0", - "passport-jwt": "^4.0.1" + "passport-jwt": "^4.0.1", + "tsx": "^4.20.6" }, "devDependencies": { "@types/bcrypt": "^6.0.0", @@ -33,9 +33,7 @@ "@types/express-jwt": "^6.0.4", "@types/multer": "^2.0.0", "@types/node": "^24.3.1", - "nodemon": "^3.1.10", "prisma": "^6.13.0", - "ts-node": "^10.9.2", "typescript": "^5.9.2" }, "prisma": { From 19789a8ad28f5d0f905bdd0edc8d601b1ae22479 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 15:17:15 +0900 Subject: [PATCH 070/130] feat: add sample env file and update main.ts for environment variable support --- mission_8/.env.sample | 1 + mission_8/package-lock.json | 21 +++++++++++++++++---- mission_8/package.json | 1 + mission_8/src/main.ts | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 mission_8/.env.sample diff --git a/mission_8/.env.sample b/mission_8/.env.sample new file mode 100644 index 000000000..46cee22e9 --- /dev/null +++ b/mission_8/.env.sample @@ -0,0 +1 @@ +JWT_SECRET="your-super-secret-key" diff --git a/mission_8/package-lock.json b/mission_8/package-lock.json index 744239b51..7d7059c47 100644 --- a/mission_8/package-lock.json +++ b/mission_8/package-lock.json @@ -13,6 +13,7 @@ "bcrypt": "^6.0.0", "cookie-parser": "^1.4.7", "cors": "^2.8.5", + "dotenv": "^17.2.3", "express": "^5.1.0", "express-jwt": "^8.5.1", "jsonwebtoken": "^9.0.2", @@ -870,6 +871,19 @@ } } }, + "node_modules/c12/node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -1079,10 +1093,9 @@ "license": "MIT" }, "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "devOptional": true, + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "license": "BSD-2-Clause", "engines": { "node": ">=12" diff --git a/mission_8/package.json b/mission_8/package.json index 1b51ffaa9..52753fbc6 100644 --- a/mission_8/package.json +++ b/mission_8/package.json @@ -17,6 +17,7 @@ "bcrypt": "^6.0.0", "cookie-parser": "^1.4.7", "cors": "^2.8.5", + "dotenv": "^17.2.3", "express": "^5.1.0", "express-jwt": "^8.5.1", "jsonwebtoken": "^9.0.2", diff --git a/mission_8/src/main.ts b/mission_8/src/main.ts index 6dd21b529..714ec3154 100644 --- a/mission_8/src/main.ts +++ b/mission_8/src/main.ts @@ -1,3 +1,4 @@ +import "dotenv/config"; import path from "path"; import express from "express"; From f477dc3075cd00b9637e80b80970069118a54ba9 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 15:23:22 +0900 Subject: [PATCH 071/130] chore: update sample env --- mission_8/.env.sample | 1 + 1 file changed, 1 insertion(+) diff --git a/mission_8/.env.sample b/mission_8/.env.sample index 46cee22e9..b572e4204 100644 --- a/mission_8/.env.sample +++ b/mission_8/.env.sample @@ -1 +1,2 @@ JWT_SECRET="your-super-secret-key" +DATABASE_URL="postgresql://user:password@localhost:5432/mydatabase" \ No newline at end of file From 5593b58e354b452afadb8666ebe7cdac01032228 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 15:28:22 +0900 Subject: [PATCH 072/130] chore: add seed.ts --- mission_8/package.json | 2 +- mission_8/prisma/seed.ts | 122 ++++++++++++++++++++------------------- 2 files changed, 64 insertions(+), 60 deletions(-) diff --git a/mission_8/package.json b/mission_8/package.json index 52753fbc6..957cfabd5 100644 --- a/mission_8/package.json +++ b/mission_8/package.json @@ -38,7 +38,7 @@ "typescript": "^5.9.2" }, "prisma": { - "seed": "node prisma/seed.js" + "seed": "tsx prisma/seed.ts" }, "type": "module" } diff --git a/mission_8/prisma/seed.ts b/mission_8/prisma/seed.ts index 0d39f9c2f..7763e3fe5 100644 --- a/mission_8/prisma/seed.ts +++ b/mission_8/prisma/seed.ts @@ -1,87 +1,90 @@ -import { PrismaClient } from "@prisma/client"; +import { PrismaClient } from '@prisma/client'; +import bcrypt from 'bcrypt'; + +// initialize Prisma Client const prisma = new PrismaClient(); async function main() { - // ------------------------------ - // Product 더미 데이터 생성 - // ------------------------------ - const product1 = await prisma.product.create({ + // create two dummy users + const password = await bcrypt.hash('password123', 10); + const user1 = await prisma.user.create({ data: { - name: "게이밍 노트북", - description: "고성능 게이밍 및 작업용 노트북", - price: 1800000, - tags: ["노트북", "게이밍", "고성능",], - comments: { - create: [ - { name: "홍길동", content: "배틀그라운드도 잘 돌아가네요!" }, - { name: "김철수", content: "팬 소음이 조금 있지만 성능은 최고입니다." } - ] - } - } + email: 'user1@example.com', + nickname: 'Alice', + password, + image: 'https://i.pravatar.cc/150?u=user1@example.com', + }, }); - const product2 = await prisma.product.create({ + const user2 = await prisma.user.create({ data: { - name: "기계식 키보드", - description: "청축 기계식 키보드, 타건감이 뛰어남", - price: 120000, - tags: ["키보드","기계식","청축",], - comments: { - create: [ - { name: "이영희", content: "타이핑할 맛이 납니다." } - ] - } - } + email: 'user2@example.com', + nickname: 'Bob', + password, + image: 'https://i.pravatar.cc/150?u=user2@example.com', + }, }); - // ------------------------------ - // Article 더미 데이터 생성 - // ------------------------------ + // create two dummy articles const article1 = await prisma.article.create({ data: { - title: "게이밍 PC 조립 가이드", - content: "부품 선택부터 조립까지 단계별 설명...", - comments: { - create: [ - { name: "박영수", content: "이 글 덕분에 처음으로 PC를 조립했습니다." }, - { name: "최민지", content: "부품 추천이 매우 유용했습니다." } - ] - } - } + title: 'Prisma is the best ORM', + content: + 'Prisma makes database access easy with an intuitive data model and type-safety.', + userId: user1.id, + }, }); const article2 = await prisma.article.create({ data: { - title: "2025년 인기 프로그래밍 언어 TOP 10", - content: "올해 주목받는 프로그래밍 언어와 트렌드를 분석...", - comments: { - create: [ - { name: "장우진", content: "Rust가 상위권이라니 반갑네요!" } - ] - } - } + title: 'Getting started with Next.js', + content: + 'Next.js is a React framework for building full-stack web applications.', + userId: user2.id, + }, + }); + + // create two dummy products + const product1 = await prisma.product.create({ + data: { + name: 'Laptop', + description: 'A very powerful laptop for all your needs.', + price: 1200, + tags: ['electronics', 'computer'], + userId: user1.id, + }, + }); + + const product2 = await prisma.product.create({ + data: { + name: 'Coffee Mug', + description: 'A mug to hold your favorite beverage.', + price: 15, + tags: ['kitchen', 'home'], + userId: user2.id, + }, }); - // ------------------------------ - // Comment 모델 개별 생성 (Product/Article와 직접 연결) - // ------------------------------ + // create comments await prisma.comment.create({ data: { - name: "손흥민", - content: "이 제품은 가격 대비 성능이 좋습니다.", - productId: product1.id - } + name: 'Commenter1', + content: 'Great article!', + userId: user2.id, + articleId: article1.id, + }, }); await prisma.comment.create({ data: { - name: "유재석", - content: "기사 내용이 깔끔하게 잘 정리되어 있네요.", - articleId: article2.id - } + name: 'Commenter2', + content: 'I love this laptop!', + userId: user1.id, + productId: product1.id, + }, }); - console.log("시딩이 완료되었습니다."); + console.log({ user1, user2, article1, article2, product1, product2 }); } main() @@ -90,5 +93,6 @@ main() process.exit(1); }) .finally(async () => { + // close Prisma Client at the end await prisma.$disconnect(); }); From da2ac64beab90396cf2ef7ce2b1131d1bc9d7f51 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 16:43:27 +0900 Subject: [PATCH 073/130] feat: install socket.io package and create socket.ts file --- mission_8/package-lock.json | 273 +++++++++++++++++++++++++++++++++++- mission_8/package.json | 2 + mission_8/src/lib/socket.ts | 20 +++ 3 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 mission_8/src/lib/socket.ts diff --git a/mission_8/package-lock.json b/mission_8/package-lock.json index 7d7059c47..f16cea7a4 100644 --- a/mission_8/package-lock.json +++ b/mission_8/package-lock.json @@ -20,6 +20,7 @@ "multer": "^2.0.2", "passport": "^0.7.0", "passport-jwt": "^4.0.1", + "socket.io": "^4.8.1", "tsx": "^4.20.6" }, "devDependencies": { @@ -30,6 +31,7 @@ "@types/express-jwt": "^6.0.4", "@types/multer": "^2.0.0", "@types/node": "^24.3.1", + "@types/socket.io": "^3.0.1", "prisma": "^6.13.0", "typescript": "^5.9.2" } @@ -560,6 +562,12 @@ "@prisma/debug": "6.13.0" } }, + "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", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, "node_modules/@standard-schema/spec": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", @@ -612,7 +620,6 @@ "version": "2.8.19", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -757,6 +764,16 @@ "@types/send": "*" } }, + "node_modules/@types/socket.io": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-3.0.1.tgz", + "integrity": "sha512-XSma2FhVD78ymvoxYV4xGXrIH/0EKQ93rR+YR0Y+Kw1xbPzLDCip/UWSejZ08FpxYeYNci/PZPQS9anrvJRqMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "socket.io": "*" + } + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -776,6 +793,15 @@ "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", "license": "MIT" }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/bcrypt": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", @@ -1153,6 +1179,95 @@ "node": ">= 0.8" } }, + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -2417,6 +2532,141 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "license": "MIT", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -2630,6 +2880,27 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/mission_8/package.json b/mission_8/package.json index 957cfabd5..6718a6de4 100644 --- a/mission_8/package.json +++ b/mission_8/package.json @@ -24,6 +24,7 @@ "multer": "^2.0.2", "passport": "^0.7.0", "passport-jwt": "^4.0.1", + "socket.io": "^4.8.1", "tsx": "^4.20.6" }, "devDependencies": { @@ -34,6 +35,7 @@ "@types/express-jwt": "^6.0.4", "@types/multer": "^2.0.0", "@types/node": "^24.3.1", + "@types/socket.io": "^3.0.1", "prisma": "^6.13.0", "typescript": "^5.9.2" }, diff --git a/mission_8/src/lib/socket.ts b/mission_8/src/lib/socket.ts new file mode 100644 index 000000000..6b7195b05 --- /dev/null +++ b/mission_8/src/lib/socket.ts @@ -0,0 +1,20 @@ +import { Server } from 'socket.io'; + +let io: Server; + +export const initializeSocket = (server: any) => { + io = new Server(server, { + cors: { + origin: '*', // In a real application, restrict this to your frontend's URL + methods: ['GET', 'POST'], + }, + }); + return io; +}; + +export const getIO = () => { + if (!io) { + throw new Error('Socket.io not initialized!'); + } + return io; +}; From 8bb41ddc8658a94671927e2f092ebab773f18746 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 16:43:52 +0900 Subject: [PATCH 074/130] feat: add notification model and likedproduct model --- mission_8/prisma/schema.prisma | 86 ++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/mission_8/prisma/schema.prisma b/mission_8/prisma/schema.prisma index 0e23cea27..dd324ea23 100644 --- a/mission_8/prisma/schema.prisma +++ b/mission_8/prisma/schema.prisma @@ -15,27 +15,30 @@ datasource db { } model Product { - id Int @id @default(autoincrement()) - name String - description String - price Int - tags String[] - user User @relation(fields: [userId], references: [id]) - userId Int - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - comments Comment[] + id Int @id @default(autoincrement()) + name String + description String + price Int + tags String[] + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] + likedBy LikedProduct[] + notifications Notification[] } model Article { - id Int @id @default(autoincrement()) - title String - content String - user User @relation(fields: [userId], references: [id]) - userId Int - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - comments Comment[] + id Int @id @default(autoincrement()) + title String + content String + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] + notifications Notification[] } model Comment { @@ -53,15 +56,40 @@ model Comment { } model User { - id Int @id @default(autoincrement()) - email String @unique - nickname String - image String? - password String - refreshToken String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - Article Article[] - Product Product[] - Comment Comment[] + id Int @id @default(autoincrement()) + email String @unique + nickname String + image String? + password String + refreshToken String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Article Article[] + Product Product[] + Comment Comment[] + likedProducts LikedProduct[] + notifications Notification[] +} + +model LikedProduct { + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + product Product @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int + createdAt DateTime @default(now()) + + @@id([userId, productId]) +} + +model Notification { + id Int @id @default(autoincrement()) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + message String + read Boolean @default(false) + createdAt DateTime @default(now()) + article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) + articleId Int? + product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int? } From c7f2bd126ad82eb8c6c149567ea71dfc20c6b13e Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 16:47:46 +0900 Subject: [PATCH 075/130] feat: add notification service --- .../src/controller/notificationController.ts | 61 +++++++++++++++++ mission_8/src/main.ts | 2 + .../src/repository/notificationRepository.ts | 68 +++++++++++++++++++ mission_8/src/router/notificationRouter.ts | 35 ++++++++++ mission_8/src/services/notificationService.ts | 66 ++++++++++++++++++ mission_8/src/services/productService.ts | 31 ++++++++- 6 files changed, 260 insertions(+), 3 deletions(-) create mode 100644 mission_8/src/controller/notificationController.ts create mode 100644 mission_8/src/repository/notificationRepository.ts create mode 100644 mission_8/src/router/notificationRouter.ts create mode 100644 mission_8/src/services/notificationService.ts diff --git a/mission_8/src/controller/notificationController.ts b/mission_8/src/controller/notificationController.ts new file mode 100644 index 000000000..ae5a2b667 --- /dev/null +++ b/mission_8/src/controller/notificationController.ts @@ -0,0 +1,61 @@ +import type { Request, Response, NextFunction } from 'express'; +import notificationService from '../services/notificationService.js'; + +async function getNotifications( + req: Request, + res: Response, + next: NextFunction +) { + try { + const userId = req.user.userId; + const notifications = await notificationService.getUserNotifications(userId); + res.status(200).json(notifications); + } catch (error) { + next(error); + } +} + +async function getUnreadCount( + req: Request, + res: Response, + next: NextFunction +) { + try { + const userId = req.user.userId; + const count = await notificationService.getUnreadNotificationCount(userId); + res.status(200).json({ count }); + } catch (error) { + next(error); + } +} + +async function markAsRead(req: Request, res: Response, next: NextFunction) { + try { + const userId = req.user.userId; + const notificationId = parseInt(req.params.id, 10); + const notification = await notificationService.markNotificationAsRead( + notificationId, + userId + ); + res.status(200).json(notification); + } catch (error) { + next(error); + } +} + +async function markAllAsRead(req: Request, res: Response, next: NextFunction) { + try { + const userId = req.user.userId; + await notificationService.markAllNotificationsAsRead(userId); + res.status(204).send(); + } catch (error) { + next(error); + } +} + +export default { + getNotifications, + getUnreadCount, + markAsRead, + markAllAsRead, +}; diff --git a/mission_8/src/main.ts b/mission_8/src/main.ts index 714ec3154..9340e3563 100644 --- a/mission_8/src/main.ts +++ b/mission_8/src/main.ts @@ -8,6 +8,7 @@ import cookieParser from "cookie-parser"; import productRouter from "./router/productRouter.js"; import articleRouter from "./router/articleRouter.js"; import imageRouter from "./router/imageRouter.js"; +import notificationRouter from "./router/notificationRouter.js"; import userRouter from "./router/userRouter.js"; import errorHandler from "./handler/errorHandler.js"; @@ -34,6 +35,7 @@ app.use(logRequest); app.use("/products", productRouter); app.use("/articles", articleRouter); app.use("/upload", imageRouter); +app.use(notificationRouter); app.use(userRouter); app.use(errorHandler); diff --git a/mission_8/src/repository/notificationRepository.ts b/mission_8/src/repository/notificationRepository.ts new file mode 100644 index 000000000..d2f792c4c --- /dev/null +++ b/mission_8/src/repository/notificationRepository.ts @@ -0,0 +1,68 @@ +import prisma from '../lib/prisma.js'; + +async function create( + userId: number, + message: string, + articleId?: number, + productId?: number +) { + return prisma.notification.create({ + data: { + userId, + message, + articleId, + productId, + }, + }); +} + +async function findManyByUserId(userId: number) { + return prisma.notification.findMany({ + where: { userId }, + orderBy: { createdAt: 'desc' }, + }); +} + +async function getUnreadCount(userId: number) { + return prisma.notification.count({ + where: { + userId, + read: false, + }, + }); +} + +async function markAsRead(notificationId: number, userId: number) { + const notification = await prisma.notification.findUnique({ + where: { id: notificationId }, + }); + + if (!notification || notification.userId !== userId) { + throw new Error('인증되지 않음 접근 혹은 알림 ID가 존재하지 않음'); + } + + return prisma.notification.update({ + where: { id: notificationId }, + data: { read: true }, + }); +} + +async function markAllAsRead(userId: number) { + return prisma.notification.updateMany({ + where: { + userId, + read: false, + }, + data: { + read: true, + }, + }); +} + +export default { + create, + findManyByUserId, + getUnreadCount, + markAsRead, + markAllAsRead, +}; diff --git a/mission_8/src/router/notificationRouter.ts b/mission_8/src/router/notificationRouter.ts new file mode 100644 index 000000000..9266195ad --- /dev/null +++ b/mission_8/src/router/notificationRouter.ts @@ -0,0 +1,35 @@ +import { Router } from 'express'; +import notificationController from '../controller/notificationController.js'; +import auth from '../middleware/auth.js'; + +const router = Router(); + +// 모든 알림을 받아옴 +router.get( + '/notifications', + auth.verifyAccessToken, + notificationController.getNotifications +); + +// 알림 수를 받아옴 +router.get( + '/notifications/unread-count', + auth.verifyAccessToken, + notificationController.getUnreadCount +); + +// 알림을 읽음으로 표시 +router.patch( + '/notifications/:id/read', + auth.verifyAccessToken, + notificationController.markAsRead +); + +// 모든 알림을 읽음으로 표시 +router.patch( + '/notifications/read-all', + auth.verifyAccessToken, + notificationController.markAllAsRead +); + +export default router; diff --git a/mission_8/src/services/notificationService.ts b/mission_8/src/services/notificationService.ts new file mode 100644 index 000000000..6cac812fe --- /dev/null +++ b/mission_8/src/services/notificationService.ts @@ -0,0 +1,66 @@ +import notificationRepository from './notificationRepository.js'; +import { getIO } from '../lib/socket.js'; + +async function createNotification( + userId: number, + message: string, + articleId?: number, + productId?: number +) { + const newNotification = await notificationRepository.create( + userId, + message, + articleId, + productId + ); + + // 특정 유저ID에게 실시간 알림 전송 + const io = getIO(); + io.to(String(userId)).emit('new_notification', newNotification); + + // Also emit an unread count update + const unreadCount = await notificationRepository.getUnreadCount(userId); + io.to(String(userId)).emit('unread_count', unreadCount); + + return newNotification; +} + +async function getUserNotifications(userId: number) { + return notificationRepository.findManyByUserId(userId); +} + +async function getUnreadNotificationCount(userId: number) { + return notificationRepository.getUnreadCount(userId); +} + +async function markNotificationAsRead(notificationId: number, userId: number) { + const updatedNotification = await notificationRepository.markAsRead( + notificationId, + userId + ); + + // Emit an unread count update + const io = getIO(); + const unreadCount = await notificationRepository.getUnreadCount(userId); + io.to(String(userId)).emit('unread_count', unreadCount); + + return updatedNotification; +} + +async function markAllNotificationsAsRead(userId: number) { + const result = await notificationRepository.markAllAsRead(userId); + + // Emit an unread count update + const io = getIO(); + io.to(String(userId)).emit('unread_count', 0); + + return result; +} + +export default { + createNotification, + getUserNotifications, + getUnreadNotificationCount, + markNotificationAsRead, + markAllNotificationsAsRead, +}; diff --git a/mission_8/src/services/productService.ts b/mission_8/src/services/productService.ts index 918726321..fdcafcc7d 100644 --- a/mission_8/src/services/productService.ts +++ b/mission_8/src/services/productService.ts @@ -1,4 +1,5 @@ import * as productRepository from "../repository/productRepository.js"; +import notificationService from "./notificationService.js"; import type { CreateProductDTO, GetProductsDTO, @@ -30,9 +31,33 @@ export async function getProduct(data: GetProductDTO) { } export async function patchProduct(data: PatchProductDTO) { - const result = await productRepository.patchProduct(data); - - return result; + const { id, price: newPrice } = data; + + const originalProduct = await productRepository.getProduct({ id: Number(id) }); + if (!originalProduct) { + throw new Error("상품이 존재하지 않습니다."); + } + const oldPrice = originalProduct.price; + + const updatedProduct = await productRepository.patchProduct(data); + + if (newPrice !== undefined && newPrice !== oldPrice) { + const likedUsers = await productRepository.getLikedUsersByProductId( + Number(id) + ); + + for (const liked of likedUsers) { + const message = `'${originalProduct.name}' 상품의 가격이 ${oldPrice}원에서 ${newPrice}원으로 변경되었습니다.`; + await notificationService.createNotification( + liked.userId, + message, + undefined, + Number(id) + ); + } + } + + return updatedProduct; } export async function deleteProduct(data: DeleteProductDTO) { From 3e3ba5b8ac0e8c8233af3a77e638cca27ed75c25 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 16:51:00 +0900 Subject: [PATCH 076/130] feat: implement Socket.IO --- mission_8/src/main.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/mission_8/src/main.ts b/mission_8/src/main.ts index 9340e3563..3004deb3a 100644 --- a/mission_8/src/main.ts +++ b/mission_8/src/main.ts @@ -1,5 +1,6 @@ import "dotenv/config"; import path from "path"; +import http from "http"; import express from "express"; import type { Request, Response, NextFunction } from "express"; @@ -10,12 +11,31 @@ import articleRouter from "./router/articleRouter.js"; import imageRouter from "./router/imageRouter.js"; import notificationRouter from "./router/notificationRouter.js"; import userRouter from "./router/userRouter.js"; +import { initializeSocket } from "./lib/socket.js"; import errorHandler from "./handler/errorHandler.js"; const PORT = Number(process.env.PORT) || 3000; const app = express(); +const httpServer = http.createServer(app); + +// Socket.IO 초기화 +const io = initializeSocket(httpServer); + +io.on("connection", (socket) => { + console.log("A user connected:", socket.id); + + socket.on("join", (userId) => { + console.log(`User ${userId} joined room`); + socket.join(userId); + }); + + socket.on("disconnect", () => { + console.log("User disconnected:", socket.id); + }); +}); + app.use(express.json()); app.use( cors({ @@ -41,4 +61,4 @@ app.use(userRouter); app.use(errorHandler); app.use("/upload", express.static(path.resolve("uploads"))); -app.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); +httpServer.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); From 63e9497e91ed3b77db18ac3fe2b32375ca18c1cc Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 16:51:47 +0900 Subject: [PATCH 077/130] feat: implement like feature --- mission_8/src/controller/productController.ts | 19 ++++++++++ mission_8/src/repository/productRepository.ts | 38 +++++++++++++++++++ mission_8/src/router/productRouter.ts | 7 ++++ mission_8/src/services/productService.ts | 12 ++++++ 4 files changed, 76 insertions(+) diff --git a/mission_8/src/controller/productController.ts b/mission_8/src/controller/productController.ts index 6466d2548..f46bdd2c6 100644 --- a/mission_8/src/controller/productController.ts +++ b/mission_8/src/controller/productController.ts @@ -254,6 +254,24 @@ const deleteComment: RequestHandler = async function (req, res, next) { } }; +const toggleLike: RequestHandler = async function (req, res, next) { + try { + const userId = req.user.userId; + const productId = parseInt(req.params.id, 10); + + if (isNaN(productId)) { + const err = new Error("Invalid product ID"); + err.statusCode = 400; + return next(err); + } + + const result = await productService.toggleLike(userId, productId); + res.status(200).json(result); + } catch (error) { + next(error); + } +}; + export { createProduct, getProducts, @@ -264,4 +282,5 @@ export { getComments, patchComment, deleteComment, + toggleLike, }; diff --git a/mission_8/src/repository/productRepository.ts b/mission_8/src/repository/productRepository.ts index 9d5dafb2f..1a8ea9922 100644 --- a/mission_8/src/repository/productRepository.ts +++ b/mission_8/src/repository/productRepository.ts @@ -195,3 +195,41 @@ export async function getProductsByUser(data: GetProductsByUserDTO) { return products; } + +export async function findLike(userId: number, productId: number) { + return prisma.likedProduct.findUnique({ + where: { + userId_productId: { + userId, + productId, + }, + }, + }); +} + +export async function likeProduct(userId: number, productId: number) { + return prisma.likedProduct.create({ + data: { + userId, + productId, + }, + }); +} + +export async function unlikeProduct(userId: number, productId: number) { + return prisma.likedProduct.delete({ + where: { + userId_productId: { + userId, + productId, + }, + }, + }); +} + +export async function getLikedUsersByProductId(productId: number) { + return prisma.likedProduct.findMany({ + where: { productId }, + select: { userId: true }, + }); +} diff --git a/mission_8/src/router/productRouter.ts b/mission_8/src/router/productRouter.ts index 8b9a5813f..9383b6fa7 100644 --- a/mission_8/src/router/productRouter.ts +++ b/mission_8/src/router/productRouter.ts @@ -39,6 +39,13 @@ router productController.deleteProduct ); +// Like or unlike a product +router.post( + "/:id/like", + auth.verifyAccessToken, + productController.toggleLike +); + router .route("/:id/comments") diff --git a/mission_8/src/services/productService.ts b/mission_8/src/services/productService.ts index fdcafcc7d..0444fdb75 100644 --- a/mission_8/src/services/productService.ts +++ b/mission_8/src/services/productService.ts @@ -89,3 +89,15 @@ export async function deleteComment(data: DeleteCommentDTO) { return result; } + +export async function toggleLike(userId: number, productId: number) { + const existingLike = await productRepository.findLike(userId, productId); + + if (existingLike) { + await productRepository.unlikeProduct(userId, productId); + return { message: '관심 목록에서 삭제했습니다.' }; + } else { + await productRepository.likeProduct(userId, productId); + return { message: '관심 목록에 추가했습니다.' }; + } +} From 8a42e58f0f3655f61f3f67e827db6a9d595edb50 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 16:52:13 +0900 Subject: [PATCH 078/130] refactor: container export --- mission_8/src/controller/index.ts | 5 ++++- mission_8/src/repository/index.ts | 5 ++++- mission_8/src/router/index.ts | 4 +++- mission_8/src/services/index.ts | 5 ++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/mission_8/src/controller/index.ts b/mission_8/src/controller/index.ts index 1d9c8cc37..7cee66bc9 100644 --- a/mission_8/src/controller/index.ts +++ b/mission_8/src/controller/index.ts @@ -1 +1,4 @@ -export * from './articleController.js'; \ No newline at end of file +export * from './articleController.js'; +export * from './productController.js'; +export * from './userController.js'; +export * from './notificationController.js'; \ No newline at end of file diff --git a/mission_8/src/repository/index.ts b/mission_8/src/repository/index.ts index a9bc4c15b..cab62f42d 100644 --- a/mission_8/src/repository/index.ts +++ b/mission_8/src/repository/index.ts @@ -1 +1,4 @@ -export * from './articleRepository.js'; \ No newline at end of file +export * from './articleRepository.js'; +export * from './productRepository.js'; +export * from './userRepository.js'; +export * from './notificationRepository.js'; \ No newline at end of file diff --git a/mission_8/src/router/index.ts b/mission_8/src/router/index.ts index 921cc19ab..2ef8681ab 100644 --- a/mission_8/src/router/index.ts +++ b/mission_8/src/router/index.ts @@ -1,3 +1,5 @@ export * from './articleRouter.js'; export * from './productRouter.js'; -export * from './imageRouter.js'; \ No newline at end of file +export * from './imageRouter.js'; +export * from './userRouter.js'; +export * from './notificationRouter.js'; \ No newline at end of file diff --git a/mission_8/src/services/index.ts b/mission_8/src/services/index.ts index ce045fa9e..69a5a5e9d 100644 --- a/mission_8/src/services/index.ts +++ b/mission_8/src/services/index.ts @@ -1 +1,4 @@ -export * from './articleService.js'; \ No newline at end of file +export * from './articleService.js'; +export * from './productService.js'; +export * from './userService.js'; +export * from './notificationService.js'; \ No newline at end of file From 4fa13569a0068f7088dcb75174eaebded053914f Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 16:52:26 +0900 Subject: [PATCH 079/130] feat: new comment real-time notification --- mission_8/src/services/articleService.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/mission_8/src/services/articleService.ts b/mission_8/src/services/articleService.ts index f57c263dd..ca517325b 100644 --- a/mission_8/src/services/articleService.ts +++ b/mission_8/src/services/articleService.ts @@ -1,4 +1,5 @@ import * as articleRepository from "../repository/articleRepository.js"; +import notificationService from "./notificationService.js"; import type { CreatePostDTO, GetPostsDTO, @@ -42,9 +43,23 @@ export async function deletePost(id: DeletePostDTO) { } export async function postComment(data: PostCommentDTO) { - const result = await articleRepository.postComment(data); - - return result; + const newComment = await articleRepository.postComment(data); + + const article = await articleRepository.getPost({ id: data.aid }); + if (!article) { + return newComment; + } + + if (article.userId !== data.userId) { + const message = `내가 판매 신청한 매물에 새로운 댓글이 달렸습니다.`; + await notificationService.createNotification( + article.userId, + message, + article.id + ); + } + + return newComment; } export async function getComments(data: GetCommentsDTO) { From cc9b99918f803e15e00beed861c70461516b14fb Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 17:01:08 +0900 Subject: [PATCH 080/130] fix: syntax error --- mission_8/src/controller/productController.ts | 12 ++++++++++++ mission_8/src/repository/notificationRepository.ts | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/mission_8/src/controller/productController.ts b/mission_8/src/controller/productController.ts index f46bdd2c6..c8bb444a7 100644 --- a/mission_8/src/controller/productController.ts +++ b/mission_8/src/controller/productController.ts @@ -255,6 +255,18 @@ const deleteComment: RequestHandler = async function (req, res, next) { }; const toggleLike: RequestHandler = async function (req, res, next) { + if (!req.user) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!req.params.id) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + try { const userId = req.user.userId; const productId = parseInt(req.params.id, 10); diff --git a/mission_8/src/repository/notificationRepository.ts b/mission_8/src/repository/notificationRepository.ts index d2f792c4c..88829f4fe 100644 --- a/mission_8/src/repository/notificationRepository.ts +++ b/mission_8/src/repository/notificationRepository.ts @@ -10,8 +10,8 @@ async function create( data: { userId, message, - articleId, - productId, + articleId: articleId ?? null, + productId: productId ?? null, }, }); } From f8a376cbc3c6b3be8631452e7b2abefad032c715 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 17:02:06 +0900 Subject: [PATCH 081/130] fix: import error --- mission_8/src/services/notificationService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission_8/src/services/notificationService.ts b/mission_8/src/services/notificationService.ts index 6cac812fe..51d3cad92 100644 --- a/mission_8/src/services/notificationService.ts +++ b/mission_8/src/services/notificationService.ts @@ -1,4 +1,4 @@ -import notificationRepository from './notificationRepository.js'; +import notificationRepository from '../repository/notificationRepository.js'; import { getIO } from '../lib/socket.js'; async function createNotification( From a751da33fb2a382fa90ea125c7e1544355743745 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 18:14:59 +0900 Subject: [PATCH 082/130] test: test html --- mission_8/test-client.html | 79 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 mission_8/test-client.html diff --git a/mission_8/test-client.html b/mission_8/test-client.html new file mode 100644 index 000000000..865a0d6b5 --- /dev/null +++ b/mission_8/test-client.html @@ -0,0 +1,79 @@ + + + + + + Socket.IO Test Client + + + +

Socket.IO 알림 테스트 클라이언트

+ + +
+

서버 로그가 여기에 표시됩니다...

+
+ + + + + From 24aa80ce56447a8a7bfa51da6929bf313a85da29 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 18:53:30 +0900 Subject: [PATCH 083/130] fix: misspell --- mission_8/src/services/articleService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission_8/src/services/articleService.ts b/mission_8/src/services/articleService.ts index ca517325b..caaca1aac 100644 --- a/mission_8/src/services/articleService.ts +++ b/mission_8/src/services/articleService.ts @@ -45,7 +45,7 @@ export async function deletePost(id: DeletePostDTO) { export async function postComment(data: PostCommentDTO) { const newComment = await articleRepository.postComment(data); - const article = await articleRepository.getPost({ id: data.aid }); + const article = await articleRepository.getPost({ id: data.pid }); if (!article) { return newComment; } From 22e739352f74eda7909475b7502e7548189b4a03 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 9 Nov 2025 18:53:36 +0900 Subject: [PATCH 084/130] test: testpage --- mission_8/test-client.html | 111 +++++++++++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 24 deletions(-) diff --git a/mission_8/test-client.html b/mission_8/test-client.html index 865a0d6b5..a7bc85c49 100644 --- a/mission_8/test-client.html +++ b/mission_8/test-client.html @@ -5,20 +5,41 @@ Socket.IO Test Client -

Socket.IO 알림 테스트 클라이언트

- - -
-

서버 로그가 여기에 표시됩니다...

+
+

1. 실시간 알림 수신 설정

+ + + +

2. 알림 트리거 (댓글 작성)

+ + + + +
+ +
+

서버 로그

+
+

서버 로그가 여기에 표시됩니다...

+
@@ -26,12 +47,23 @@

Socket.IO 알림 테스트 클라이언트

const log = document.getElementById('log'); const userIdInput = document.getElementById('userIdInput'); const joinBtn = document.getElementById('joinBtn'); + const accessTokenInput = document.getElementById('accessTokenInput'); + const articleIdInput = document.getElementById('articleIdInput'); + const commentInput = document.getElementById('commentInput'); + const postCommentBtn = document.getElementById('postCommentBtn'); let socket; - function logEvent(eventName, data) { + function logEvent(eventName, data, className) { const eventDiv = document.createElement('div'); eventDiv.classList.add('event'); - eventDiv.innerHTML = `[${eventName}]: ${JSON.stringify(data, null, 2)}`; + + const nameSpan = document.createElement('span'); + nameSpan.classList.add('event-name', className || eventName.toLowerCase()); + nameSpan.textContent = `[${eventName}]`; + + eventDiv.appendChild(nameSpan); + eventDiv.append(`: ${JSON.stringify(data, null, 2)}`); + log.appendChild(eventDiv); log.scrollTop = log.scrollHeight; } @@ -49,31 +81,62 @@

Socket.IO 알림 테스트 클라이언트

log.innerHTML = ''; // Clear log - // 서버 주소는 실제 실행 환경에 맞게 변경해야 할 수 있습니다. socket = io('http://localhost:3000'); socket.on('connect', () => { - logEvent('connect', { id: socket.id }); - - // 연결 성공 후, 'join' 이벤트를 보내 사용자 ID 기반의 room에 참가 + logEvent('CONNECT', { id: socket.id }); socket.emit('join', userId); - logEvent('join', `Sent join request for userId: ${userId}`); + logEvent('JOIN', `Sent join request for userId: ${userId}`); }); socket.on('disconnect', () => { - logEvent('disconnect', 'Connection lost'); + logEvent('DISCONNECT', 'Connection lost'); }); - // 서버로부터 오는 새로운 알림을 리스닝 socket.on('new_notification', (data) => { - logEvent('new_notification', data); + logEvent('NEW_NOTIFICATION', data); }); - // 안 읽은 알림 개수 업데이트를 리스닝 socket.on('unread_count', (data) => { - logEvent('unread_count', data); + logEvent('UNREAD_COUNT', data); }); }); + + postCommentBtn.addEventListener('click', async () => { + const token = accessTokenInput.value; + const articleId = articleIdInput.value; + const comment = commentInput.value; + + if (!token || !articleId || !comment) { + alert('Access Token, 게시글 ID, 댓글 내용을 모두 입력하세요.'); + return; + } + + const url = `http://localhost:3000/articles/${articleId}/comments`; + const payload = { content: comment }; + + logEvent('API_REQUEST', { method: 'POST', url, body: payload }); + + try { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: JSON.stringify(payload) + }); + + const responseData = await response.json(); + logEvent('API_RESPONSE', { status: response.status, ok: response.ok, data: responseData }); + + if (response.ok) { + commentInput.value = ''; + } + } catch (error) { + logEvent('API_RESPONSE', { status: 'Error', error: error.message }); + } + }); - + \ No newline at end of file From fa972cedd8b09cc6f78df49dc453f0b8590bf776 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 16 Nov 2025 17:57:12 +0900 Subject: [PATCH 085/130] feat: copy mission_8 to mission_9 --- mission_9/.env.sample | 2 + mission_9/.gitignore | 10 + mission_9/env.d.ts | 13 + mission_9/package-lock.json | 2914 +++++++++++++++++ mission_9/package.json | 46 + mission_9/prisma/schema.prisma | 95 + mission_9/prisma/seed.ts | 98 + mission_9/src/container.ts | 1 + mission_9/src/controller/articleController.ts | 253 ++ mission_9/src/controller/index.ts | 4 + .../src/controller/notificationController.ts | 61 + mission_9/src/controller/productController.ts | 298 ++ mission_9/src/controller/userController.ts | 156 + mission_9/src/handler/errorHandler.ts | 12 + mission_9/src/lib/prisma.ts | 5 + mission_9/src/lib/socket.ts | 20 + mission_9/src/main.ts | 64 + mission_9/src/middleware/auth.ts | 173 + mission_9/src/middleware/index.ts | 1 + mission_9/src/middleware/validator.ts | 31 + mission_9/src/repository/articleRepository.ts | 177 + mission_9/src/repository/index.ts | 4 + .../src/repository/notificationRepository.ts | 68 + mission_9/src/repository/productRepository.ts | 235 ++ mission_9/src/repository/userRepository.ts | 61 + mission_9/src/router/articleRouter.ts | 73 + mission_9/src/router/imageRouter.ts | 19 + mission_9/src/router/index.ts | 5 + mission_9/src/router/notificationRouter.ts | 35 + mission_9/src/router/productRouter.ts | 79 + mission_9/src/router/userRouter.ts | 44 + mission_9/src/services/articleService.ts | 80 + mission_9/src/services/index.ts | 4 + mission_9/src/services/notificationService.ts | 66 + mission_9/src/services/productService.ts | 103 + mission_9/src/services/userService.ts | 121 + mission_9/src/types/article.ts | 54 + mission_9/src/types/auth.d.ts | 5 + mission_9/src/types/express/index.d.ts | 10 + mission_9/src/types/global.ts | 5 + mission_9/src/types/product.ts | 63 + mission_9/src/types/user.ts | 21 + mission_9/test-client.html | 142 + mission_9/tsconfig.json | 48 + 44 files changed, 5779 insertions(+) create mode 100644 mission_9/.env.sample create mode 100644 mission_9/.gitignore create mode 100644 mission_9/env.d.ts create mode 100644 mission_9/package-lock.json create mode 100644 mission_9/package.json create mode 100644 mission_9/prisma/schema.prisma create mode 100644 mission_9/prisma/seed.ts create mode 100644 mission_9/src/container.ts create mode 100644 mission_9/src/controller/articleController.ts create mode 100644 mission_9/src/controller/index.ts create mode 100644 mission_9/src/controller/notificationController.ts create mode 100644 mission_9/src/controller/productController.ts create mode 100644 mission_9/src/controller/userController.ts create mode 100644 mission_9/src/handler/errorHandler.ts create mode 100644 mission_9/src/lib/prisma.ts create mode 100644 mission_9/src/lib/socket.ts create mode 100644 mission_9/src/main.ts create mode 100644 mission_9/src/middleware/auth.ts create mode 100644 mission_9/src/middleware/index.ts create mode 100644 mission_9/src/middleware/validator.ts create mode 100644 mission_9/src/repository/articleRepository.ts create mode 100644 mission_9/src/repository/index.ts create mode 100644 mission_9/src/repository/notificationRepository.ts create mode 100644 mission_9/src/repository/productRepository.ts create mode 100644 mission_9/src/repository/userRepository.ts create mode 100644 mission_9/src/router/articleRouter.ts create mode 100644 mission_9/src/router/imageRouter.ts create mode 100644 mission_9/src/router/index.ts create mode 100644 mission_9/src/router/notificationRouter.ts create mode 100644 mission_9/src/router/productRouter.ts create mode 100644 mission_9/src/router/userRouter.ts create mode 100644 mission_9/src/services/articleService.ts create mode 100644 mission_9/src/services/index.ts create mode 100644 mission_9/src/services/notificationService.ts create mode 100644 mission_9/src/services/productService.ts create mode 100644 mission_9/src/services/userService.ts create mode 100644 mission_9/src/types/article.ts create mode 100644 mission_9/src/types/auth.d.ts create mode 100644 mission_9/src/types/express/index.d.ts create mode 100644 mission_9/src/types/global.ts create mode 100644 mission_9/src/types/product.ts create mode 100644 mission_9/src/types/user.ts create mode 100644 mission_9/test-client.html create mode 100644 mission_9/tsconfig.json diff --git a/mission_9/.env.sample b/mission_9/.env.sample new file mode 100644 index 000000000..b572e4204 --- /dev/null +++ b/mission_9/.env.sample @@ -0,0 +1,2 @@ +JWT_SECRET="your-super-secret-key" +DATABASE_URL="postgresql://user:password@localhost:5432/mydatabase" \ No newline at end of file diff --git a/mission_9/.gitignore b/mission_9/.gitignore new file mode 100644 index 000000000..d58e9d958 --- /dev/null +++ b/mission_9/.gitignore @@ -0,0 +1,10 @@ +node_modules +/dist + +# Keep environment variables out of version control +.env + +/generated/prisma +/prisma/migrations + +todo.list \ No newline at end of file diff --git a/mission_9/env.d.ts b/mission_9/env.d.ts new file mode 100644 index 000000000..f4b3b91de --- /dev/null +++ b/mission_9/env.d.ts @@ -0,0 +1,13 @@ +declare namespace NodeJS { + interface ProcessEnv { + NODE_ENV: "development" | "production"; + PORT?: string; + DATABASE_URL?: string; + /* DB_HOST: string; + DB_PORT: string; + DB_USERNAME: string; + DB_PASSWORD: string; + DB_NAME: string; */ + JWT_SECRET: string; + } +} diff --git a/mission_9/package-lock.json b/mission_9/package-lock.json new file mode 100644 index 000000000..f16cea7a4 --- /dev/null +++ b/mission_9/package-lock.json @@ -0,0 +1,2914 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sprint_mission_3", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "dotenv": "^17.2.3", + "express": "^5.1.0", + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "socket.io": "^4.8.1", + "tsx": "^4.20.6" + }, + "devDependencies": { + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.9", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.3", + "@types/express-jwt": "^6.0.4", + "@types/multer": "^2.0.0", + "@types/node": "^24.3.1", + "@types/socket.io": "^3.0.1", + "prisma": "^6.13.0", + "typescript": "^5.9.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@prisma/client": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.13.0.tgz", + "integrity": "sha512-8m2+I3dQovkV8CkDMluiwEV1TxV9EXdT6xaCz39O6jYw7mkf5gwfmi+cL4LJsEPwz5tG7sreBwkRpEMJedGYUQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.13.0.tgz", + "integrity": "sha512-OYMM+pcrvj/NqNWCGESSxVG3O7kX6oWuGyvufTUNnDw740KIQvNyA4v0eILgkpuwsKIDU36beZCkUtIt0naTog==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.16.12", + "read-package-up": "11.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.13.0.tgz", + "integrity": "sha512-um+9pfKJW0ihmM83id9FXGi5qEbVJ0Vxi1Gm0xpYsjwUBnw6s2LdPBbrsG9QXRX46K4CLWCTNvskXBup4i9hlw==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.13.0.tgz", + "integrity": "sha512-D+1B79LFvtWA0KTt8ALekQ6A/glB9w10ETknH5Y9g1k2NYYQOQy93ffiuqLn3Pl6IPJG3EsK/YMROKEaq8KBrA==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/fetch-engine": "6.13.0", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd.tgz", + "integrity": "sha512-MpPyKSzBX7P/ZY9odp9TSegnS/yH3CSbchQE9f0yBg3l2QyN59I6vGXcoYcqKC9VTniS1s18AMmhyr1OWavjHg==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.13.0.tgz", + "integrity": "sha512-grmmq+4FeFKmaaytA8Ozc2+Tf3BC8xn/DVJos6LL022mfRlMZYjT3hZM0/xG7+5fO95zFG9CkDUs0m1S2rXs5Q==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.13.0.tgz", + "integrity": "sha512-Nii2pX50fY4QKKxQwm7/vvqT6Ku8yYJLZAFX4e2vzHwRdMqjugcOG5hOSLjxqoXb0cvOspV70TOhMzrw8kqAnw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0" + } + }, + "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", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie-parser": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.9.tgz", + "integrity": "sha512-tGZiZ2Gtc4m3wIdLkZ8mkj1T6CEHb35+VApbL2T14Dew8HA7c+04dmKqsKRNC+8RJPm16JEK0tFSwdZqubfc4g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", + "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-jwt": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-6.0.4.tgz", + "integrity": "sha512-I53KRQ9D0eTA6hVCN9S73iOeprKS3JNWK+Cp2mDPB6uOIkTVpkgSkX394kHQzb5cd0U02I0adRmsMxHk+zX8tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/express-unless": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz", + "integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express-unless": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.3.tgz", + "integrity": "sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/multer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", + "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/node": { + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/socket.io": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-3.0.1.tgz", + "integrity": "sha512-XSma2FhVD78ymvoxYV4xGXrIH/0EKQ93rR+YR0Y+Kw1xbPzLDCip/UWSejZ08FpxYeYNci/PZPQS9anrvJRqMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "socket.io": "*" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/c12/node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.16.12", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", + "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-jwt": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.5.1.tgz", + "integrity": "sha512-Dv6QjDLpR2jmdb8M6XQXiCcpEom7mK8TOqnr0/TngDKsG2DHVkO8+XnVxkJVN7BuS1I3OrGw6N8j5DaaGgkDRQ==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "^9", + "express-unless": "^2.1.3", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express-unless": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz", + "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==", + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/index-to-position": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", + "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", + "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "mkdirp": "^0.5.6", + "object-assign": "^4.1.1", + "type-is": "^1.6.18", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", + "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "devOptional": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/nypm": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", + "integrity": "sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.2.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/pkg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz", + "integrity": "sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/prisma": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.13.0.tgz", + "integrity": "sha512-dfzORf0AbcEyyzxuv2lEwG8g+WRGF/qDQTpHf/6JoHsyF5MyzCEZwClVaEmw3WXcobgadosOboKUgQU0kFs9kw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.13.0", + "@prisma/engines": "6.13.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "license": "MIT", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "devOptional": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "devOptional": true, + "license": "CC0-1.0" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "devOptional": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/mission_9/package.json b/mission_9/package.json new file mode 100644 index 000000000..6718a6de4 --- /dev/null +++ b/mission_9/package.json @@ -0,0 +1,46 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc", + "start": "NODE_ENV=production node dist/main.js", + "dev": "tsx watch src/main.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "dotenv": "^17.2.3", + "express": "^5.1.0", + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "socket.io": "^4.8.1", + "tsx": "^4.20.6" + }, + "devDependencies": { + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.9", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.3", + "@types/express-jwt": "^6.0.4", + "@types/multer": "^2.0.0", + "@types/node": "^24.3.1", + "@types/socket.io": "^3.0.1", + "prisma": "^6.13.0", + "typescript": "^5.9.2" + }, + "prisma": { + "seed": "tsx prisma/seed.ts" + }, + "type": "module" +} diff --git a/mission_9/prisma/schema.prisma b/mission_9/prisma/schema.prisma new file mode 100644 index 000000000..dd324ea23 --- /dev/null +++ b/mission_9/prisma/schema.prisma @@ -0,0 +1,95 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" + // output = "../generated/prisma" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model Product { + id Int @id @default(autoincrement()) + name String + description String + price Int + tags String[] + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] + likedBy LikedProduct[] + notifications Notification[] +} + +model Article { + id Int @id @default(autoincrement()) + title String + content String + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] + notifications Notification[] +} + +model Comment { + id Int @id @default(autoincrement()) + name String + content String + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int? + Article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) + articleId Int? +} + +model User { + id Int @id @default(autoincrement()) + email String @unique + nickname String + image String? + password String + refreshToken String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Article Article[] + Product Product[] + Comment Comment[] + likedProducts LikedProduct[] + notifications Notification[] +} + +model LikedProduct { + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + product Product @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int + createdAt DateTime @default(now()) + + @@id([userId, productId]) +} + +model Notification { + id Int @id @default(autoincrement()) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + message String + read Boolean @default(false) + createdAt DateTime @default(now()) + article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) + articleId Int? + product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int? +} diff --git a/mission_9/prisma/seed.ts b/mission_9/prisma/seed.ts new file mode 100644 index 000000000..7763e3fe5 --- /dev/null +++ b/mission_9/prisma/seed.ts @@ -0,0 +1,98 @@ +import { PrismaClient } from '@prisma/client'; +import bcrypt from 'bcrypt'; + +// initialize Prisma Client +const prisma = new PrismaClient(); + +async function main() { + // create two dummy users + const password = await bcrypt.hash('password123', 10); + const user1 = await prisma.user.create({ + data: { + email: 'user1@example.com', + nickname: 'Alice', + password, + image: 'https://i.pravatar.cc/150?u=user1@example.com', + }, + }); + + const user2 = await prisma.user.create({ + data: { + email: 'user2@example.com', + nickname: 'Bob', + password, + image: 'https://i.pravatar.cc/150?u=user2@example.com', + }, + }); + + // create two dummy articles + const article1 = await prisma.article.create({ + data: { + title: 'Prisma is the best ORM', + content: + 'Prisma makes database access easy with an intuitive data model and type-safety.', + userId: user1.id, + }, + }); + + const article2 = await prisma.article.create({ + data: { + title: 'Getting started with Next.js', + content: + 'Next.js is a React framework for building full-stack web applications.', + userId: user2.id, + }, + }); + + // create two dummy products + const product1 = await prisma.product.create({ + data: { + name: 'Laptop', + description: 'A very powerful laptop for all your needs.', + price: 1200, + tags: ['electronics', 'computer'], + userId: user1.id, + }, + }); + + const product2 = await prisma.product.create({ + data: { + name: 'Coffee Mug', + description: 'A mug to hold your favorite beverage.', + price: 15, + tags: ['kitchen', 'home'], + userId: user2.id, + }, + }); + + // create comments + await prisma.comment.create({ + data: { + name: 'Commenter1', + content: 'Great article!', + userId: user2.id, + articleId: article1.id, + }, + }); + + await prisma.comment.create({ + data: { + name: 'Commenter2', + content: 'I love this laptop!', + userId: user1.id, + productId: product1.id, + }, + }); + + console.log({ user1, user2, article1, article2, product1, product2 }); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + // close Prisma Client at the end + await prisma.$disconnect(); + }); diff --git a/mission_9/src/container.ts b/mission_9/src/container.ts new file mode 100644 index 000000000..ba0183f59 --- /dev/null +++ b/mission_9/src/container.ts @@ -0,0 +1 @@ +import prisma from './lib/prisma.js'; \ No newline at end of file diff --git a/mission_9/src/controller/articleController.ts b/mission_9/src/controller/articleController.ts new file mode 100644 index 000000000..2f603387d --- /dev/null +++ b/mission_9/src/controller/articleController.ts @@ -0,0 +1,253 @@ +import * as articleService from "../services/articleService.js"; +import type { RequestHandler } from "express"; + +const createPost: RequestHandler = async function (req, res, next) { + const { title, content } = req.body; + + const userId = req.user ? req.user.userId : null; + if (userId === null) { + const err = new Error("Access token is missing or invalid"); + err.statusCode = 401; + return next(err); + } + + if (!title || !content) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + const article = await articleService.createPost({ userId, title, content }); + res.status(201).json(article); + } catch (err) { + next(err); + } +}; + +const getPosts: RequestHandler = async function (req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search } = req.query; + + try { + const articles = await articleService.getPosts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search: String(search), + }); + + if (articles) res.status(200).json(articles); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with given parameters`; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const getPost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const article = await articleService.getPost({ id: Number(id) }); + + if (article) res.status(200).json(article); + else { + const err = new Error(`Cannot find article with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchPost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + // Columns in model Article + const articleCols = ["title", "content"]; + + // ? + const filteredBody = Object.entries(req.body) + .filter(([key]) => articleCols.includes(key)) + .reduce>((obj, [key, value]) => { + obj[key] = value; + return obj; + }, {}); + + try { + const article = await articleService.patchPost({ + id: Number(id), + ...filteredBody, + }); + + if (article) res.status(200).json(article); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const deletePost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const deleted = await articleService.deletePost({ id: Number(id) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const postComment: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Access token is missing or invalid"); + err.statusCode = 401; + return next(err); + } + + if (!name || !content || !pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + return next(err); + } + + try { + const comment = await articleService.postComment({ + userId, + name, + content, + pid: Number(pid), + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +}; + +const getComments: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + const comments = await articleService.getComments({ + pid: Number(pid), + cursor: Number(cursor), + limit: Number(limit), + }); + + if (comments) + res.status(200).json({ + comments, + nextCursor: + comments.length === Number(limit) ? comments.at(-1)?.id : null, // llm + }); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comments with id ${pid}`; + return next(err); + } +}; + +const patchComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id' and 'cid'"; + return next(err); + } + + const { name, content } = req.body; + if (!name || !content) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid SQL Parameters"; + return next(err); + } + + const comment = await articleService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comment with ID ${pid}`; + return next(err); + } +}; + +const deleteComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await articleService.deleteComment({ cid: Number(cid) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find any comment with ID ${cid}`); + err.statusCode = 404; + return next(err); + } +}; + +export { + createPost, + getPosts, + getPost, + patchPost, + deletePost, + postComment, + getComments, + patchComment, + deleteComment, +}; diff --git a/mission_9/src/controller/index.ts b/mission_9/src/controller/index.ts new file mode 100644 index 000000000..7cee66bc9 --- /dev/null +++ b/mission_9/src/controller/index.ts @@ -0,0 +1,4 @@ +export * from './articleController.js'; +export * from './productController.js'; +export * from './userController.js'; +export * from './notificationController.js'; \ No newline at end of file diff --git a/mission_9/src/controller/notificationController.ts b/mission_9/src/controller/notificationController.ts new file mode 100644 index 000000000..ae5a2b667 --- /dev/null +++ b/mission_9/src/controller/notificationController.ts @@ -0,0 +1,61 @@ +import type { Request, Response, NextFunction } from 'express'; +import notificationService from '../services/notificationService.js'; + +async function getNotifications( + req: Request, + res: Response, + next: NextFunction +) { + try { + const userId = req.user.userId; + const notifications = await notificationService.getUserNotifications(userId); + res.status(200).json(notifications); + } catch (error) { + next(error); + } +} + +async function getUnreadCount( + req: Request, + res: Response, + next: NextFunction +) { + try { + const userId = req.user.userId; + const count = await notificationService.getUnreadNotificationCount(userId); + res.status(200).json({ count }); + } catch (error) { + next(error); + } +} + +async function markAsRead(req: Request, res: Response, next: NextFunction) { + try { + const userId = req.user.userId; + const notificationId = parseInt(req.params.id, 10); + const notification = await notificationService.markNotificationAsRead( + notificationId, + userId + ); + res.status(200).json(notification); + } catch (error) { + next(error); + } +} + +async function markAllAsRead(req: Request, res: Response, next: NextFunction) { + try { + const userId = req.user.userId; + await notificationService.markAllNotificationsAsRead(userId); + res.status(204).send(); + } catch (error) { + next(error); + } +} + +export default { + getNotifications, + getUnreadCount, + markAsRead, + markAllAsRead, +}; diff --git a/mission_9/src/controller/productController.ts b/mission_9/src/controller/productController.ts new file mode 100644 index 000000000..c8bb444a7 --- /dev/null +++ b/mission_9/src/controller/productController.ts @@ -0,0 +1,298 @@ +import * as productService from "../services/productService.js"; +import type { RequestHandler } from "express"; + +const createProduct: RequestHandler = async function createProduct( + req, + res, + next +) { + // destructuring field data from request body + const { name, description, price, tags } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!name || !description || !price || !tags) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Product table + const product = await productService.createProduct({ + userId, + name, + description, + price, + tags, + }); + + res.status(201).json(product); + } catch (err) { + next(err); + } +}; + +const getProducts: RequestHandler = async function (req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search = "" } = req.query; + + try { + const products = await productService.getProducts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search: String(search), + }); + + if (products) res.status(200).json(products); + else { + const err = new Error("Cannot find products"); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const getProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const product = await productService.getProduct({ id }); + + if (product) res.status(200).json(product); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + // Attributes in model Product + const productCols = ["name", "description", "price", "tags"]; + + // Possible improvement? + const filteredBody = Object.entries(req.body) + .filter(([key]) => productCols.includes(key)) + .reduce>((obj, [key, value]) => { + obj[key] = value; + return obj; + }, {}); + + try { + const product = await productService.patchProduct({ id, ...filteredBody }); + + if (product) res.status(200).json(product); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find product with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const deleteProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const deleted = await productService.deleteProduct({ id }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const postComment: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + // validation + if (!name || !content || !pid) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Comment table + const comment = await productService.postComment({ + userId, + pid: Number(pid), + name, + content, + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +}; + +const getComments: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + try { + const comments = await productService.getComments({ + pid: Number(pid), + cursor: cursor ? Number(cursor) : null, + limit: Number(limit), + }); + + // Cursor pagination + const nextCursor = + comments.length > 0 ? comments[comments.length - 1] : null; + + if (comments) + res.status(200).json({ + comments, + nextCursor, + }); + else { + const err = new Error(`Cannot find any comments`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + const { name, content } = req.body; + + if (!pid || !cid || !name || !content) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(`Cannot find any comment with ID ${cid}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const deleteComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await productService.deleteComment({ cid: Number(cid) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${pid}`); + err.statusCode = 404; + return next(err); + } +}; + +const toggleLike: RequestHandler = async function (req, res, next) { + if (!req.user) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!req.params.id) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const userId = req.user.userId; + const productId = parseInt(req.params.id, 10); + + if (isNaN(productId)) { + const err = new Error("Invalid product ID"); + err.statusCode = 400; + return next(err); + } + + const result = await productService.toggleLike(userId, productId); + res.status(200).json(result); + } catch (error) { + next(error); + } +}; + +export { + createProduct, + getProducts, + getProduct, + patchProduct, + deleteProduct, + postComment, + getComments, + patchComment, + deleteComment, + toggleLike, +}; diff --git a/mission_9/src/controller/userController.ts b/mission_9/src/controller/userController.ts new file mode 100644 index 000000000..397fed1ad --- /dev/null +++ b/mission_9/src/controller/userController.ts @@ -0,0 +1,156 @@ +import * as userService from "../services/userService.js"; +import type { RequestHandler } from "express"; + +// for Creating user +const createUser: RequestHandler = async function (req, res, next) { + const { email, nickname, password } = req.body; + + if (!email || !nickname || !password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const userId = await userService.createUser({ email, nickname, password }); + + return res.status(200).json(userId); + } catch (err) { + next(err); + } +}; + +// for Login +const getAccessToken: RequestHandler = async function (req, res, next) { + const { email, password } = req.body; + + if (!email || !password) { + const err = new Error("Email or password is wrong"); + err.statusCode = 404; + return next(err); + } + + try { + const user = await userService.getUser(req.body); + const accessToken = userService.createToken(user); + const refreshToken = userService.createToken(user, "refresh"); + await userService.updateUserInfo(user.id, { refreshToken }); + res.cookie("refreshToken", refreshToken, { + httpOnly: true, + sameSite: "none", + secure: true, + }); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +}; + +const getMyInfo: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + + if (!userId) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + try { + const user = await userService.getUserById(userId); + + return res.status(200).json(user); + } catch (err) { + next(err); + } +}; + +const updateMyInfo: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + const { email, nickname } = req.body; + + if (!email && !nickname || userId === null) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const updatedUser = await userService.updateUserInfo(userId, req.body); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +}; + +const updateMyPassword: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + const { password } = req.body; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const updatedUser = await userService.updateUserPassword(userId, password); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +}; + +const getMyProducts: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + try { + const products = await userService.getMyProducts(userId); + + return res.status(200).json(products); + } catch (err) { + next(err); + } +}; + +const getRefreshToken: RequestHandler = async function (req, res, next) { + const userId = req.auth ? req.auth.userId : null; + const refreshToken = req.cookies.refreshToken; + + if (!refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + next(err); + } + + try { + const accessToken = await userService.refreshToken(Number(userId), refreshToken); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +}; + +export { + createUser, + getAccessToken, + getMyInfo, + updateMyInfo, + updateMyPassword, + getMyProducts, + getRefreshToken, +}; diff --git a/mission_9/src/handler/errorHandler.ts b/mission_9/src/handler/errorHandler.ts new file mode 100644 index 000000000..ed4c35489 --- /dev/null +++ b/mission_9/src/handler/errorHandler.ts @@ -0,0 +1,12 @@ +import type { ErrorRequestHandler } from "express"; + +const errorHandler: ErrorRequestHandler = function (err, req, res, next) { + console.error(`[ERROR] ${err.stack || err.message}`); + + const statusCode = err.statusCode || 500; + const message = err.message || "Internal server error!"; + + res.status(statusCode).json({ message }); +} + +export default errorHandler; \ No newline at end of file diff --git a/mission_9/src/lib/prisma.ts b/mission_9/src/lib/prisma.ts new file mode 100644 index 000000000..b904402d2 --- /dev/null +++ b/mission_9/src/lib/prisma.ts @@ -0,0 +1,5 @@ +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +export default prisma; \ No newline at end of file diff --git a/mission_9/src/lib/socket.ts b/mission_9/src/lib/socket.ts new file mode 100644 index 000000000..6b7195b05 --- /dev/null +++ b/mission_9/src/lib/socket.ts @@ -0,0 +1,20 @@ +import { Server } from 'socket.io'; + +let io: Server; + +export const initializeSocket = (server: any) => { + io = new Server(server, { + cors: { + origin: '*', // In a real application, restrict this to your frontend's URL + methods: ['GET', 'POST'], + }, + }); + return io; +}; + +export const getIO = () => { + if (!io) { + throw new Error('Socket.io not initialized!'); + } + return io; +}; diff --git a/mission_9/src/main.ts b/mission_9/src/main.ts new file mode 100644 index 000000000..3004deb3a --- /dev/null +++ b/mission_9/src/main.ts @@ -0,0 +1,64 @@ +import "dotenv/config"; +import path from "path"; +import http from "http"; + +import express from "express"; +import type { Request, Response, NextFunction } from "express"; +import cors from "cors"; +import cookieParser from "cookie-parser"; +import productRouter from "./router/productRouter.js"; +import articleRouter from "./router/articleRouter.js"; +import imageRouter from "./router/imageRouter.js"; +import notificationRouter from "./router/notificationRouter.js"; +import userRouter from "./router/userRouter.js"; +import { initializeSocket } from "./lib/socket.js"; + +import errorHandler from "./handler/errorHandler.js"; + +const PORT = Number(process.env.PORT) || 3000; + +const app = express(); +const httpServer = http.createServer(app); + +// Socket.IO 초기화 +const io = initializeSocket(httpServer); + +io.on("connection", (socket) => { + console.log("A user connected:", socket.id); + + socket.on("join", (userId) => { + console.log(`User ${userId} joined room`); + socket.join(userId); + }); + + socket.on("disconnect", () => { + console.log("User disconnected:", socket.id); + }); +}); + +app.use(express.json()); +app.use( + cors({ + methods: ["GET", "POST", "PUT", "PATCH", "DELETE"], + }) +); +app.use(cookieParser()); + +function logRequest(req: Request, _: Response, next: NextFunction) { + console.log(`[${req.method}] ${req.originalUrl}`); + next(); +} + +// middleware for logging all http request +app.use(logRequest); + +app.use("/products", productRouter); +app.use("/articles", articleRouter); +app.use("/upload", imageRouter); +app.use(notificationRouter); +app.use(userRouter); + +app.use(errorHandler); +app.use("/upload", express.static(path.resolve("uploads"))); + +httpServer.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); diff --git a/mission_9/src/middleware/auth.ts b/mission_9/src/middleware/auth.ts new file mode 100644 index 000000000..0d040e8c6 --- /dev/null +++ b/mission_9/src/middleware/auth.ts @@ -0,0 +1,173 @@ +import type { RequestHandler } from "express"; +import { expressjwt } from "express-jwt"; +import * as articleRepository from "../repository/articleRepository.js"; +import * as productRepository from "../repository/productRepository.js"; + +// 토큰 검증 +const verifyAccessToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + requestProperty: "user", +}); + +// refresh 토큰 검증 +const verifyRefreshToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + getToken: (req) => req.cookies.refreshToken, +}); + +// 게시글 유저 검증 +const verifyArticleAuth: RequestHandler = async (req, res, next) => { + // Get article id + const { id } = req.params; + + // Get article author's id + try { + const article = await articleRepository.getPost({ id: Number(id) }); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + return next(err); + } + + // Call next if valid user + if (req.user && req.user.userId === article.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 유저 검증 +const verifyProductAuth: RequestHandler = async (req, res, next) => { + // Get product id + const { id } = req.params; + + // Get product uploaders's id + try { + const product = await productRepository.getProduct({ id: Number(id) }); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + return next(err); + } + + // Call next if valid user + if (req.user && req.user.userId === product.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 게시글 존재 여부 확인 +const checkArticleExist: RequestHandler = async (req, res, next) => { + const { id } = req.params; + + try { + const article = await articleRepository.getPost({ id: Number(id) }); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + return next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 상품 존재 여부 확인 +const checkProductExist: RequestHandler = async (req, res, next) => { + const { id } = req.params; + + try { + const product = await productRepository.getProduct({ id: Number(id) }); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + return next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 게시글 댓글 유저 검증 +const verifyArticleCommentAuth: RequestHandler = async (req, res, next) => { + const { cid } = req.params; + + if (!cid) { + const err = new Error("Comment id is required"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await articleRepository.getComment({ cid: parseInt(cid) }); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + return next(err); + } + + if (req.user && req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 댓글 유저 검증 +const verifyProductCommentAuth: RequestHandler = async (req, res, next) => { + const { cid } = req.params; + + if (!cid) { + const err = new Error("Comment id is required"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productRepository.getComment({ cid: parseInt(cid) }); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + return next(err); + } + + if (req.user && req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +export default { + verifyAccessToken, + verifyRefreshToken, + verifyArticleAuth, + verifyProductAuth, + checkArticleExist, + checkProductExist, + verifyArticleCommentAuth, + verifyProductCommentAuth, +}; diff --git a/mission_9/src/middleware/index.ts b/mission_9/src/middleware/index.ts new file mode 100644 index 000000000..02584180c --- /dev/null +++ b/mission_9/src/middleware/index.ts @@ -0,0 +1 @@ +export * from './validator.js'; \ No newline at end of file diff --git a/mission_9/src/middleware/validator.ts b/mission_9/src/middleware/validator.ts new file mode 100644 index 000000000..48cf69245 --- /dev/null +++ b/mission_9/src/middleware/validator.ts @@ -0,0 +1,31 @@ +import type { RequestHandler } from "express"; + +// Verify required parameters are okay +const validateProduct: RequestHandler = async function (req, res, next) { + const { name, description, price, tags } = req.body; + + // validation logic (possible improvements with Zod library in the future) + if (!name || !description || !price || !tags) + return res.status(400).json({ message: "Missing required fields" }); + + if (isNaN(price)) + return res.status(400).json({ message: "Price must be a number" }); + + if (!Array.isArray(tags) || !tags.every((tag) => typeof tag === "string")) + return res.status(400).json({ message: "Tags must be an array of string" }); + + next(); +}; + +// Verify required parameters are okay +const validateArticle: RequestHandler = async function (req, res, next) { + const { title, content } = req.body; + + // validation + if (!title || !content) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + next(); +}; + +export { validateProduct, validateArticle }; diff --git a/mission_9/src/repository/articleRepository.ts b/mission_9/src/repository/articleRepository.ts new file mode 100644 index 000000000..a3a79f670 --- /dev/null +++ b/mission_9/src/repository/articleRepository.ts @@ -0,0 +1,177 @@ +import prisma from "../lib/prisma.js"; +import type { + CreatePostDTO, + GetPostsDTO, + GetPostDTO, + PatchPostDTO, + DeletePostDTO, + PostCommentDTO, + GetCommentsDTO, + GetCommentDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/article.js"; + +export async function createPost(data: CreatePostDTO) { + return await prisma.article.create({ + data, + }); +} + +export async function getPosts(data: GetPostsDTO) { + // search에 값이 있을 때만 where로 문자열 검색 + const where = data.search + ? { + OR: [ + { + title: { + contains: data.search, + mode: "insensitive" as const, + }, + }, + { + content: { + contains: data.search, + mode: "insensitive" as const, + }, + }, + ], + } + : {}; + + const result = await prisma.article.findMany({ + select: { + id: true, + title: true, + content: true, + createdAt: true, + }, + orderBy: { + createdAt: data.sort, + }, + where, + skip: data.offset * data.limit, + take: data.limit, + }); + + return result; +} + +export async function getPost(data: GetPostDTO) { + const result = await prisma.article.findUnique({ + where: { + id: data.id, + }, + }); + + return result; +} + +export async function patchPost(data: PatchPostDTO) { + const { id, ...filteredBody } = data; + + const result = await prisma.article.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deletePost(data: DeletePostDTO) { + const { id } = data; + + const result = await prisma.article.delete({ + where: { + id, + }, + }); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const { pid: articleId, name, content, userId } = data; + + const result = await prisma.comment.create({ + data: { + name, + content, + articleId, + userId, + }, + }); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const { pid, cursor, limit } = data; + + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + articleId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(data: GetCommentDTO) { + const { cid: id } = data; + + const result = await prisma.comment.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const { cid, name, content } = data; + + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const { cid } = data; + + const result = prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} diff --git a/mission_9/src/repository/index.ts b/mission_9/src/repository/index.ts new file mode 100644 index 000000000..cab62f42d --- /dev/null +++ b/mission_9/src/repository/index.ts @@ -0,0 +1,4 @@ +export * from './articleRepository.js'; +export * from './productRepository.js'; +export * from './userRepository.js'; +export * from './notificationRepository.js'; \ No newline at end of file diff --git a/mission_9/src/repository/notificationRepository.ts b/mission_9/src/repository/notificationRepository.ts new file mode 100644 index 000000000..88829f4fe --- /dev/null +++ b/mission_9/src/repository/notificationRepository.ts @@ -0,0 +1,68 @@ +import prisma from '../lib/prisma.js'; + +async function create( + userId: number, + message: string, + articleId?: number, + productId?: number +) { + return prisma.notification.create({ + data: { + userId, + message, + articleId: articleId ?? null, + productId: productId ?? null, + }, + }); +} + +async function findManyByUserId(userId: number) { + return prisma.notification.findMany({ + where: { userId }, + orderBy: { createdAt: 'desc' }, + }); +} + +async function getUnreadCount(userId: number) { + return prisma.notification.count({ + where: { + userId, + read: false, + }, + }); +} + +async function markAsRead(notificationId: number, userId: number) { + const notification = await prisma.notification.findUnique({ + where: { id: notificationId }, + }); + + if (!notification || notification.userId !== userId) { + throw new Error('인증되지 않음 접근 혹은 알림 ID가 존재하지 않음'); + } + + return prisma.notification.update({ + where: { id: notificationId }, + data: { read: true }, + }); +} + +async function markAllAsRead(userId: number) { + return prisma.notification.updateMany({ + where: { + userId, + read: false, + }, + data: { + read: true, + }, + }); +} + +export default { + create, + findManyByUserId, + getUnreadCount, + markAsRead, + markAllAsRead, +}; diff --git a/mission_9/src/repository/productRepository.ts b/mission_9/src/repository/productRepository.ts new file mode 100644 index 000000000..1a8ea9922 --- /dev/null +++ b/mission_9/src/repository/productRepository.ts @@ -0,0 +1,235 @@ +import prisma from "../lib/prisma.js"; +import type { + CreateProductDTO, + GetProductsDTO, + GetProductDTO, + PatchProductDTO, + DeleteProductDTO, + PostCommentDTO, + GetCommentsDTO, + GetCommentDTO, + PatchCommentDTO, + DeleteCommentDTO, + GetProductsByUserDTO, +} from "../types/product.js"; + +export async function createProduct(data: CreateProductDTO) { + const { userId, name, description, price, tags } = data; + + return await prisma.product.create({ + data: { + name, + description, + price, + tags, + userId, + }, + }); +} + +export async function getProducts(data: GetProductsDTO) { + const { offset, limit, sort, search } = data; + + const result = await prisma.product.findMany({ + select: { + id: true, + name: true, + price: true, + createdAt: true, + }, + orderBy: { + createdAt: sort, + }, + where: { + OR: [ + { + name: { + contains: search, + mode: "insensitive", + }, + }, + { + description: { + contains: search, + mode: "insensitive", + }, + }, + ], + }, + skip: offset * limit, + take: limit, + }); + + return result; +} + +export async function getProduct(data: GetProductDTO) { + const { id } = data; + const result = await prisma.product.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchProduct(data: PatchProductDTO) { + const { id, ...filteredBody } = data; + + const result = await prisma.product.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deleteProduct(data: DeleteProductDTO) { + const { id } = data; + + const result = await prisma.product.delete({ + where: { + id, + }, + }); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const { pid, userId, name, content } = data; + + const result = await prisma.comment.create({ + data: { + userId, + name, + content, + productId: pid, + }, + }); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const { pid, cursor, limit } = data; + + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + productId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(data: GetCommentDTO) { + const { cid: id } = data; + + const result = await prisma.comment.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const { cid, name, content } = data; + + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const { cid } = data; + + const result = await prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} + +export async function getProductsByUser(data: GetProductsByUserDTO) { + const { userId: id } = data; + + const products = await prisma.user.findUnique({ + where: { id }, + select: { + Product: true, + }, + }); + + return products; +} + +export async function findLike(userId: number, productId: number) { + return prisma.likedProduct.findUnique({ + where: { + userId_productId: { + userId, + productId, + }, + }, + }); +} + +export async function likeProduct(userId: number, productId: number) { + return prisma.likedProduct.create({ + data: { + userId, + productId, + }, + }); +} + +export async function unlikeProduct(userId: number, productId: number) { + return prisma.likedProduct.delete({ + where: { + userId_productId: { + userId, + productId, + }, + }, + }); +} + +export async function getLikedUsersByProductId(productId: number) { + return prisma.likedProduct.findMany({ + where: { productId }, + select: { userId: true }, + }); +} diff --git a/mission_9/src/repository/userRepository.ts b/mission_9/src/repository/userRepository.ts new file mode 100644 index 000000000..3ec40d685 --- /dev/null +++ b/mission_9/src/repository/userRepository.ts @@ -0,0 +1,61 @@ +import prisma from "../lib/prisma.js"; +import bcrypt from "bcrypt"; +import type { CreateUserDTO, UserInfoDTO, GetUserDTO } from "../types/user.js"; + +export async function createUser(user: CreateUserDTO) { + const hashedPassword = await hashPassword(user.password); + + const createdUser = await prisma.user.create({ + data: { + ...user, + password: hashedPassword, // This line overwrites user.password + }, + }); + + return createdUser; +} + +export async function findByEmail(email: string) { + const result = await prisma.user.findFirst({ + where: { + email, + }, + }); + + return result; +} + +export async function findById(id: number) { + const result = await prisma.user.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function hashPassword(password: string) { + const salt = await bcrypt.genSalt(10); + const hash = await bcrypt.hash(password, salt); + + return hash; +} + +export function filterSensitiveUserData(user: UserInfoDTO) { + const { password, refreshToken, ...rest } = user; + return rest; +} + +export async function updateUser(id: number, toUpdate: any) { + if (toUpdate.password) { + toUpdate.password = await hashPassword(toUpdate.password); + } + + const updatedUser = await prisma.user.update({ + where: { id }, + data: toUpdate, + }); + + return updatedUser; +} diff --git a/mission_9/src/router/articleRouter.ts b/mission_9/src/router/articleRouter.ts new file mode 100644 index 000000000..07b603722 --- /dev/null +++ b/mission_9/src/router/articleRouter.ts @@ -0,0 +1,73 @@ +import express from "express"; +import { validateArticle } from "../middleware/index.js"; +import auth from "../middleware/auth.js"; +import * as articleController from "../controller/articleController.js"; + +const router = express.Router(); + +router + .route("/") + + // Create a post + .post( + auth.verifyAccessToken, + validateArticle, + articleController.createPost + ) + + // Retrieve all articles + .get(articleController.getPosts); + +router + .route("/:id") + + // Get informations of a specific article + .get(articleController.getPost) + + // Modify a article property + .patch( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.patchPost + ) + + // Delete a particular article + .delete( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.deletePost + ); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkArticleExist, + articleController.postComment + ) + + // Inquery all comments + .get(auth.checkArticleExist, articleController.getComments); + +router + .route("/:id/comments/:cid") + + // Modify comment + .patch( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.patchComment + ) + + // Delete comment + .delete( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.deleteComment + ); + +export default router; diff --git a/mission_9/src/router/imageRouter.ts b/mission_9/src/router/imageRouter.ts new file mode 100644 index 000000000..e73d6d5fd --- /dev/null +++ b/mission_9/src/router/imageRouter.ts @@ -0,0 +1,19 @@ +import express from 'express'; +import multer from "multer"; + +const router = express.Router(); + +const upload = multer({ dest: 'uploads/' }); + +// 이미지 리사이징 기능 구현 예정 +router.post('/', upload.single('image'), async (req, res) => { + // console.log(req.file); + if (!req.file) { + return res.status(400).json({ message: 'No file uploaded' }); + } + + res.status(201).json({ message: 'Upload OK', filePath: req.file.path }); +}); + + +export default router; \ No newline at end of file diff --git a/mission_9/src/router/index.ts b/mission_9/src/router/index.ts new file mode 100644 index 000000000..2ef8681ab --- /dev/null +++ b/mission_9/src/router/index.ts @@ -0,0 +1,5 @@ +export * from './articleRouter.js'; +export * from './productRouter.js'; +export * from './imageRouter.js'; +export * from './userRouter.js'; +export * from './notificationRouter.js'; \ No newline at end of file diff --git a/mission_9/src/router/notificationRouter.ts b/mission_9/src/router/notificationRouter.ts new file mode 100644 index 000000000..9266195ad --- /dev/null +++ b/mission_9/src/router/notificationRouter.ts @@ -0,0 +1,35 @@ +import { Router } from 'express'; +import notificationController from '../controller/notificationController.js'; +import auth from '../middleware/auth.js'; + +const router = Router(); + +// 모든 알림을 받아옴 +router.get( + '/notifications', + auth.verifyAccessToken, + notificationController.getNotifications +); + +// 알림 수를 받아옴 +router.get( + '/notifications/unread-count', + auth.verifyAccessToken, + notificationController.getUnreadCount +); + +// 알림을 읽음으로 표시 +router.patch( + '/notifications/:id/read', + auth.verifyAccessToken, + notificationController.markAsRead +); + +// 모든 알림을 읽음으로 표시 +router.patch( + '/notifications/read-all', + auth.verifyAccessToken, + notificationController.markAllAsRead +); + +export default router; diff --git a/mission_9/src/router/productRouter.ts b/mission_9/src/router/productRouter.ts new file mode 100644 index 000000000..9383b6fa7 --- /dev/null +++ b/mission_9/src/router/productRouter.ts @@ -0,0 +1,79 @@ +import express from "express"; +import type { Router } from "express"; +import { validateProduct } from "../middleware/validator.js"; +import auth from "../middleware/auth.js"; +import * as productController from "../controller/productController.js"; + +const router = express.Router(); + +router + .route("/") + + // Upload a new product + .post( + auth.verifyAccessToken, + validateProduct, + productController.createProduct + ) + + // Retrieve all products + .get(productController.getProducts); + +router + .route("/:id") + + // Get informations of a specific product + .get(productController.getProduct) + + // Modify a product property + .patch( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.patchProduct + ) + + // Delete a particular product + .delete( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.deleteProduct + ); + +// Like or unlike a product +router.post( + "/:id/like", + auth.verifyAccessToken, + productController.toggleLike +); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkProductExist, + productController.postComment + ) + + // Inquery all comments + .get(auth.checkProductExist, productController.getComments); + +router + .route("/:id/comments/:cid") + + .patch( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.patchComment + ) + + .delete( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.deleteComment + ); + +export default router; diff --git a/mission_9/src/router/userRouter.ts b/mission_9/src/router/userRouter.ts new file mode 100644 index 000000000..9ab871231 --- /dev/null +++ b/mission_9/src/router/userRouter.ts @@ -0,0 +1,44 @@ +import express from "express"; +import * as userController from "../controller/userController.js"; +import auth from "../middleware/auth.js"; + +const userRouter = express.Router(); + +userRouter + .route("/users") + + // Create user + .post(userController.createUser) + + // Get my(user) info + .get(auth.verifyAccessToken, userController.getMyInfo); + +// Update user info (nickname, email) +userRouter.patch( + "/users/info", + auth.verifyAccessToken, + userController.updateMyInfo +); + +// Update user password +userRouter.patch( + "/users/password", + auth.verifyAccessToken, + userController.updateMyPassword +); + +// Get product lists uploaded by user +userRouter.get( + "/users/products", + auth.verifyAccessToken, + userController.getMyProducts +); + +userRouter.post("/login", userController.getAccessToken); +userRouter.post( + "/login/refresh", + auth.verifyRefreshToken, + userController.getRefreshToken +); + +export default userRouter; diff --git a/mission_9/src/services/articleService.ts b/mission_9/src/services/articleService.ts new file mode 100644 index 000000000..caaca1aac --- /dev/null +++ b/mission_9/src/services/articleService.ts @@ -0,0 +1,80 @@ +import * as articleRepository from "../repository/articleRepository.js"; +import notificationService from "./notificationService.js"; +import type { + CreatePostDTO, + GetPostsDTO, + GetPostDTO, + PatchPostDTO, + DeletePostDTO, + PostCommentDTO, + GetCommentsDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/article.js"; + +export async function createPost(data: CreatePostDTO) { + const result = await articleRepository.createPost(data); + + return result; +} + +export async function getPosts(data: GetPostsDTO) { + const result = await articleRepository.getPosts(data); + + return result; +} + +export async function getPost(id: GetPostDTO) { + const result = await articleRepository.getPost(id); + + return result; +} + +export async function patchPost(data: PatchPostDTO) { + const result = await articleRepository.patchPost(data); + + return result; +} + +export async function deletePost(id: DeletePostDTO) { + const result = await articleRepository.deletePost(id); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const newComment = await articleRepository.postComment(data); + + const article = await articleRepository.getPost({ id: data.pid }); + if (!article) { + return newComment; + } + + if (article.userId !== data.userId) { + const message = `내가 판매 신청한 매물에 새로운 댓글이 달렸습니다.`; + await notificationService.createNotification( + article.userId, + message, + article.id + ); + } + + return newComment; +} + +export async function getComments(data: GetCommentsDTO) { + const result = await articleRepository.getComments(data); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const result = await articleRepository.patchComment(data); + + return result; +} +export async function deleteComment(data: DeleteCommentDTO) { + const result = await articleRepository.deleteComment(data); + + return result; +} diff --git a/mission_9/src/services/index.ts b/mission_9/src/services/index.ts new file mode 100644 index 000000000..69a5a5e9d --- /dev/null +++ b/mission_9/src/services/index.ts @@ -0,0 +1,4 @@ +export * from './articleService.js'; +export * from './productService.js'; +export * from './userService.js'; +export * from './notificationService.js'; \ No newline at end of file diff --git a/mission_9/src/services/notificationService.ts b/mission_9/src/services/notificationService.ts new file mode 100644 index 000000000..51d3cad92 --- /dev/null +++ b/mission_9/src/services/notificationService.ts @@ -0,0 +1,66 @@ +import notificationRepository from '../repository/notificationRepository.js'; +import { getIO } from '../lib/socket.js'; + +async function createNotification( + userId: number, + message: string, + articleId?: number, + productId?: number +) { + const newNotification = await notificationRepository.create( + userId, + message, + articleId, + productId + ); + + // 특정 유저ID에게 실시간 알림 전송 + const io = getIO(); + io.to(String(userId)).emit('new_notification', newNotification); + + // Also emit an unread count update + const unreadCount = await notificationRepository.getUnreadCount(userId); + io.to(String(userId)).emit('unread_count', unreadCount); + + return newNotification; +} + +async function getUserNotifications(userId: number) { + return notificationRepository.findManyByUserId(userId); +} + +async function getUnreadNotificationCount(userId: number) { + return notificationRepository.getUnreadCount(userId); +} + +async function markNotificationAsRead(notificationId: number, userId: number) { + const updatedNotification = await notificationRepository.markAsRead( + notificationId, + userId + ); + + // Emit an unread count update + const io = getIO(); + const unreadCount = await notificationRepository.getUnreadCount(userId); + io.to(String(userId)).emit('unread_count', unreadCount); + + return updatedNotification; +} + +async function markAllNotificationsAsRead(userId: number) { + const result = await notificationRepository.markAllAsRead(userId); + + // Emit an unread count update + const io = getIO(); + io.to(String(userId)).emit('unread_count', 0); + + return result; +} + +export default { + createNotification, + getUserNotifications, + getUnreadNotificationCount, + markNotificationAsRead, + markAllNotificationsAsRead, +}; diff --git a/mission_9/src/services/productService.ts b/mission_9/src/services/productService.ts new file mode 100644 index 000000000..0444fdb75 --- /dev/null +++ b/mission_9/src/services/productService.ts @@ -0,0 +1,103 @@ +import * as productRepository from "../repository/productRepository.js"; +import notificationService from "./notificationService.js"; +import type { + CreateProductDTO, + GetProductsDTO, + GetProductDTO, + PatchProductDTO, + DeleteProductDTO, + PostCommentDTO, + GetCommentsDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/product.js"; + +export async function createProduct(data: CreateProductDTO) { + const result = await productRepository.createProduct(data); + + return result; +} + +export async function getProducts(data: GetProductsDTO) { + const result = await productRepository.getProducts(data); + + return result; +} + +export async function getProduct(data: GetProductDTO) { + const result = await productRepository.getProduct(data); + + return result; +} + +export async function patchProduct(data: PatchProductDTO) { + const { id, price: newPrice } = data; + + const originalProduct = await productRepository.getProduct({ id: Number(id) }); + if (!originalProduct) { + throw new Error("상품이 존재하지 않습니다."); + } + const oldPrice = originalProduct.price; + + const updatedProduct = await productRepository.patchProduct(data); + + if (newPrice !== undefined && newPrice !== oldPrice) { + const likedUsers = await productRepository.getLikedUsersByProductId( + Number(id) + ); + + for (const liked of likedUsers) { + const message = `'${originalProduct.name}' 상품의 가격이 ${oldPrice}원에서 ${newPrice}원으로 변경되었습니다.`; + await notificationService.createNotification( + liked.userId, + message, + undefined, + Number(id) + ); + } + } + + return updatedProduct; +} + +export async function deleteProduct(data: DeleteProductDTO) { + const result = await productRepository.deleteProduct(data); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const result = await productRepository.postComment(data); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const result = await productRepository.getComments(data); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const result = await productRepository.patchComment(data); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const result = await productRepository.deleteComment(data); + + return result; +} + +export async function toggleLike(userId: number, productId: number) { + const existingLike = await productRepository.findLike(userId, productId); + + if (existingLike) { + await productRepository.unlikeProduct(userId, productId); + return { message: '관심 목록에서 삭제했습니다.' }; + } else { + await productRepository.likeProduct(userId, productId); + return { message: '관심 목록에 추가했습니다.' }; + } +} diff --git a/mission_9/src/services/userService.ts b/mission_9/src/services/userService.ts new file mode 100644 index 000000000..2060ef614 --- /dev/null +++ b/mission_9/src/services/userService.ts @@ -0,0 +1,121 @@ +import * as userRepository from "../repository/userRepository.js"; +import * as productRepository from "../repository/productRepository.js"; +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; +import type { CreateUserDTO, GetUserDTO, UserInfoDTO } from "../types/user.js"; + +export async function createUser(user: CreateUserDTO) { + // 이미 가입된 이메일인지 검증 + const existedUser = await userRepository.findByEmail(user.email); + + if (existedUser) { + const err = new Error("User already exists"); + err.statusCode = 422; + throw err; + } + + const createdUser = await userRepository.createUser(user); + const createdUserId = await userRepository.filterSensitiveUserData( + createdUser + ).id; + + return createdUserId; +} + +export async function getUser({ email, password }: GetUserDTO) { + const user: UserInfoDTO | null = await userRepository.findByEmail(email); + + // If user is invalid + if (!user || !user.password) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + throw err; + } + + // Verifying password + await verifyPassword(password, user.password); + + // Return without password + return userRepository.filterSensitiveUserData(user); +} + +export async function getUserById(userId: number) { + const user = await userRepository.findById(userId); + + if (!user) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return userRepository.filterSensitiveUserData(user); +} + +async function verifyPassword(inputPassword: string, password: string) { + const isVerified = await bcrypt.compare(inputPassword, password); + + if (!isVerified) { + const err = new Error("Password is wrong"); + err.statusCode = 401; + throw err; + } +} + +export function createToken(user: UserInfoDTO, token: string | null = null) { + const payload = { userId: user.id }; + const options: jwt.SignOptions = { + expiresIn: token === "refresh" ? "2W" : "1H", + }; + + if (!process.env.JWT_SECRET) { + throw new Error("JWT_SECRET is not defined"); + } + + return jwt.sign(payload, process.env.JWT_SECRET, options); +} + +export async function refreshToken(userId: number, refreshToken: string) { + const user = await userRepository.findById(userId); + + if (!user || user.refreshToken !== refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 404; + throw err; + } + + const accessToken = createToken(user); + return accessToken; +} + +export async function updateUserInfo(userId: number, toUpdate: any) { + // 수정할 내용이 없다면 에러 처리 + if (Object.keys(toUpdate).length === 0) { + const err = new Error("No data to update"); + err.statusCode = 400; + throw err; + } + + const updatedUser = await userRepository.updateUser(userId, toUpdate); + + return userRepository.filterSensitiveUserData(updatedUser); +} + +export async function updateUserPassword(userId: number, newPassword: string) { + const hashedPassword = await userRepository.hashPassword(newPassword); + const user = await userRepository.updateUser(userId, { + password: hashedPassword, + }); + + return userRepository.filterSensitiveUserData(user); +} + +export async function getMyProducts(userId: number) { + const products = await productRepository.getProductsByUser({ userId }); + if (!products) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return products.Product; +} diff --git a/mission_9/src/types/article.ts b/mission_9/src/types/article.ts new file mode 100644 index 000000000..1398c1c95 --- /dev/null +++ b/mission_9/src/types/article.ts @@ -0,0 +1,54 @@ +export interface CreatePostDTO { + title: string; + content: string; + userId: number; +} + +export interface GetPostsDTO { + cursor?: number; + limit: number; + sort: "asc" | "desc"; + offset: number; + search?: string; +} + +export interface GetPostDTO { + id: number; +} + +export interface PatchPostDTO { + id: number; + title?: string; + content?: string; +} + +export interface DeletePostDTO { + id: number; +} + +export interface PostCommentDTO { + pid: number; + name: string; + content: string; + userId: number; +} + +export interface GetCommentsDTO { + pid: number; + cursor: number; + limit: number; +} + +export interface GetCommentDTO { + cid: number; +} + +export interface PatchCommentDTO { + cid: number; + name: string; + content: string; +} + +export interface DeleteCommentDTO { + cid: number; +} diff --git a/mission_9/src/types/auth.d.ts b/mission_9/src/types/auth.d.ts new file mode 100644 index 000000000..7353fbba8 --- /dev/null +++ b/mission_9/src/types/auth.d.ts @@ -0,0 +1,5 @@ +export interface JwtPayload { + userId: number; + iat?: number; + exp?: number; +} diff --git a/mission_9/src/types/express/index.d.ts b/mission_9/src/types/express/index.d.ts new file mode 100644 index 000000000..25cbc8d62 --- /dev/null +++ b/mission_9/src/types/express/index.d.ts @@ -0,0 +1,10 @@ +import "express"; +import type { JwtPayload } from "../auth.d.js"; + +declare module "express-serve-static-core" { + interface Request { + // user?: import("../types/auth").JwtPayload; + user?: JwtPayload; + auth?: JwtPayload; + } +} diff --git a/mission_9/src/types/global.ts b/mission_9/src/types/global.ts new file mode 100644 index 000000000..452228e41 --- /dev/null +++ b/mission_9/src/types/global.ts @@ -0,0 +1,5 @@ +declare global { + interface Error { + statusCode?: number; + } +} \ No newline at end of file diff --git a/mission_9/src/types/product.ts b/mission_9/src/types/product.ts new file mode 100644 index 000000000..52d1aa2f2 --- /dev/null +++ b/mission_9/src/types/product.ts @@ -0,0 +1,63 @@ +export interface CreateProductDTO { + userId: number; + name: string; + description: string; + price: number; + tags: string[]; +} + +export interface GetProductsDTO { + offset: number; + limit: number; + sort: "asc" | "desc"; + search: string; +} + +export interface GetProductDTO { + id: number; +} + +export interface PatchProductDTO { + id: number; + name?: string; + description?: string; + price?: number; + tags?: string[]; +} + +export interface DeleteProductDTO { + id: number; +} + +export interface PostCommentDTO { + pid: number; + userId: number; + content: string; + name: string; +} + +export interface GetCommentsDTO { + pid: number; + cursor: number | null; + limit: number; +} + +export interface GetCommentDTO { + cid: number; +} + +export interface PatchCommentDTO { + cid: number; + name: string; + content: string; +} + +export interface DeleteCommentDTO { + cid: number; +} + +export interface GetProductsByUserDTO { + userId: number; + offset?: number; + limit?: number; +} diff --git a/mission_9/src/types/user.ts b/mission_9/src/types/user.ts new file mode 100644 index 000000000..adf66d149 --- /dev/null +++ b/mission_9/src/types/user.ts @@ -0,0 +1,21 @@ +export interface CreateUserDTO { + email: string; + nickname: string; + password: string; +} + +export interface GetUserDTO { + email: string; + password: string; +} + +export interface UserInfoDTO { + password?: string; + email: string; + nickname: string; + image: string | null; + refreshToken?: string | null; + createdAt: Date; + updatedAt: Date; + id: number; +} diff --git a/mission_9/test-client.html b/mission_9/test-client.html new file mode 100644 index 000000000..a7bc85c49 --- /dev/null +++ b/mission_9/test-client.html @@ -0,0 +1,142 @@ + + + + + + Socket.IO Test Client + + + +
+

1. 실시간 알림 수신 설정

+ + + +

2. 알림 트리거 (댓글 작성)

+ + + + +
+ +
+

서버 로그

+
+

서버 로그가 여기에 표시됩니다...

+
+
+ + + + + \ No newline at end of file diff --git a/mission_9/tsconfig.json b/mission_9/tsconfig.json new file mode 100644 index 000000000..cbfb43efb --- /dev/null +++ b/mission_9/tsconfig.json @@ -0,0 +1,48 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "moduleResolution": "nodenext", + "target": "es2022", + // "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, + + "esModuleInterop": true + }, + "include": ["src", "env.d.ts"] +} From c84d3aa2e15f8ab77b6448b7dafdb225647866fd Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 16 Nov 2025 18:02:01 +0900 Subject: [PATCH 086/130] feat: install jest, @types/jest, ts-jest for testing --- mission_9/package-lock.json | 6595 +++++++++++++++++++++++++++++------ mission_9/package.json | 3 + 2 files changed, 5488 insertions(+), 1110 deletions(-) diff --git a/mission_9/package-lock.json b/mission_9/package-lock.json index f16cea7a4..ad1f6a0ee 100644 --- a/mission_9/package-lock.json +++ b/mission_9/package-lock.json @@ -29,10 +29,13 @@ "@types/cors": "^2.8.19", "@types/express": "^5.0.3", "@types/express-jwt": "^6.0.4", + "@types/jest": "^30.0.0", "@types/multer": "^2.0.0", "@types/node": "^24.3.1", "@types/socket.io": "^3.0.1", + "jest": "^30.2.0", "prisma": "^6.13.0", + "ts-jest": "^29.4.5", "typescript": "^5.9.2" } }, @@ -51,1383 +54,4228 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "devOptional": true, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "aix" - ], + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "devOptional": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, "engines": { - "node": ">=18" + "node": ">=6.0.0" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/linux-s390x": { + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emnapi/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ - "s390x" + "ppc64" ], "license": "MIT", "optional": true, "os": [ - "linux" + "aix" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/linux-x64": { + "node_modules/@esbuild/android-arm": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ - "x64" + "arm" ], "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/netbsd-arm64": { + "node_modules/@esbuild/android-arm64": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], "license": "MIT", "optional": true, "os": [ - "netbsd" + "android" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/netbsd-x64": { + "node_modules/@esbuild/android-x64": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], "license": "MIT", "optional": true, "os": [ - "netbsd" + "android" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/openbsd-arm64": { + "node_modules/@esbuild/darwin-arm64": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], "license": "MIT", "optional": true, "os": [ - "openbsd" + "darwin" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/openbsd-x64": { + "node_modules/@esbuild/darwin-x64": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], "license": "MIT", "optional": true, "os": [ - "openbsd" + "darwin" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/openharmony-arm64": { + "node_modules/@esbuild/freebsd-arm64": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], "license": "MIT", "optional": true, "os": [ - "openharmony" + "freebsd" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/sunos-x64": { + "node_modules/@esbuild/freebsd-x64": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], "license": "MIT", "optional": true, "os": [ - "sunos" + "freebsd" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/win32-arm64": { + "node_modules/@esbuild/linux-arm": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ - "arm64" + "arm" ], "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/win32-ia32": { + "node_modules/@esbuild/linux-arm64": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ - "ia32" + "arm64" ], "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/win32-x64": { + "node_modules/@esbuild/linux-ia32": { "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ - "x64" + "ia32" ], "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { "node": ">=18" } }, - "node_modules/@prisma/client": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.13.0.tgz", - "integrity": "sha512-8m2+I3dQovkV8CkDMluiwEV1TxV9EXdT6xaCz39O6jYw7mkf5gwfmi+cL4LJsEPwz5tG7sreBwkRpEMJedGYUQ==", - "hasInstallScript": true, - "license": "Apache-2.0", + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.18" - }, - "peerDependencies": { - "prisma": "*", - "typescript": ">=5.1.0" - }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/@prisma/config": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.13.0.tgz", - "integrity": "sha512-OYMM+pcrvj/NqNWCGESSxVG3O7kX6oWuGyvufTUNnDw740KIQvNyA4v0eILgkpuwsKIDU36beZCkUtIt0naTog==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "c12": "3.1.0", - "deepmerge-ts": "7.1.5", - "effect": "3.16.12", - "read-package-up": "11.0.0" - } - }, - "node_modules/@prisma/debug": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.13.0.tgz", - "integrity": "sha512-um+9pfKJW0ihmM83id9FXGi5qEbVJ0Vxi1Gm0xpYsjwUBnw6s2LdPBbrsG9QXRX46K4CLWCTNvskXBup4i9hlw==", - "devOptional": true, - "license": "Apache-2.0" - }, - "node_modules/@prisma/engines": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.13.0.tgz", - "integrity": "sha512-D+1B79LFvtWA0KTt8ALekQ6A/glB9w10ETknH5Y9g1k2NYYQOQy93ffiuqLn3Pl6IPJG3EsK/YMROKEaq8KBrA==", - "devOptional": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "6.13.0", - "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", - "@prisma/fetch-engine": "6.13.0", - "@prisma/get-platform": "6.13.0" + "node": ">=18" } }, - "node_modules/@prisma/engines-version": { - "version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd.tgz", - "integrity": "sha512-MpPyKSzBX7P/ZY9odp9TSegnS/yH3CSbchQE9f0yBg3l2QyN59I6vGXcoYcqKC9VTniS1s18AMmhyr1OWavjHg==", - "devOptional": true, - "license": "Apache-2.0" - }, - "node_modules/@prisma/fetch-engine": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.13.0.tgz", - "integrity": "sha512-grmmq+4FeFKmaaytA8Ozc2+Tf3BC8xn/DVJos6LL022mfRlMZYjT3hZM0/xG7+5fO95zFG9CkDUs0m1S2rXs5Q==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "6.13.0", - "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", - "@prisma/get-platform": "6.13.0" + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@prisma/get-platform": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.13.0.tgz", - "integrity": "sha512-Nii2pX50fY4QKKxQwm7/vvqT6Ku8yYJLZAFX4e2vzHwRdMqjugcOG5hOSLjxqoXb0cvOspV70TOhMzrw8kqAnw==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "6.13.0" + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "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", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "license": "MIT" - }, - "node_modules/@standard-schema/spec": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@types/bcrypt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", - "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", - "dev": true, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], "license": "MIT", - "dependencies": { - "@types/node": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@types/node": "*" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/cookie-parser": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.9.tgz", - "integrity": "sha512-tGZiZ2Gtc4m3wIdLkZ8mkj1T6CEHb35+VApbL2T14Dew8HA7c+04dmKqsKRNC+8RJPm16JEK0tFSwdZqubfc4g==", - "dev": true, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], "license": "MIT", - "peerDependencies": { - "@types/express": "*" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/cors": { - "version": "2.8.19", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", - "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@types/node": "*" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/express": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", - "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", - "dev": true, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^5.0.0", - "@types/serve-static": "*" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" } }, - "node_modules/@types/express-jwt": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-6.0.4.tgz", - "integrity": "sha512-I53KRQ9D0eTA6hVCN9S73iOeprKS3JNWK+Cp2mDPB6uOIkTVpkgSkX394kHQzb5cd0U02I0adRmsMxHk+zX8tA==", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@types/express": "*", - "@types/express-unless": "*" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@types/express-serve-static-core": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz", - "integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==", + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "engines": { + "node": ">=8" } }, - "node_modules/@types/express-unless": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.3.tgz", - "integrity": "sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw==", + "node_modules/@jest/console": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", + "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/express": "*" + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "node_modules/@jest/core": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", + "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", "dev": true, - "license": "MIT" - }, - "node_modules/@types/jsonwebtoken": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", - "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", "license": "MIT", "dependencies": { - "@types/ms": "*", - "@types/node": "*" + "@jest/console": "30.2.0", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.2.0", + "jest-config": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-resolve-dependencies": "30.2.0", + "jest-runner": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "jest-watcher": "30.2.0", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", "dev": true, - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } }, - "node_modules/@types/multer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", - "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", + "node_modules/@jest/environment": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", + "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", "dev": true, "license": "MIT", "dependencies": { - "@types/express": "*" + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/node": { - "version": "24.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", - "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "node_modules/@jest/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.10.0" + "expect": "30.2.0", + "jest-snapshot": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "devOptional": true, - "license": "MIT" + "node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } }, - "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "node_modules/@jest/fake-timers": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", + "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@sinonjs/fake-timers": "^13.0.0", + "@types/node": "*", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } }, - "node_modules/@types/send": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", - "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "node_modules/@jest/globals": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", + "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", "dev": true, "license": "MIT", "dependencies": { - "@types/mime": "^1", - "@types/node": "*" + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/types": "30.2.0", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/serve-static": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", - "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", "dev": true, "license": "MIT", "dependencies": { - "@types/http-errors": "*", "@types/node": "*", - "@types/send": "*" + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@types/socket.io": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-3.0.1.tgz", - "integrity": "sha512-XSma2FhVD78ymvoxYV4xGXrIH/0EKQ93rR+YR0Y+Kw1xbPzLDCip/UWSejZ08FpxYeYNci/PZPQS9anrvJRqMA==", + "node_modules/@jest/reporters": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", + "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", "dev": true, "license": "MIT", "dependencies": { - "socket.io": "*" - } - }, - "node_modules/accepts": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", + "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", + "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/types": "30.2.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", + "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", + "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@prisma/client": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.13.0.tgz", + "integrity": "sha512-8m2+I3dQovkV8CkDMluiwEV1TxV9EXdT6xaCz39O6jYw7mkf5gwfmi+cL4LJsEPwz5tG7sreBwkRpEMJedGYUQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.13.0.tgz", + "integrity": "sha512-OYMM+pcrvj/NqNWCGESSxVG3O7kX6oWuGyvufTUNnDw740KIQvNyA4v0eILgkpuwsKIDU36beZCkUtIt0naTog==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.16.12", + "read-package-up": "11.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.13.0.tgz", + "integrity": "sha512-um+9pfKJW0ihmM83id9FXGi5qEbVJ0Vxi1Gm0xpYsjwUBnw6s2LdPBbrsG9QXRX46K4CLWCTNvskXBup4i9hlw==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.13.0.tgz", + "integrity": "sha512-D+1B79LFvtWA0KTt8ALekQ6A/glB9w10ETknH5Y9g1k2NYYQOQy93ffiuqLn3Pl6IPJG3EsK/YMROKEaq8KBrA==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/fetch-engine": "6.13.0", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd.tgz", + "integrity": "sha512-MpPyKSzBX7P/ZY9odp9TSegnS/yH3CSbchQE9f0yBg3l2QyN59I6vGXcoYcqKC9VTniS1s18AMmhyr1OWavjHg==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.13.0.tgz", + "integrity": "sha512-grmmq+4FeFKmaaytA8Ozc2+Tf3BC8xn/DVJos6LL022mfRlMZYjT3hZM0/xG7+5fO95zFG9CkDUs0m1S2rXs5Q==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0", + "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", + "@prisma/get-platform": "6.13.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.13.0.tgz", + "integrity": "sha512-Nii2pX50fY4QKKxQwm7/vvqT6Ku8yYJLZAFX4e2vzHwRdMqjugcOG5hOSLjxqoXb0cvOspV70TOhMzrw8kqAnw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.13.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.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", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie-parser": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.9.tgz", + "integrity": "sha512-tGZiZ2Gtc4m3wIdLkZ8mkj1T6CEHb35+VApbL2T14Dew8HA7c+04dmKqsKRNC+8RJPm16JEK0tFSwdZqubfc4g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", + "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-jwt": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-6.0.4.tgz", + "integrity": "sha512-I53KRQ9D0eTA6hVCN9S73iOeprKS3JNWK+Cp2mDPB6uOIkTVpkgSkX394kHQzb5cd0U02I0adRmsMxHk+zX8tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/express-unless": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz", + "integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express-unless": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.3.tgz", + "integrity": "sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/multer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", + "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/node": { + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/socket.io": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-3.0.1.tgz", + "integrity": "sha512-XSma2FhVD78ymvoxYV4xGXrIH/0EKQ93rR+YR0Y+Kw1xbPzLDCip/UWSejZ08FpxYeYNci/PZPQS9anrvJRqMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "socket.io": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/babel-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", + "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "30.2.0", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, + "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", + "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", + "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.28", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.28.tgz", + "integrity": "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "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/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/c12/node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001755", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001755.tgz", + "integrity": "sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/cjs-module-lexer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz", + "integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.16.12", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", + "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.254", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.254.tgz", + "integrity": "sha512-DcUsWpVhv9svsKRxnSCZ86SjD+sp32SGidNB37KpqXJncp1mfUgKbHvBomE89WJDbfVKw1mdv5+ikrvd43r+Bg==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-jwt": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.5.1.tgz", + "integrity": "sha512-Dv6QjDLpR2jmdb8M6XQXiCcpEom7mK8TOqnr0/TngDKsG2DHVkO8+XnVxkJVN7BuS1I3OrGw6N8j5DaaGgkDRQ==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "^9", + "express-unless": "^2.1.3", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express-unless": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz", + "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==", + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], "license": "MIT", "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" + "pure-rand": "^6.1.0" }, "engines": { - "node": ">= 0.6" + "node": ">=8.0.0" } }, - "node_modules/append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, "license": "MIT" }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "license": "MIT", - "engines": { - "node": "^4.5.0 || >= 5.9" + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" } }, - "node_modules/bcrypt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", - "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", - "hasInstallScript": true, + "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==", + "dev": true, "license": "MIT", "dependencies": { - "node-addon-api": "^8.3.0", - "node-gyp-build": "^4.8.4" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">= 18" + "node": ">=8" } }, - "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", "license": "MIT", "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { - "node": ">=18" + "node": ">= 0.8" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause" - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", "dependencies": { - "streamsearch": "^1.1.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=10.16.0" + "node": ">=8" } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/c12": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", - "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", - "devOptional": true, - "license": "MIT", + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", "dependencies": { - "chokidar": "^4.0.3", - "confbox": "^0.2.2", - "defu": "^6.1.4", - "dotenv": "^16.6.1", - "exsolve": "^1.0.7", - "giget": "^2.0.0", - "jiti": "^2.4.2", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "perfect-debounce": "^1.0.0", - "pkg-types": "^2.2.0", - "rc9": "^2.1.2" + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" }, - "peerDependencies": { - "magicast": "^0.3.5" + "engines": { + "node": ">=14" }, - "peerDependenciesMeta": { - "magicast": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/c12/node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "devOptional": true, - "license": "BSD-2-Clause", + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" + "node": ">= 0.6" } }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, "engines": { - "node": ">= 0.4" + "node": ">= 0.8" } }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.4" - }, + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "devOptional": true, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=6.9.0" } }, - "node_modules/citty": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", - "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "consola": "^3.2.3" + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "engines": [ - "node >= 6.0" - ], + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "devOptional": true, - "license": "MIT" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/consola": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", - "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", - "devOptional": true, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, "license": "MIT", "engines": { - "node": "^14.18.0 || >=16.10.0" + "node": ">=8.0.0" } }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { - "safe-buffer": "5.2.1" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" } }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "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": ">= 0.6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/cookie-parser": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", - "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "devOptional": true, "license": "MIT", "dependencies": { - "cookie": "0.7.2", - "cookie-signature": "1.0.6" + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" }, - "engines": { - "node": ">= 0.8.0" + "bin": { + "giget": "dist/cli.mjs" } }, - "node_modules/cookie-parser/node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, "engines": { - "node": ">= 0.10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "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/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" }, - "engines": { - "node": ">=6.0" + "bin": { + "handlebars": "bin/handlebars" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deepmerge-ts": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", - "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", - "devOptional": true, - "license": "BSD-3-Clause", "engines": { - "node": ">=16.0.0" + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/destr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", - "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", - "license": "BSD-2-Clause", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://dotenvx.com" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "license": "Apache-2.0", + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "devOptional": true, + "license": "ISC", "dependencies": { - "safe-buffer": "^5.0.1" + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, "license": "MIT" }, - "node_modules/effect": { - "version": "3.16.12", - "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", - "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "fast-check": "^3.23.1" - } - }, - "node_modules/encodeurl": { + "node_modules/http-errors": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, "engines": { "node": ">= 0.8" } }, - "node_modules/engine.io": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", - "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "license": "MIT", - "dependencies": { - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.7.2", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1" - }, "engines": { - "node": ">=10.2.0" + "node": ">= 0.8" } }, - "node_modules/engine.io-parser": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", - "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", - "license": "MIT", + "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.0.0" + "node": ">=10.17.0" } }, - "node_modules/engine.io/node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" }, "engines": { - "node": ">=6.0" + "node": ">=8" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/engine.io/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=0.8.19" } }, - "node_modules/engine.io/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/index-to-position": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", + "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", + "devOptional": true, "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" + "engines": { + "node": ">=18" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.10" } }, - "node_modules/engine.io/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=6" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=0.12.0" } }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "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", - "dependencies": { - "es-errors": "^1.3.0" + "engines": { + "node": ">=8" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.4" + "node": ">=8" } }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">=18" + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "engines": { + "node": ">=10" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", + "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", + "dev": true, "license": "MIT", "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.0", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" + "@jest/core": "30.2.0", + "@jest/types": "30.2.0", + "import-local": "^3.2.0", + "jest-cli": "30.2.0" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">= 18" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/express-jwt": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.5.1.tgz", - "integrity": "sha512-Dv6QjDLpR2jmdb8M6XQXiCcpEom7mK8TOqnr0/TngDKsG2DHVkO8+XnVxkJVN7BuS1I3OrGw6N8j5DaaGgkDRQ==", + "node_modules/jest-changed-files": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", + "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.1.1", + "jest-util": "30.2.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-circus": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", + "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", + "dev": true, "license": "MIT", "dependencies": { - "@types/jsonwebtoken": "^9", - "express-unless": "^2.1.3", - "jsonwebtoken": "^9.0.0" + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "p-limit": "^3.1.0", + "pretty-format": "30.2.0", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, "engines": { - "node": ">= 8.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/express-unless": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz", - "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==", - "license": "MIT" - }, - "node_modules/exsolve": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", - "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/fast-check": { - "version": "3.23.2", - "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", - "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", - "devOptional": true, + "node_modules/jest-circus/node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, "funding": [ { "type": "individual", @@ -1438,271 +4286,545 @@ "url": "https://opencollective.com/fast-check" } ], + "license": "MIT" + }, + "node_modules/jest-cli": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", + "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", + "dev": true, "license": "MIT", "dependencies": { - "pure-rand": "^6.1.0" + "@jest/core": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=8.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "node_modules/jest-config": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", + "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", + "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.2.0", + "@jest/types": "30.2.0", + "babel-jest": "30.2.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-circus": "30.2.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-runner": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "micromatch": "^4.0.8", + "parse-json": "^5.2.0", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">= 0.8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } } }, - "node_modules/find-up-simple": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", - "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", - "devOptional": true, + "node_modules/jest-config/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, "engines": { - "node": ">=18" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, "engines": { - "node": ">= 0.6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "node_modules/jest-docblock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, "license": "MIT", + "dependencies": { + "detect-newline": "^3.1.0" + }, "engines": { - "node": ">= 0.8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, + "node_modules/jest-each": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", + "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "jest-util": "30.2.0", + "pretty-format": "30.2.0" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "node_modules/jest-environment-node": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", + "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", + "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "node_modules/jest-haste-map": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", + "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", + "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" + "@jest/types": "30.2.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "micromatch": "^4.0.8", + "walker": "^1.0.8" }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optionalDependencies": { + "fsevents": "^2.3.3" } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "node_modules/jest-leak-detector": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", + "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", + "dev": true, "license": "MIT", "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" + "@jest/get-type": "30.1.0", + "pretty-format": "30.2.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/get-tsconfig": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", - "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, "license": "MIT", "dependencies": { - "resolve-pkg-maps": "^1.0.0" + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/giget": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", - "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", - "devOptional": true, + "node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", "dependencies": { - "citty": "^0.1.6", - "consola": "^3.4.0", - "defu": "^6.1.4", - "node-fetch-native": "^1.6.6", - "nypm": "^0.6.0", - "pathe": "^2.0.3" + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, - "bin": { - "giget": "dist/cli.mjs" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "dev": true, "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" + }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", + "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/jest-resolve-dependencies": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", + "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", + "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.2.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/hosted-git-info": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", - "devOptional": true, - "license": "ISC", + "node_modules/jest-runner": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", + "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", + "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^10.0.1" + "@jest/console": "30.2.0", + "@jest/environment": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-leak-detector": "30.2.0", + "jest-message-util": "30.2.0", + "jest-resolve": "30.2.0", + "jest-runtime": "30.2.0", + "jest-util": "30.2.0", + "jest-watcher": "30.2.0", + "jest-worker": "30.2.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/jest-runtime": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", + "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", + "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/globals": "30.2.0", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" }, "engines": { - "node": ">= 0.8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/jest-snapshot": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", + "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "pretty-format": "30.2.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, "engines": { - "node": ">= 0.8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "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": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", + "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", + "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.2.0" }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/index-to-position": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", - "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", - "devOptional": true, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" + "node_modules/jest-watcher": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", + "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.2.0", + "string-length": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "node_modules/jest-worker": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", + "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", + "dev": true, "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.2.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, "engines": { - "node": ">= 0.10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } }, "node_modules/jiti": { "version": "2.5.1", @@ -1721,6 +4843,53 @@ "devOptional": true, "license": "MIT" }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -1764,6 +4933,36 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -1800,6 +4999,13 @@ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -1813,6 +5019,39 @@ "devOptional": true, "license": "ISC" }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1843,6 +5082,27 @@ "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/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", @@ -1864,6 +5124,32 @@ "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/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/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -1873,6 +5159,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -1952,6 +5248,29 @@ "node": ">= 0.6" } }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -1961,6 +5280,13 @@ "node": ">= 0.6" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, "node_modules/node-addon-api": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", @@ -1988,6 +5314,20 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, "node_modules/normalize-package-data": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", @@ -2003,6 +5343,29 @@ "node": "^16.14.0 || >=18.0.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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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/nypm": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", @@ -2072,6 +5435,84 @@ "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/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parse-json": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", @@ -2117,22 +5558,69 @@ "url": "https://github.com/sponsors/jaredhanson" } }, - "node_modules/passport-jwt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", - "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "license": "MIT", - "dependencies": { - "jsonwebtoken": "^9.0.0", - "passport-strategy": "^1.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/passport-strategy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", - "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, "engines": { - "node": ">= 0.4.0" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/path-to-regexp": { @@ -2170,6 +5658,42 @@ "devOptional": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/pkg-types": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz", @@ -2182,6 +5706,34 @@ "pathe": "^2.0.3" } }, + "node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/prisma": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.13.0.tgz", @@ -2288,6 +5840,13 @@ "destr": "^2.0.3" } }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/read-package-up": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", @@ -2354,6 +5913,39 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -2406,9 +5998,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -2460,6 +6052,29 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -2532,6 +6147,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/socket.io": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", @@ -2667,6 +6305,27 @@ "node": ">= 0.6" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -2703,30 +6362,314 @@ "devOptional": true, "license": "CC0-1.0" }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" } }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, "engines": { - "node": ">=10.0.0" + "node": ">=8" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, "node_modules/tinyexec": { @@ -2736,6 +6679,26 @@ "devOptional": true, "license": "MIT" }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -2745,6 +6708,67 @@ "node": ">=0.6" } }, + "node_modules/ts-jest": { + "version": "29.4.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.5.tgz", + "integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, "node_modules/tsx": { "version": "4.20.6", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", @@ -2764,6 +6788,16 @@ "fsevents": "~2.3.3" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "4.41.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", @@ -2811,6 +6845,20 @@ "node": ">=14.17" } }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/undici-types": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", @@ -2839,6 +6887,72 @@ "node": ">= 0.8" } }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -2854,6 +6968,21 @@ "node": ">= 0.4.0" } }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -2874,12 +7003,154 @@ "node": ">= 0.8" } }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/ws": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", @@ -2909,6 +7180,110 @@ "engines": { "node": ">=0.4" } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/mission_9/package.json b/mission_9/package.json index 6718a6de4..5a495942a 100644 --- a/mission_9/package.json +++ b/mission_9/package.json @@ -33,10 +33,13 @@ "@types/cors": "^2.8.19", "@types/express": "^5.0.3", "@types/express-jwt": "^6.0.4", + "@types/jest": "^30.0.0", "@types/multer": "^2.0.0", "@types/node": "^24.3.1", "@types/socket.io": "^3.0.1", + "jest": "^30.2.0", "prisma": "^6.13.0", + "ts-jest": "^29.4.5", "typescript": "^5.9.2" }, "prisma": { From 3b762e2c265aee23e0ce0c5e884a9c609385f912 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 16 Nov 2025 19:42:14 +0900 Subject: [PATCH 087/130] feat: add jest.config.js --- mission_9/jest.config.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 mission_9/jest.config.js diff --git a/mission_9/jest.config.js b/mission_9/jest.config.js new file mode 100644 index 000000000..c6ded9fc5 --- /dev/null +++ b/mission_9/jest.config.js @@ -0,0 +1,13 @@ +const { createDefaultPreset } = require("ts-jest"); + +const tsJestTransformCfg = createDefaultPreset().transform; + +/** @type {import("jest").Config} **/ +export default { + testEnvironment: "node", + verbose: true, + collectCoverage: true, + transform: { + ...tsJestTransformCfg, + }, +}; \ No newline at end of file From 8dac1143a15450261462ef6cbad67b151d6d490f Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 16 Nov 2025 19:43:45 +0900 Subject: [PATCH 088/130] feat: add packages supertest @types/supertest --- mission_9/package-lock.json | 283 ++++++++++++++++++++++++++++++++++++ mission_9/package.json | 2 + 2 files changed, 285 insertions(+) diff --git a/mission_9/package-lock.json b/mission_9/package-lock.json index ad1f6a0ee..19265a0de 100644 --- a/mission_9/package-lock.json +++ b/mission_9/package-lock.json @@ -33,8 +33,10 @@ "@types/multer": "^2.0.0", "@types/node": "^24.3.1", "@types/socket.io": "^3.0.1", + "@types/supertest": "^6.0.3", "jest": "^30.2.0", "prisma": "^6.13.0", + "supertest": "^7.1.4", "ts-jest": "^29.4.5", "typescript": "^5.9.2" } @@ -1465,6 +1467,29 @@ "@tybys/wasm-util": "^0.10.0" } }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -1711,6 +1736,13 @@ "@types/express": "*" } }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/cors": { "version": "2.8.19", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", @@ -1821,6 +1853,13 @@ "@types/node": "*" } }, + "node_modules/@types/methods": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", + "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -1914,6 +1953,30 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/superagent": { + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/supertest": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.3.tgz", + "integrity": "sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } + }, "node_modules/@types/yargs": { "version": "17.0.35", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", @@ -2308,6 +2371,20 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/babel-jest": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", @@ -2883,6 +2960,29 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2987,6 +3087,13 @@ "node": ">=6.6.0" } }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -3074,6 +3181,16 @@ "devOptional": true, "license": "MIT" }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -3100,6 +3217,17 @@ "node": ">=8" } }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "node_modules/dotenv": { "version": "17.2.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", @@ -3324,6 +3452,22 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", @@ -3572,6 +3716,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -3656,6 +3807,64 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "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", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/formidable": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3898,6 +4107,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -5089,6 +5314,16 @@ "dev": true, "license": "MIT" }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -5103,6 +5338,19 @@ "node": ">=8.6" } }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", @@ -6582,6 +6830,41 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/superagent": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz", + "integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.1", + "cookiejar": "^2.1.4", + "debug": "^4.3.7", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.4", + "formidable": "^3.5.4", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supertest": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.4.tgz", + "integrity": "sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^10.2.3" + }, + "engines": { + "node": ">=14.18.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", diff --git a/mission_9/package.json b/mission_9/package.json index 5a495942a..2dc3bcbc2 100644 --- a/mission_9/package.json +++ b/mission_9/package.json @@ -37,8 +37,10 @@ "@types/multer": "^2.0.0", "@types/node": "^24.3.1", "@types/socket.io": "^3.0.1", + "@types/supertest": "^6.0.3", "jest": "^30.2.0", "prisma": "^6.13.0", + "supertest": "^7.1.4", "ts-jest": "^29.4.5", "typescript": "^5.9.2" }, From 01ae80b4d5afe8c723d038ea55312a5bb4738543 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 16 Nov 2025 19:46:22 +0900 Subject: [PATCH 089/130] feat: add test directory for testing purposes --- mission_9/src/test/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mission_9/src/test/.gitkeep diff --git a/mission_9/src/test/.gitkeep b/mission_9/src/test/.gitkeep new file mode 100644 index 000000000..e69de29bb From aaec5de9138bfca7ebd7261fd81bb403ab291f89 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 16 Nov 2025 19:49:56 +0900 Subject: [PATCH 090/130] feat: add test script to package.json --- mission_9/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission_9/package.json b/mission_9/package.json index 2dc3bcbc2..8266f0cc0 100644 --- a/mission_9/package.json +++ b/mission_9/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "test": "jest --coverage --detectOpenHandles", "build": "tsc", "start": "NODE_ENV=production node dist/main.js", "dev": "tsx watch src/main.ts" From de5b1913419f0d3c6646ef64f6e928fdc95af7a3 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 16 Nov 2025 20:00:33 +0900 Subject: [PATCH 091/130] feat: use babel-jest instead of ts-jest for testing --- mission_9/babel.config.cjs | 6 + mission_9/jest.config.js | 13 - mission_9/package-lock.json | 1735 ++++++++++++++++++++++++++++++++--- mission_9/package.json | 5 +- 4 files changed, 1594 insertions(+), 165 deletions(-) create mode 100644 mission_9/babel.config.cjs delete mode 100644 mission_9/jest.config.js diff --git a/mission_9/babel.config.cjs b/mission_9/babel.config.cjs new file mode 100644 index 000000000..1bca1aa2b --- /dev/null +++ b/mission_9/babel.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + presets: [ + ['@babel/preset-env', {targets: {node: 'current'}}], + '@babel/preset-typescript', + ], +}; diff --git a/mission_9/jest.config.js b/mission_9/jest.config.js deleted file mode 100644 index c6ded9fc5..000000000 --- a/mission_9/jest.config.js +++ /dev/null @@ -1,13 +0,0 @@ -const { createDefaultPreset } = require("ts-jest"); - -const tsJestTransformCfg = createDefaultPreset().transform; - -/** @type {import("jest").Config} **/ -export default { - testEnvironment: "node", - verbose: true, - collectCoverage: true, - transform: { - ...tsJestTransformCfg, - }, -}; \ No newline at end of file diff --git a/mission_9/package-lock.json b/mission_9/package-lock.json index 19265a0de..cbaeb6837 100644 --- a/mission_9/package-lock.json +++ b/mission_9/package-lock.json @@ -24,6 +24,9 @@ "tsx": "^4.20.6" }, "devDependencies": { + "@babel/core": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@babel/preset-typescript": "^7.28.5", "@types/bcrypt": "^6.0.0", "@types/cookie-parser": "^1.4.9", "@types/cors": "^2.8.19", @@ -34,10 +37,10 @@ "@types/node": "^24.3.1", "@types/socket.io": "^3.0.1", "@types/supertest": "^6.0.3", + "babel-jest": "^30.2.0", "jest": "^30.2.0", "prisma": "^6.13.0", "supertest": "^7.1.4", - "ts-jest": "^29.4.5", "typescript": "^5.9.2" } }, @@ -124,6 +127,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", @@ -161,6 +177,83 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", + "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.10" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", @@ -171,6 +264,20 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", @@ -203,6 +310,19 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-plugin-utils": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", @@ -213,6 +333,56 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", @@ -243,6 +413,21 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", + "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helpers": { "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", @@ -273,6 +458,103 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", + "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", @@ -328,6 +610,22 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", @@ -461,17 +759,1027 @@ "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", + "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", + "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", + "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.5.tgz", + "integrity": "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "node_modules/@babel/preset-env": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", + "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/compat-data": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.5", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.4", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.28.5", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.28.5", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.4", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.4", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -480,30 +1788,43 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -2440,6 +3761,58 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/babel-preset-current-node-syntax": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", @@ -2601,19 +3974,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -3094,6 +4454,20 @@ "dev": true, "license": "MIT" }, + "node_modules/core-js-compat": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz", + "integrity": "sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.26.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -3549,6 +4923,16 @@ "node": ">=4" } }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -4063,28 +5447,6 @@ "dev": true, "license": "ISC" }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -4279,6 +5641,22 @@ "dev": true, "license": "MIT" }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -5188,6 +6566,13 @@ "node": ">=8" } }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -5224,13 +6609,6 @@ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -5260,13 +6638,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -5528,13 +6899,6 @@ "node": ">= 0.6" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "license": "MIT" - }, "node_modules/node-addon-api": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", @@ -5854,6 +7218,13 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", @@ -6161,6 +7532,64 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6171,6 +7600,27 @@ "node": ">=0.10.0" } }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -6878,6 +8328,19 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/synckit": { "version": "0.11.11", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", @@ -6991,59 +8454,6 @@ "node": ">=0.6" } }, - "node_modules/ts-jest": { - "version": "29.4.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.5.tgz", - "integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "^0.2.6", - "fast-json-stable-stringify": "^2.1.0", - "handlebars": "^4.7.8", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.7.3", - "type-fest": "^4.41.0", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0 || ^30.0.0", - "@jest/types": "^29.0.0 || ^30.0.0", - "babel-jest": "^29.0.0 || ^30.0.0", - "jest": "^29.0.0 || ^30.0.0", - "jest-util": "^29.0.0 || ^30.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jest-util": { - "optional": true - } - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -7128,26 +8538,56 @@ "node": ">=14.17" } }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/undici-types": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", "license": "MIT" }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", @@ -7312,13 +8752,6 @@ "node": ">= 8" } }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", diff --git a/mission_9/package.json b/mission_9/package.json index 8266f0cc0..e010da845 100644 --- a/mission_9/package.json +++ b/mission_9/package.json @@ -28,6 +28,9 @@ "tsx": "^4.20.6" }, "devDependencies": { + "@babel/core": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@babel/preset-typescript": "^7.28.5", "@types/bcrypt": "^6.0.0", "@types/cookie-parser": "^1.4.9", "@types/cors": "^2.8.19", @@ -38,10 +41,10 @@ "@types/node": "^24.3.1", "@types/socket.io": "^3.0.1", "@types/supertest": "^6.0.3", + "babel-jest": "^30.2.0", "jest": "^30.2.0", "prisma": "^6.13.0", "supertest": "^7.1.4", - "ts-jest": "^29.4.5", "typescript": "^5.9.2" }, "prisma": { From 2af8c71ad861ab94c3f6dd515dc50884f4ac3d42 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 16 Nov 2025 23:06:48 +0900 Subject: [PATCH 092/130] feat: empty test files --- .../{src/test/.gitkeep => test/integration/article-auth.test.ts} | 0 mission_9/test/integration/article-noauth.test.ts | 0 mission_9/test/integration/product-auth.test.ts | 0 mission_9/test/integration/product-noauth.test.ts | 0 mission_9/test/integration/user.test.js | 0 mission_9/test/unit/product.test.ts | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename mission_9/{src/test/.gitkeep => test/integration/article-auth.test.ts} (100%) create mode 100644 mission_9/test/integration/article-noauth.test.ts create mode 100644 mission_9/test/integration/product-auth.test.ts create mode 100644 mission_9/test/integration/product-noauth.test.ts create mode 100644 mission_9/test/integration/user.test.js create mode 100644 mission_9/test/unit/product.test.ts diff --git a/mission_9/src/test/.gitkeep b/mission_9/test/integration/article-auth.test.ts similarity index 100% rename from mission_9/src/test/.gitkeep rename to mission_9/test/integration/article-auth.test.ts diff --git a/mission_9/test/integration/article-noauth.test.ts b/mission_9/test/integration/article-noauth.test.ts new file mode 100644 index 000000000..e69de29bb diff --git a/mission_9/test/integration/product-auth.test.ts b/mission_9/test/integration/product-auth.test.ts new file mode 100644 index 000000000..e69de29bb diff --git a/mission_9/test/integration/product-noauth.test.ts b/mission_9/test/integration/product-noauth.test.ts new file mode 100644 index 000000000..e69de29bb diff --git a/mission_9/test/integration/user.test.js b/mission_9/test/integration/user.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/mission_9/test/unit/product.test.ts b/mission_9/test/unit/product.test.ts new file mode 100644 index 000000000..e69de29bb From e64d9adc6a67ec275050a8c20b58bc9f8bbfde42 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 16 Nov 2025 23:07:07 +0900 Subject: [PATCH 093/130] feat: update babel config --- mission_9/babel.config.cjs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mission_9/babel.config.cjs b/mission_9/babel.config.cjs index 1bca1aa2b..9a46be1c8 100644 --- a/mission_9/babel.config.cjs +++ b/mission_9/babel.config.cjs @@ -1,6 +1,3 @@ module.exports = { - presets: [ - ['@babel/preset-env', {targets: {node: 'current'}}], - '@babel/preset-typescript', - ], + presets: ["@babel/preset-env"], }; From 4903d136947ea855aba13635c5785bd1b4123873 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 16 Nov 2025 23:26:53 +0900 Subject: [PATCH 094/130] feat: update test configurations --- mission_9/babel.config.cjs | 2 +- mission_9/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mission_9/babel.config.cjs b/mission_9/babel.config.cjs index 9a46be1c8..fb119885f 100644 --- a/mission_9/babel.config.cjs +++ b/mission_9/babel.config.cjs @@ -1,3 +1,3 @@ module.exports = { - presets: ["@babel/preset-env"], + presets: ["@babel/preset-env", "@babel/preset-typescript"], }; diff --git a/mission_9/package.json b/mission_9/package.json index e010da845..0c35308b7 100644 --- a/mission_9/package.json +++ b/mission_9/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "main": "index.js", "scripts": { - "test": "jest --coverage --detectOpenHandles", + "test": "jest --verbose", "build": "tsc", "start": "NODE_ENV=production node dist/main.js", "dev": "tsx watch src/main.ts" From e8c761daaa7557dc6c1ebabd991af9b1c55d6a84 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 16 Nov 2025 23:27:11 +0900 Subject: [PATCH 095/130] refactor: export httpServer from app.ts for testing --- mission_9/src/app.ts | 59 ++++++++++++++++++++++++++++++++++++++++++ mission_9/src/main.ts | 60 +------------------------------------------ 2 files changed, 60 insertions(+), 59 deletions(-) create mode 100644 mission_9/src/app.ts diff --git a/mission_9/src/app.ts b/mission_9/src/app.ts new file mode 100644 index 000000000..7c97b396a --- /dev/null +++ b/mission_9/src/app.ts @@ -0,0 +1,59 @@ +import path from "path"; +import http from "http"; + +import express from "express"; +import type { Request, Response, NextFunction } from "express"; +import cors from "cors"; +import cookieParser from "cookie-parser"; +import productRouter from "./router/productRouter.js"; +import articleRouter from "./router/articleRouter.js"; +import imageRouter from "./router/imageRouter.js"; +import notificationRouter from "./router/notificationRouter.js"; +import userRouter from "./router/userRouter.js"; +import { initializeSocket } from "./lib/socket.js"; + +import errorHandler from "./handler/errorHandler.js"; + +const app = express(); +export const httpServer = http.createServer(app); + +// Socket.IO 초기화 +const io = initializeSocket(httpServer); + +io.on("connection", (socket) => { + console.log("A user connected:", socket.id); + + socket.on("join", (userId) => { + console.log(`User ${userId} joined room`); + socket.join(userId); + }); + + socket.on("disconnect", () => { + console.log("User disconnected:", socket.id); + }); +}); + +app.use(express.json()); +app.use( + cors({ + methods: ["GET", "POST", "PUT", "PATCH", "DELETE"], + }) +); +app.use(cookieParser()); + +function logRequest(req: Request, _: Response, next: NextFunction) { + console.log(`[${req.method}] ${req.originalUrl}`); + next(); +} + +// middleware for logging all http request +app.use(logRequest); + +app.use("/products", productRouter); +app.use("/articles", articleRouter); +app.use("/upload", imageRouter); +app.use(notificationRouter); +app.use(userRouter); + +app.use(errorHandler); +app.use("/upload", express.static(path.resolve("uploads"))); diff --git a/mission_9/src/main.ts b/mission_9/src/main.ts index 3004deb3a..ded3928d4 100644 --- a/mission_9/src/main.ts +++ b/mission_9/src/main.ts @@ -1,64 +1,6 @@ import "dotenv/config"; -import path from "path"; -import http from "http"; - -import express from "express"; -import type { Request, Response, NextFunction } from "express"; -import cors from "cors"; -import cookieParser from "cookie-parser"; -import productRouter from "./router/productRouter.js"; -import articleRouter from "./router/articleRouter.js"; -import imageRouter from "./router/imageRouter.js"; -import notificationRouter from "./router/notificationRouter.js"; -import userRouter from "./router/userRouter.js"; -import { initializeSocket } from "./lib/socket.js"; - -import errorHandler from "./handler/errorHandler.js"; +import { httpServer } from "./app.js"; const PORT = Number(process.env.PORT) || 3000; -const app = express(); -const httpServer = http.createServer(app); - -// Socket.IO 초기화 -const io = initializeSocket(httpServer); - -io.on("connection", (socket) => { - console.log("A user connected:", socket.id); - - socket.on("join", (userId) => { - console.log(`User ${userId} joined room`); - socket.join(userId); - }); - - socket.on("disconnect", () => { - console.log("User disconnected:", socket.id); - }); -}); - -app.use(express.json()); -app.use( - cors({ - methods: ["GET", "POST", "PUT", "PATCH", "DELETE"], - }) -); -app.use(cookieParser()); - -function logRequest(req: Request, _: Response, next: NextFunction) { - console.log(`[${req.method}] ${req.originalUrl}`); - next(); -} - -// middleware for logging all http request -app.use(logRequest); - -app.use("/products", productRouter); -app.use("/articles", articleRouter); -app.use("/upload", imageRouter); -app.use(notificationRouter); -app.use(userRouter); - -app.use(errorHandler); -app.use("/upload", express.static(path.resolve("uploads"))); - httpServer.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); From 6d90f00a8abd00897d4b6c4880b04c5409e2f4ba Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 00:26:50 +0900 Subject: [PATCH 096/130] feat: coverage files --- mission_9/coverage/clover.xml | 6 + mission_9/coverage/coverage-final.json | 1 + mission_9/coverage/lcov-report/base.css | 224 ++++++++++++++++++ .../coverage/lcov-report/block-navigation.js | 87 +++++++ mission_9/coverage/lcov-report/favicon.png | Bin 0 -> 445 bytes mission_9/coverage/lcov-report/index.html | 101 ++++++++ mission_9/coverage/lcov-report/prettify.css | 1 + mission_9/coverage/lcov-report/prettify.js | 2 + .../lcov-report/sort-arrow-sprite.png | Bin 0 -> 138 bytes mission_9/coverage/lcov-report/sorter.js | 210 ++++++++++++++++ mission_9/coverage/lcov.info | 0 11 files changed, 632 insertions(+) create mode 100644 mission_9/coverage/clover.xml create mode 100644 mission_9/coverage/coverage-final.json create mode 100644 mission_9/coverage/lcov-report/base.css create mode 100644 mission_9/coverage/lcov-report/block-navigation.js create mode 100644 mission_9/coverage/lcov-report/favicon.png create mode 100644 mission_9/coverage/lcov-report/index.html create mode 100644 mission_9/coverage/lcov-report/prettify.css create mode 100644 mission_9/coverage/lcov-report/prettify.js create mode 100644 mission_9/coverage/lcov-report/sort-arrow-sprite.png create mode 100644 mission_9/coverage/lcov-report/sorter.js create mode 100644 mission_9/coverage/lcov.info diff --git a/mission_9/coverage/clover.xml b/mission_9/coverage/clover.xml new file mode 100644 index 000000000..6ef1353be --- /dev/null +++ b/mission_9/coverage/clover.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/mission_9/coverage/coverage-final.json b/mission_9/coverage/coverage-final.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/mission_9/coverage/coverage-final.json @@ -0,0 +1 @@ +{} diff --git a/mission_9/coverage/lcov-report/base.css b/mission_9/coverage/lcov-report/base.css new file mode 100644 index 000000000..f418035b4 --- /dev/null +++ b/mission_9/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/mission_9/coverage/lcov-report/block-navigation.js b/mission_9/coverage/lcov-report/block-navigation.js new file mode 100644 index 000000000..530d1ed2b --- /dev/null +++ b/mission_9/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selector that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/mission_9/coverage/lcov-report/favicon.png b/mission_9/coverage/lcov-report/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c1525b811a167671e9de1fa78aab9f5c0b61cef7 GIT binary patch literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ Unknown% + Statements + 0/0 +
+ + +
+ Unknown% + Branches + 0/0 +
+ + +
+ Unknown% + Functions + 0/0 +
+ + +
+ Unknown% + Lines + 0/0 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/mission_9/coverage/lcov-report/prettify.css b/mission_9/coverage/lcov-report/prettify.css new file mode 100644 index 000000000..b317a7cda --- /dev/null +++ b/mission_9/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/mission_9/coverage/lcov-report/prettify.js b/mission_9/coverage/lcov-report/prettify.js new file mode 100644 index 000000000..b3225238f --- /dev/null +++ b/mission_9/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/mission_9/coverage/lcov-report/sort-arrow-sprite.png b/mission_9/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed68316eb3f65dec9063332d2f69bf3093bbfab GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc literal 0 HcmV?d00001 diff --git a/mission_9/coverage/lcov-report/sorter.js b/mission_9/coverage/lcov-report/sorter.js new file mode 100644 index 000000000..4ed70ae5a --- /dev/null +++ b/mission_9/coverage/lcov-report/sorter.js @@ -0,0 +1,210 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + + // Try to create a RegExp from the searchValue. If it fails (invalid regex), + // it will be treated as a plain text search + let searchRegex; + try { + searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive + } catch (error) { + searchRegex = null; + } + + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + let isMatch = false; + + if (searchRegex) { + // If a valid regex was created, use it for matching + isMatch = searchRegex.test(row.textContent); + } else { + // Otherwise, fall back to the original plain text search + isMatch = row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()); + } + + row.style.display = isMatch ? '' : 'none'; + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/mission_9/coverage/lcov.info b/mission_9/coverage/lcov.info new file mode 100644 index 000000000..e69de29bb From 1dab62ea067ab074fd6c35dfb2e0c94268dc4822 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 00:27:11 +0900 Subject: [PATCH 097/130] feat: remove useless test files --- mission_9/test/integration/article-auth.test.ts | 0 mission_9/test/integration/article-noauth.test.ts | 0 mission_9/test/integration/product-auth.test.ts | 0 mission_9/test/integration/product-noauth.test.ts | 0 mission_9/test/integration/user.test.js | 0 mission_9/test/unit/product.test.ts | 0 6 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 mission_9/test/integration/article-auth.test.ts delete mode 100644 mission_9/test/integration/article-noauth.test.ts delete mode 100644 mission_9/test/integration/product-auth.test.ts delete mode 100644 mission_9/test/integration/product-noauth.test.ts delete mode 100644 mission_9/test/integration/user.test.js delete mode 100644 mission_9/test/unit/product.test.ts diff --git a/mission_9/test/integration/article-auth.test.ts b/mission_9/test/integration/article-auth.test.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/mission_9/test/integration/article-noauth.test.ts b/mission_9/test/integration/article-noauth.test.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/mission_9/test/integration/product-auth.test.ts b/mission_9/test/integration/product-auth.test.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/mission_9/test/integration/product-noauth.test.ts b/mission_9/test/integration/product-noauth.test.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/mission_9/test/integration/user.test.js b/mission_9/test/integration/user.test.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/mission_9/test/unit/product.test.ts b/mission_9/test/unit/product.test.ts deleted file mode 100644 index e69de29bb..000000000 From ad23ada2fe8590cc31a5396bc7c812a8e6809c0f Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 00:49:39 +0900 Subject: [PATCH 098/130] feat: use ts-jest instaed of babel-jest --- mission_9/babel.config.cjs | 3 - mission_9/jest.config.cjs | 13 + mission_9/package-lock.json | 1737 +++-------------------------------- mission_9/package.json | 5 +- 4 files changed, 166 insertions(+), 1592 deletions(-) delete mode 100644 mission_9/babel.config.cjs create mode 100644 mission_9/jest.config.cjs diff --git a/mission_9/babel.config.cjs b/mission_9/babel.config.cjs deleted file mode 100644 index fb119885f..000000000 --- a/mission_9/babel.config.cjs +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: ["@babel/preset-env", "@babel/preset-typescript"], -}; diff --git a/mission_9/jest.config.cjs b/mission_9/jest.config.cjs new file mode 100644 index 000000000..09d20b259 --- /dev/null +++ b/mission_9/jest.config.cjs @@ -0,0 +1,13 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest/presets/default-esm', + testEnvironment: 'node', + transform: { + '^.+\\.m?[tj]s$': [ + 'ts-jest', + { + useESM: true, + }, + ], + }, +}; diff --git a/mission_9/package-lock.json b/mission_9/package-lock.json index cbaeb6837..19265a0de 100644 --- a/mission_9/package-lock.json +++ b/mission_9/package-lock.json @@ -24,9 +24,6 @@ "tsx": "^4.20.6" }, "devDependencies": { - "@babel/core": "^7.28.5", - "@babel/preset-env": "^7.28.5", - "@babel/preset-typescript": "^7.28.5", "@types/bcrypt": "^6.0.0", "@types/cookie-parser": "^1.4.9", "@types/cors": "^2.8.19", @@ -37,10 +34,10 @@ "@types/node": "^24.3.1", "@types/socket.io": "^3.0.1", "@types/supertest": "^6.0.3", - "babel-jest": "^30.2.0", "jest": "^30.2.0", "prisma": "^6.13.0", "supertest": "^7.1.4", + "ts-jest": "^29.4.5", "typescript": "^5.9.2" } }, @@ -127,19 +124,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.3" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", @@ -177,83 +161,6 @@ "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", - "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.5", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", - "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "regexpu-core": "^6.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", @@ -264,20 +171,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", @@ -310,19 +203,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-plugin-utils": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", @@ -333,56 +213,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", @@ -413,21 +243,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", - "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helpers": { "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", @@ -458,103 +273,6 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", - "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", - "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", @@ -610,22 +328,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", @@ -756,1030 +458,20 @@ "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", - "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", - "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", - "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", - "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", - "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", - "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", - "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", - "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.5.tgz", - "integrity": "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", - "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.5", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.4", - "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-dotall-regex": "^7.27.1", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.28.5", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.28.5", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.4", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.28.5", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.4", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "core-js-compat": "^3.43.0", - "semver": "^6.3.1" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { "node": ">=6.9.0" @@ -1788,43 +480,30 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-typescript": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", - "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-typescript": "^7.28.5" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -3761,58 +2440,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, "node_modules/babel-preset-current-node-syntax": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", @@ -3974,6 +2601,19 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -4454,20 +3094,6 @@ "dev": true, "license": "MIT" }, - "node_modules/core-js-compat": { - "version": "3.46.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz", - "integrity": "sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.26.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -4923,16 +3549,6 @@ "node": ">=4" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -5447,6 +4063,28 @@ "dev": true, "license": "ISC" }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -5641,22 +4279,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -6566,13 +5188,6 @@ "node": ">=8" } }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -6609,6 +5224,13 @@ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -6638,6 +5260,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -6899,6 +5528,13 @@ "node": ">= 0.6" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, "node_modules/node-addon-api": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", @@ -7218,13 +5854,6 @@ "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", @@ -7532,64 +6161,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.2", - "regjsgen": "^0.8.0", - "regjsparser": "^0.13.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.2.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/regjsparser": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", - "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7600,27 +6171,6 @@ "node": ">=0.10.0" } }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -8328,19 +6878,6 @@ "node": ">=8" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/synckit": { "version": "0.11.11", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", @@ -8454,6 +6991,59 @@ "node": ">=0.6" } }, + "node_modules/ts-jest": { + "version": "29.4.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.5.tgz", + "integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -8538,55 +7128,25 @@ "node": ">=14.17" } }, - "node_modules/undici-types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", - "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", - "license": "MIT" - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, - "license": "MIT", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" }, "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", - "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" + "node": ">=0.8.0" } }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", - "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "license": "MIT" }, "node_modules/unicorn-magic": { "version": "0.1.0", @@ -8752,6 +7312,13 @@ "node": ">= 8" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", diff --git a/mission_9/package.json b/mission_9/package.json index 0c35308b7..b05a135b1 100644 --- a/mission_9/package.json +++ b/mission_9/package.json @@ -28,9 +28,6 @@ "tsx": "^4.20.6" }, "devDependencies": { - "@babel/core": "^7.28.5", - "@babel/preset-env": "^7.28.5", - "@babel/preset-typescript": "^7.28.5", "@types/bcrypt": "^6.0.0", "@types/cookie-parser": "^1.4.9", "@types/cors": "^2.8.19", @@ -41,10 +38,10 @@ "@types/node": "^24.3.1", "@types/socket.io": "^3.0.1", "@types/supertest": "^6.0.3", - "babel-jest": "^30.2.0", "jest": "^30.2.0", "prisma": "^6.13.0", "supertest": "^7.1.4", + "ts-jest": "^29.4.5", "typescript": "^5.9.2" }, "prisma": { From ea701f4713d1d6b637ed3580682a84a4c4ace7d5 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 00:49:59 +0900 Subject: [PATCH 099/130] feat: exclude test files from build --- mission_9/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mission_9/tsconfig.json b/mission_9/tsconfig.json index cbfb43efb..cd741fa49 100644 --- a/mission_9/tsconfig.json +++ b/mission_9/tsconfig.json @@ -44,5 +44,6 @@ "esModuleInterop": true }, - "include": ["src", "env.d.ts"] + "include": ["src", "env.d.ts"], + "exclude": ["**/*.test.ts"] } From 74cf975116546d18304870a48cb5966d3286e829 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 01:32:53 +0900 Subject: [PATCH 100/130] feat: fix jest error --- mission_9/jest.config.cjs | 21 ++++++++++++--------- mission_9/package.json | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/mission_9/jest.config.cjs b/mission_9/jest.config.cjs index 09d20b259..6496c55b0 100644 --- a/mission_9/jest.config.cjs +++ b/mission_9/jest.config.cjs @@ -1,13 +1,16 @@ /** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { - preset: 'ts-jest/presets/default-esm', - testEnvironment: 'node', - transform: { - '^.+\\.m?[tj]s$': [ - 'ts-jest', - { - useESM: true, - }, - ], + preset: "ts-jest/presets/default-esm", + testEnvironment: "node", + globals: { + "ts-jest": { + useESM: true, + }, }, + moduleNameMapper: { + "^(\\.{1,2}/.*)\\.js$": "$1", + }, + extensionsToTreatAsEsm: [".ts", ".tsx"], + moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], + testMatch: ["/src/**/*.test.ts"], }; diff --git a/mission_9/package.json b/mission_9/package.json index b05a135b1..a33634533 100644 --- a/mission_9/package.json +++ b/mission_9/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "main": "index.js", "scripts": { - "test": "jest --verbose", + "test": "NODE_OPTIONS='--experimental-vm-modules' jest --verbose", "build": "tsc", "start": "NODE_ENV=production node dist/main.js", "dev": "tsx watch src/main.ts" From fd0165387591491475c4fc89f46573c6e524a3d3 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 02:41:55 +0900 Subject: [PATCH 101/130] feat: update seed --- mission_9/prisma/seed.ts | 68 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/mission_9/prisma/seed.ts b/mission_9/prisma/seed.ts index 7763e3fe5..bd79ab898 100644 --- a/mission_9/prisma/seed.ts +++ b/mission_9/prisma/seed.ts @@ -13,6 +13,7 @@ async function main() { nickname: 'Alice', password, image: 'https://i.pravatar.cc/150?u=user1@example.com', + refreshToken: 'some-refresh-token', }, }); @@ -66,7 +67,7 @@ async function main() { }); // create comments - await prisma.comment.create({ + const comment1 = await prisma.comment.create({ data: { name: 'Commenter1', content: 'Great article!', @@ -75,7 +76,7 @@ async function main() { }, }); - await prisma.comment.create({ + const comment2 = await prisma.comment.create({ data: { name: 'Commenter2', content: 'I love this laptop!', @@ -84,7 +85,66 @@ async function main() { }, }); - console.log({ user1, user2, article1, article2, product1, product2 }); + const comment3 = await prisma.comment.create({ + data: { + name: 'Commenter3', + content: 'This is a general comment.', + userId: user1.id, + }, + }); + + const comment4 = await prisma.comment.create({ + data: { + name: 'Commenter4', + content: 'This comment is for both an article and a product.', + userId: user2.id, + articleId: article2.id, + productId: product2.id, + }, + }); + + + // create a liked product + const likedProduct = await prisma.likedProduct.create({ + data: { + userId: user1.id, + productId: product2.id, + }, + }); + + // create notifications + const notification1 = await prisma.notification.create({ + data: { + userId: user1.id, + message: 'Your article has a new comment!', + articleId: article1.id, + }, + }); + + const notification2 = await prisma.notification.create({ + data: { + userId: user2.id, + message: 'Your product has a new comment!', + productId: product1.id, + read: true, + }, + }); + + console.log({ + user1, + user2, + article1, + article2, + product1, + product2, + comment1, + comment2, + comment3, + comment4, + likedProduct, + notification1, + notification2, + }); } main() @@ -95,4 +155,4 @@ main() .finally(async () => { // close Prisma Client at the end await prisma.$disconnect(); - }); + }); \ No newline at end of file From 6421883c33139c0b14e4e2ccdda0aa6576087ab3 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 02:42:16 +0900 Subject: [PATCH 102/130] chore: comment out deprecated configs --- mission_9/jest.config.cjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mission_9/jest.config.cjs b/mission_9/jest.config.cjs index 6496c55b0..395ed16ba 100644 --- a/mission_9/jest.config.cjs +++ b/mission_9/jest.config.cjs @@ -2,11 +2,11 @@ module.exports = { preset: "ts-jest/presets/default-esm", testEnvironment: "node", - globals: { + /* globals: { "ts-jest": { useESM: true, }, - }, + }, */ moduleNameMapper: { "^(\\.{1,2}/.*)\\.js$": "$1", }, From be605d137eeeec0728efcdc97dc5ca9f52b9d8e9 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 02:42:46 +0900 Subject: [PATCH 103/130] feat: add test files --- mission_9/package-lock.json | 665 ++++++++---------- .../test/integration/article-auth.test.ts.no | 3 + .../test/integration/article-noauth.test.ts | 45 ++ .../test/integration/product-auth.test.ts.no | 3 + .../integration/product-noauth.test.ts.no | 3 + .../src/test/integration/user.test.js.no | 3 + mission_9/src/test/unit/product.test.ts.no | 3 + 7 files changed, 345 insertions(+), 380 deletions(-) create mode 100644 mission_9/src/test/integration/article-auth.test.ts.no create mode 100644 mission_9/src/test/integration/article-noauth.test.ts create mode 100644 mission_9/src/test/integration/product-auth.test.ts.no create mode 100644 mission_9/src/test/integration/product-noauth.test.ts.no create mode 100644 mission_9/src/test/integration/user.test.js.no create mode 100644 mission_9/src/test/unit/product.test.ts.no diff --git a/mission_9/package-lock.json b/mission_9/package-lock.json index 19265a0de..799db1783 100644 --- a/mission_9/package-lock.json +++ b/mission_9/package-lock.json @@ -45,7 +45,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -97,16 +97,6 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/generator": { "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", @@ -141,26 +131,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", @@ -227,7 +197,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1515,9 +1485,9 @@ } }, "node_modules/@prisma/client": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.13.0.tgz", - "integrity": "sha512-8m2+I3dQovkV8CkDMluiwEV1TxV9EXdT6xaCz39O6jYw7mkf5gwfmi+cL4LJsEPwz5tG7sreBwkRpEMJedGYUQ==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.19.0.tgz", + "integrity": "sha512-QXFT+N/bva/QI2qoXmjBzL7D6aliPffIwP+81AdTGq0FXDoLxLkWivGMawG8iM5B9BKfxLIXxfWWAF6wbuJU6g==", "hasInstallScript": true, "license": "Apache-2.0", "engines": { @@ -1537,66 +1507,66 @@ } }, "node_modules/@prisma/config": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.13.0.tgz", - "integrity": "sha512-OYMM+pcrvj/NqNWCGESSxVG3O7kX6oWuGyvufTUNnDw740KIQvNyA4v0eILgkpuwsKIDU36beZCkUtIt0naTog==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.19.0.tgz", + "integrity": "sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg==", "devOptional": true, "license": "Apache-2.0", "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", - "effect": "3.16.12", - "read-package-up": "11.0.0" + "effect": "3.18.4", + "empathic": "2.0.0" } }, "node_modules/@prisma/debug": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.13.0.tgz", - "integrity": "sha512-um+9pfKJW0ihmM83id9FXGi5qEbVJ0Vxi1Gm0xpYsjwUBnw6s2LdPBbrsG9QXRX46K4CLWCTNvskXBup4i9hlw==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.19.0.tgz", + "integrity": "sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA==", "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/engines": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.13.0.tgz", - "integrity": "sha512-D+1B79LFvtWA0KTt8ALekQ6A/glB9w10ETknH5Y9g1k2NYYQOQy93ffiuqLn3Pl6IPJG3EsK/YMROKEaq8KBrA==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.19.0.tgz", + "integrity": "sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw==", "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.13.0", - "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", - "@prisma/fetch-engine": "6.13.0", - "@prisma/get-platform": "6.13.0" + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/fetch-engine": "6.19.0", + "@prisma/get-platform": "6.19.0" } }, "node_modules/@prisma/engines-version": { - "version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd.tgz", - "integrity": "sha512-MpPyKSzBX7P/ZY9odp9TSegnS/yH3CSbchQE9f0yBg3l2QyN59I6vGXcoYcqKC9VTniS1s18AMmhyr1OWavjHg==", + "version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773.tgz", + "integrity": "sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ==", "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.13.0.tgz", - "integrity": "sha512-grmmq+4FeFKmaaytA8Ozc2+Tf3BC8xn/DVJos6LL022mfRlMZYjT3hZM0/xG7+5fO95zFG9CkDUs0m1S2rXs5Q==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.19.0.tgz", + "integrity": "sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.13.0", - "@prisma/engines-version": "6.13.0-35.361e86d0ea4987e9f53a565309b3eed797a6bcbd", - "@prisma/get-platform": "6.13.0" + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/get-platform": "6.19.0" } }, "node_modules/@prisma/get-platform": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.13.0.tgz", - "integrity": "sha512-Nii2pX50fY4QKKxQwm7/vvqT6Ku8yYJLZAFX4e2vzHwRdMqjugcOG5hOSLjxqoXb0cvOspV70TOhMzrw8kqAnw==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.19.0.tgz", + "integrity": "sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.13.0" + "@prisma/debug": "6.19.0" } }, "node_modules/@sinclair/typebox": { @@ -1727,9 +1697,9 @@ } }, "node_modules/@types/cookie-parser": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.9.tgz", - "integrity": "sha512-tGZiZ2Gtc4m3wIdLkZ8mkj1T6CEHb35+VApbL2T14Dew8HA7c+04dmKqsKRNC+8RJPm16JEK0tFSwdZqubfc4g==", + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.10.tgz", + "integrity": "sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -1753,15 +1723,15 @@ } }, "node_modules/@types/express": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", - "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.5.tgz", + "integrity": "sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==", "dev": true, "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", - "@types/serve-static": "*" + "@types/serve-static": "^1" } }, "node_modules/@types/express-jwt": { @@ -1776,9 +1746,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz", - "integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", + "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", "dev": true, "license": "MIT", "dependencies": { @@ -1884,21 +1854,14 @@ } }, "node_modules/@types/node": { - "version": "24.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", - "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "license": "MIT", "dependencies": { - "undici-types": "~7.10.0" + "undici-types": "~7.16.0" } }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "devOptional": true, - "license": "MIT" - }, "node_modules/@types/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", @@ -1914,26 +1877,36 @@ "license": "MIT" }, "node_modules/@types/send": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", - "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/mime": "^1", "@types/node": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", - "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", "dev": true, "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", - "@types/send": "*" + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" } }, "node_modules/@types/socket.io": { @@ -2299,19 +2272,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ansi-regex": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", @@ -3072,21 +3032,12 @@ "node": ">= 0.8.0" } }, - "node_modules/cookie-parser/node_modules/cookie-signature": { + "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, "node_modules/cookiejar": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", @@ -3123,9 +3074,9 @@ } }, "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -3277,9 +3228,9 @@ "license": "MIT" }, "node_modules/effect": { - "version": "3.16.12", - "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", - "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz", + "integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3314,6 +3265,16 @@ "dev": true, "license": "MIT" }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -3679,10 +3640,19 @@ "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==", "license": "MIT" }, + "node_modules/express/node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, "node_modules/exsolve": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", - "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", "devOptional": true, "license": "MIT" }, @@ -3709,6 +3679,23 @@ "node": ">=8.0.0" } }, + "node_modules/fast-check/node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "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", @@ -3777,19 +3764,6 @@ "node": ">=8" } }, - "node_modules/find-up-simple": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", - "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -4135,19 +4109,6 @@ "node": ">= 0.4" } }, - "node_modules/hosted-git-info": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", - "devOptional": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -4232,19 +4193,6 @@ "node": ">=0.8.19" } }, - "node_modules/index-to-position": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", - "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4362,6 +4310,19 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", @@ -4496,23 +4457,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-circus/node_modules/pure-rand": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", - "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, "node_modules/jest-cli": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", @@ -4598,25 +4542,6 @@ } } }, - "node_modules/jest-config/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-diff": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", @@ -4936,6 +4861,19 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jest-util": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", @@ -5052,9 +4990,9 @@ } }, "node_modules/jiti": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", - "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "devOptional": true, "license": "MIT", "bin": { @@ -5065,7 +5003,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -5137,6 +5075,18 @@ "npm": ">=6" } }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jwa": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", @@ -5238,11 +5188,14 @@ "license": "MIT" }, "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "devOptional": true, - "license": "ISC" + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } }, "node_modules/make-dir": { "version": "4.0.0", @@ -5260,6 +5213,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -5545,9 +5511,9 @@ } }, "node_modules/node-fetch-native": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", - "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", "devOptional": true, "license": "MIT" }, @@ -5576,21 +5542,6 @@ "dev": true, "license": "MIT" }, - "node_modules/normalize-package-data": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", - "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", - "devOptional": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^7.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -5615,16 +5566,16 @@ } }, "node_modules/nypm": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", - "integrity": "sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", + "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", "devOptional": true, "license": "MIT", "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", - "pkg-types": "^2.2.0", + "pkg-types": "^2.3.0", "tinyexec": "^1.0.1" }, "bin": { @@ -5762,18 +5713,19 @@ "license": "BlueOak-1.0.0" }, "node_modules/parse-json": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", - "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", - "devOptional": true, + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "index-to-position": "^1.1.0", - "type-fest": "^4.39.1" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">=18" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5871,13 +5823,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "license": "MIT", - "engines": { - "node": ">=16" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/pathe": { @@ -5903,7 +5863,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -5943,9 +5903,9 @@ } }, "node_modules/pkg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz", - "integrity": "sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5983,15 +5943,15 @@ } }, "node_modules/prisma": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.13.0.tgz", - "integrity": "sha512-dfzORf0AbcEyyzxuv2lEwG8g+WRGF/qDQTpHf/6JoHsyF5MyzCEZwClVaEmw3WXcobgadosOboKUgQU0kFs9kw==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.19.0.tgz", + "integrity": "sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==", "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/config": "6.13.0", - "@prisma/engines": "6.13.0" + "@prisma/config": "6.19.0", + "@prisma/engines": "6.19.0" }, "bin": { "prisma": "build/index.js" @@ -6022,10 +5982,10 @@ } }, "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "devOptional": true, + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, "funding": [ { "type": "individual", @@ -6063,18 +6023,34 @@ } }, "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", + "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", - "iconv-lite": "0.6.3", + "iconv-lite": "0.7.0", "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/rc9": { @@ -6095,44 +6071,6 @@ "dev": true, "license": "MIT" }, - "node_modules/read-package-up": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", - "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "find-up-simple": "^1.0.0", - "read-pkg": "^9.0.0", - "type-fest": "^4.6.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", - "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@types/normalize-package-data": "^2.4.3", - "normalize-package-data": "^6.0.0", - "parse-json": "^8.0.0", - "type-fest": "^4.6.0", - "unicorn-magic": "^0.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -6246,15 +6184,13 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/send": { @@ -6574,42 +6510,6 @@ "source-map": "^0.6.0" } }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "devOptional": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", - "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", - "devOptional": true, - "license": "CC0-1.0" - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -6956,11 +6856,14 @@ } }, "node_modules/tinyexec": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", - "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", "devOptional": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/tmpl": { "version": "1.0.5", @@ -7044,6 +6947,32 @@ } } }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -7082,13 +7011,13 @@ } }, "node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "devOptional": true, + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=16" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7115,9 +7044,9 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -7143,24 +7072,11 @@ } }, "node_modules/undici-types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", - "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, - "node_modules/unicorn-magic": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", - "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -7266,17 +7182,6 @@ "node": ">=10.12.0" } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/mission_9/src/test/integration/article-auth.test.ts.no b/mission_9/src/test/integration/article-auth.test.ts.no new file mode 100644 index 000000000..e002ddfb6 --- /dev/null +++ b/mission_9/src/test/integration/article-auth.test.ts.no @@ -0,0 +1,3 @@ +describe('Article Integration Test (Auth)', () => { + // Placeholder for future authenticated article tests +}); \ No newline at end of file diff --git a/mission_9/src/test/integration/article-noauth.test.ts b/mission_9/src/test/integration/article-noauth.test.ts new file mode 100644 index 000000000..30561c29d --- /dev/null +++ b/mission_9/src/test/integration/article-noauth.test.ts @@ -0,0 +1,45 @@ +import { jest } from "@jest/globals"; +import requeset from "supertest"; +import { httpServer as app } from "../../app.js"; + +describe("Article Integration Test (No Auth)", () => { + describe("GET /articles", () => { + it("should return a list of articles", async () => { + const response = await requeset(app).get("/articles").expect(200); + expect(Array.isArray(response.body)).toBe(true); + }); + }); + + describe("GET /articles/:id", () => { + it("should return a specific article by ID", async () => { + const articleId = 1; + const response = await requeset(app) + .get(`/articles/${articleId}`) + .expect(200); + + expect(response.body).toEqual(expect.objectContaining({ id: articleId })); + }); + + it("should return 404 for non-existing article", async () => { + const nonExistingId = 9999; + await requeset(app).get(`/articles/${nonExistingId}`).expect(404); + }); + }); + + describe("GET /articles/:id/comments", () => { + it("should return comments for a specific article", async () => { + const articleId = 1; // Example article ID + const response = await requeset(app) + .get(`/articles/${articleId}/comments`) + .expect(200); + expect(Array.isArray(response.body.comments)).toBe(true); + }); + + it("should return 404 for comments of non-existing article", async () => { + const nonExistingId = 9999; // Example non-existing article ID + await requeset(app) + .get(`/articles/${nonExistingId}/comments`) + .expect(404); + }); + }); +}); diff --git a/mission_9/src/test/integration/product-auth.test.ts.no b/mission_9/src/test/integration/product-auth.test.ts.no new file mode 100644 index 000000000..e002ddfb6 --- /dev/null +++ b/mission_9/src/test/integration/product-auth.test.ts.no @@ -0,0 +1,3 @@ +describe('Article Integration Test (Auth)', () => { + // Placeholder for future authenticated article tests +}); \ No newline at end of file diff --git a/mission_9/src/test/integration/product-noauth.test.ts.no b/mission_9/src/test/integration/product-noauth.test.ts.no new file mode 100644 index 000000000..caecb73b7 --- /dev/null +++ b/mission_9/src/test/integration/product-noauth.test.ts.no @@ -0,0 +1,3 @@ +describe('Product Integration Test (No Auth)', () => { + // Placeholder for future authenticated article tests +}); \ No newline at end of file diff --git a/mission_9/src/test/integration/user.test.js.no b/mission_9/src/test/integration/user.test.js.no new file mode 100644 index 000000000..02b38cb3f --- /dev/null +++ b/mission_9/src/test/integration/user.test.js.no @@ -0,0 +1,3 @@ +describe('User Integration Test', () => { + // Placeholder for future authenticated article tests +}); \ No newline at end of file diff --git a/mission_9/src/test/unit/product.test.ts.no b/mission_9/src/test/unit/product.test.ts.no new file mode 100644 index 000000000..40bbac122 --- /dev/null +++ b/mission_9/src/test/unit/product.test.ts.no @@ -0,0 +1,3 @@ +describe('Product Service Unit Test', () => { + // Placeholder for future authenticated article tests +}); \ No newline at end of file From 7a272328f0bc7fedf1684ccea7036d67a0cc32e8 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 17:09:54 +0900 Subject: [PATCH 104/130] feat: json --- mission_9/src/controller/userController.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mission_9/src/controller/userController.ts b/mission_9/src/controller/userController.ts index 397fed1ad..00b5f5407 100644 --- a/mission_9/src/controller/userController.ts +++ b/mission_9/src/controller/userController.ts @@ -14,7 +14,7 @@ const createUser: RequestHandler = async function (req, res, next) { try { const userId = await userService.createUser({ email, nickname, password }); - return res.status(200).json(userId); + return res.status(200).json({ userId }); } catch (err) { next(err); } @@ -69,7 +69,7 @@ const updateMyInfo: RequestHandler = async function (req, res, next) { const userId = req.user ? req.user.userId : null; const { email, nickname } = req.body; - if (!email && !nickname || userId === null) { + if ((!email && !nickname) || userId === null) { const err = new Error("Required parameter is missing"); err.statusCode = 400; return next(err); @@ -137,7 +137,10 @@ const getRefreshToken: RequestHandler = async function (req, res, next) { } try { - const accessToken = await userService.refreshToken(Number(userId), refreshToken); + const accessToken = await userService.refreshToken( + Number(userId), + refreshToken + ); return res.status(200).json({ accessToken }); } catch (err) { From a7021e0d38fb9a66d062c7ad7e9b3f3a1da80616 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 18:16:16 +0900 Subject: [PATCH 105/130] feat: add onDelete Cascade --- mission_9/prisma/schema.prisma | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mission_9/prisma/schema.prisma b/mission_9/prisma/schema.prisma index dd324ea23..7702d7a5c 100644 --- a/mission_9/prisma/schema.prisma +++ b/mission_9/prisma/schema.prisma @@ -20,7 +20,7 @@ model Product { description String price Int tags String[] - user User @relation(fields: [userId], references: [id]) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -33,7 +33,7 @@ model Article { id Int @id @default(autoincrement()) title String content String - user User @relation(fields: [userId], references: [id]) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -45,7 +45,7 @@ model Comment { id Int @id @default(autoincrement()) name String content String - user User @relation(fields: [userId], references: [id]) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt From c2be636d6f7d24fa9340686ad8280ccbf3757606 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 18:16:42 +0900 Subject: [PATCH 106/130] feat: hide console message --- mission_9/jest.config.cjs | 18 +++++++++++------- mission_9/src/test/setup.ts | 4 ++++ 2 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 mission_9/src/test/setup.ts diff --git a/mission_9/jest.config.cjs b/mission_9/jest.config.cjs index 395ed16ba..870f23e3f 100644 --- a/mission_9/jest.config.cjs +++ b/mission_9/jest.config.cjs @@ -1,16 +1,20 @@ /** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { - preset: "ts-jest/presets/default-esm", + // preset: "ts-jest/presets/default-esm", // transform을 명시적으로 사용하기 위해 주석 처리 또는 삭제 + transform: { + "^.+\\.tsx?$": [ + "ts-jest", + { + useESM: true, + }, + ], + }, testEnvironment: "node", - /* globals: { - "ts-jest": { - useESM: true, - }, - }, */ moduleNameMapper: { "^(\\.{1,2}/.*)\\.js$": "$1", }, - extensionsToTreatAsEsm: [".ts", ".tsx"], + extensionsToTreatAsEsm: [".ts"], moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], testMatch: ["/src/**/*.test.ts"], + setupFilesAfterEnv: ["/src/test/setup.ts"], }; diff --git a/mission_9/src/test/setup.ts b/mission_9/src/test/setup.ts new file mode 100644 index 000000000..a80cd98d9 --- /dev/null +++ b/mission_9/src/test/setup.ts @@ -0,0 +1,4 @@ +import { jest } from '@jest/globals'; + +jest.spyOn(console, "error").mockImplementation(() => {}); +jest.spyOn(console, "log").mockImplementation(() => {}); \ No newline at end of file From 9aa3579a3b0d7de5729d5fbb7a618a347d08924a Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 18:17:07 +0900 Subject: [PATCH 107/130] feat: add test files --- .../src/test/integration/article-auth.test.ts | 169 ++++++++++++++++++ .../test/integration/article-auth.test.ts.no | 3 - .../test/integration/article-noauth.test.ts | 58 ++++-- .../src/test/integration/product-auth.test.ts | 169 ++++++++++++++++++ .../test/integration/product-auth.test.ts.no | 3 - .../test/integration/product-noauth.test.ts | 84 +++++++++ .../integration/product-noauth.test.ts.no | 3 - .../src/test/integration/user.test.js.no | 3 - mission_9/src/test/integration/user.test.ts | 43 +++++ mission_9/src/test/util/getAuthToken.ts | 14 ++ 10 files changed, 525 insertions(+), 24 deletions(-) create mode 100644 mission_9/src/test/integration/article-auth.test.ts delete mode 100644 mission_9/src/test/integration/article-auth.test.ts.no create mode 100644 mission_9/src/test/integration/product-auth.test.ts delete mode 100644 mission_9/src/test/integration/product-auth.test.ts.no create mode 100644 mission_9/src/test/integration/product-noauth.test.ts delete mode 100644 mission_9/src/test/integration/product-noauth.test.ts.no delete mode 100644 mission_9/src/test/integration/user.test.js.no create mode 100644 mission_9/src/test/integration/user.test.ts create mode 100644 mission_9/src/test/util/getAuthToken.ts diff --git a/mission_9/src/test/integration/article-auth.test.ts b/mission_9/src/test/integration/article-auth.test.ts new file mode 100644 index 000000000..81c8ac2d0 --- /dev/null +++ b/mission_9/src/test/integration/article-auth.test.ts @@ -0,0 +1,169 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; +import { getAuthToken } from "../util/getAuthToken.js"; + +const prisma = new PrismaClient(); + +let authToken: string; +let userId: number; +let articleId: number; +let commentId: number; + +const mockUser = { + email: "article-auth-user@test.com", + nickname: "test-auth", + password: "password123", +}; + +const mockArticle = { + title: "Auth Test Article", + content: "This is the content of the auth test article.", +}; + +const mockComment = { + name: "test-author", + content: "Example auth comment", +}; + +beforeAll(async () => { + // Ensure user does not exist + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + await request(app).post("/users").send(mockUser); + authToken = await getAuthToken(mockUser.email, mockUser.password); + const user = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + userId = user!.id; + + const articleResponse = await request(app) + .post("/articles") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockArticle, userId }); + articleId = articleResponse.body.id; + + const commentResponse = await request(app) + .post(`/articles/${articleId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockComment, userId }); + commentId = commentResponse.body.id; +}); + +afterAll(async () => { + await prisma.user.delete({ where: { id: userId } }); + authToken = ""; +}); + +describe("Article Integration Test (Auth)", () => { + describe("POST /articles", () => { + it("should create another article and return its properties", async () => { + const anotherMockArticle = { + title: "Another New Article", + content: "This is another article.", + }; + + const response = await request(app) + .post("/articles") + .set("Authorization", `Bearer ${authToken}`) + .send(anotherMockArticle) + .expect(201); + expect(response.body).toEqual( + expect.objectContaining({ id: expect.any(Number) }) + ); + await prisma.article.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /articles/:id", () => { + it("should update a specific article by ID", async () => { + const updatedData = { + title: "Modified Title", + }; + + const response = await request(app) + .patch(`/articles/${articleId}`) + .set("Authorization", `Bearer ${authToken}`) + .send(updatedData) + .expect(200); + + expect(response.body).toEqual( + expect.objectContaining({ id: articleId, title: updatedData.title }) + ); + }); + }); + + describe("DELETE /articles/:id", () => { + it("should delete a specific article by ID", async () => { + const tempArticleRes = await request(app) + .post("/articles") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockArticle, title: "To Be Deleted" }); + const tempArticleId = tempArticleRes.body.id; + + const response = await request(app) + .delete(`/articles/${tempArticleId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempArticleId); + }); + }); + + describe("POST /articles/:id/comments", () => { + it("should post another comment to a specific article", async () => { + const anotherMockComment = { + name: "another-author", + content: "Another example comment", + }; + + const response = await request(app) + .post(`/articles/${articleId}/comments`) + .send(anotherMockComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(201); + + expect(response.body).toHaveProperty("id"); + await prisma.comment.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /articles/:id/comments/:cid", () => { + it("should update a specific comment by ID", async () => { + const updatedComment = { + name: "updated-author", + content: "Updated comment content", + }; + + const response = await request(app) + .patch(`/articles/${articleId}/comments/${commentId}`) + .send(updatedComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("content", updatedComment.content); + }); + }); + + describe("DELETE /articles/:id/comments/:cid", () => { + it("should delete a specific comment by ID", async () => { + const tempCommentRes = await request(app) + .post(`/articles/${articleId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ name: "temp-user", content: "to be deleted" }); + const tempCommentId = tempCommentRes.body.id; + + const response = await request(app) + .delete(`/articles/${articleId}/comments/${tempCommentId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempCommentId); + }); + }); +}); diff --git a/mission_9/src/test/integration/article-auth.test.ts.no b/mission_9/src/test/integration/article-auth.test.ts.no deleted file mode 100644 index e002ddfb6..000000000 --- a/mission_9/src/test/integration/article-auth.test.ts.no +++ /dev/null @@ -1,3 +0,0 @@ -describe('Article Integration Test (Auth)', () => { - // Placeholder for future authenticated article tests -}); \ No newline at end of file diff --git a/mission_9/src/test/integration/article-noauth.test.ts b/mission_9/src/test/integration/article-noauth.test.ts index 30561c29d..bccb9fb11 100644 --- a/mission_9/src/test/integration/article-noauth.test.ts +++ b/mission_9/src/test/integration/article-noauth.test.ts @@ -1,19 +1,56 @@ -import { jest } from "@jest/globals"; -import requeset from "supertest"; +import request from "supertest"; import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); +let articleId: number; +let userId: number; + +const mockUser = { + email: "article-noauth-user@test.com", + nickname: "test-noauth", + password: "password123", +}; + +beforeAll(async () => { + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + // Create user + const userResponse = await request(app).post("/users").send(mockUser); + userId = userResponse.body.userId; + + // Create article + const article = await prisma.article.create({ + data: { + title: "Test Article", + content: "Test Content", + userId: userId, + }, + }); + articleId = article.id; +}); + +afterAll(async () => { + // Clean up + await prisma.user.delete({ where: { id: userId } }); +}); describe("Article Integration Test (No Auth)", () => { describe("GET /articles", () => { it("should return a list of articles", async () => { - const response = await requeset(app).get("/articles").expect(200); + const response = await request(app).get("/articles").expect(200); expect(Array.isArray(response.body)).toBe(true); }); }); describe("GET /articles/:id", () => { it("should return a specific article by ID", async () => { - const articleId = 1; - const response = await requeset(app) + const response = await request(app) .get(`/articles/${articleId}`) .expect(200); @@ -22,24 +59,21 @@ describe("Article Integration Test (No Auth)", () => { it("should return 404 for non-existing article", async () => { const nonExistingId = 9999; - await requeset(app).get(`/articles/${nonExistingId}`).expect(404); + await request(app).get(`/articles/${nonExistingId}`).expect(404); }); }); describe("GET /articles/:id/comments", () => { it("should return comments for a specific article", async () => { - const articleId = 1; // Example article ID - const response = await requeset(app) + const response = await request(app) .get(`/articles/${articleId}/comments`) .expect(200); expect(Array.isArray(response.body.comments)).toBe(true); }); it("should return 404 for comments of non-existing article", async () => { - const nonExistingId = 9999; // Example non-existing article ID - await requeset(app) - .get(`/articles/${nonExistingId}/comments`) - .expect(404); + const nonExistingId = 9999; + await request(app).get(`/articles/${nonExistingId}/comments`).expect(404); }); }); }); diff --git a/mission_9/src/test/integration/product-auth.test.ts b/mission_9/src/test/integration/product-auth.test.ts new file mode 100644 index 000000000..ed556c171 --- /dev/null +++ b/mission_9/src/test/integration/product-auth.test.ts @@ -0,0 +1,169 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; +import { getAuthToken } from "../util/getAuthToken.js"; + +const prisma = new PrismaClient(); + +let authToken: string; +let userId: number; +let productId: number; +let commentId: number; + +const mockUser = { + email: "product-auth-user@test.com", + nickname: "test-product-auth", + password: "password123", +}; + +const mockProduct = { + name: "Auth Test Product", + description: "This is an auth test product.", + price: 50000, + tags: [], +}; + +const mockComment = { + name: "product-comment-author", + content: "Example product auth comment", +}; + +beforeAll(async () => { + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + await request(app).post("/users").send(mockUser); + authToken = await getAuthToken(mockUser.email, mockUser.password); + const user = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + userId = user!.id; + + const productResponse = await request(app) + .post("/products") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockProduct, userId }); + productId = productResponse.body.id; + + const commentResponse = await request(app) + .post(`/products/${productId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockComment, userId }); + commentId = commentResponse.body.id; +}); + +afterAll(async () => { + await prisma.user.delete({ where: { id: userId } }); + authToken = ""; +}); + +describe("Product Integration Test (Auth)", () => { + describe("POST /products", () => { + it("should upload another product and return its properties", async () => { + const anotherMockProduct = { + name: "Another Auth Product", + description: "Another one.", + price: 100, + tags: ["new"], + }; + + const response = await request(app) + .post("/products") + .set("Authorization", `Bearer ${authToken}`) + .send(anotherMockProduct) + .expect(201); + expect(response.body).toEqual( + expect.objectContaining({ id: expect.any(Number) }) + ); + await prisma.product.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /products/:id", () => { + it("should update a specific product by ID", async () => { + const updatedData = { + price: 9999, + }; + + const response = await request(app) + .patch(`/products/${productId}`) + .send(updatedData) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("price", updatedData.price); + }); + }); + + describe("DELETE /products/:id", () => { + it("should delete a specific product by ID", async () => { + const tempProductRes = await request(app) + .post("/products") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockProduct, name: "To Be Deleted" }); + const tempProductId = tempProductRes.body.id; + + const response = await request(app) + .delete(`/products/${tempProductId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempProductId); + }); + }); + + describe("POST /products/:id/comments", () => { + it("should post another comment to a specific product", async () => { + const anotherMockComment = { + name: "another-product-commenter", + content: "Another product comment", + }; + + const response = await request(app) + .post(`/products/${productId}/comments`) + .send(anotherMockComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(201); + + expect(response.body).toHaveProperty("id"); + await prisma.comment.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /products/:id/comments/:cid", () => { + it("should update a specific comment by ID", async () => { + const updatedComment = { + name: "updated-product-commenter", + content: "Updated product comment", + }; + const response = await request(app) + .patch(`/products/${productId}/comments/${commentId}`) + .send(updatedComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("content", updatedComment.content); + }); + }); + + describe("DELETE /products/:id/comments/:cid", () => { + it("should delete a specific comment by ID", async () => { + const tempCommentRes = await request(app) + .post(`/products/${productId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ name: "temp-user", content: "to be deleted" }); + const tempCommentId = tempCommentRes.body.id; + + const response = await request(app) + .delete(`/products/${productId}/comments/${tempCommentId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempCommentId); + }); + }); +}); diff --git a/mission_9/src/test/integration/product-auth.test.ts.no b/mission_9/src/test/integration/product-auth.test.ts.no deleted file mode 100644 index e002ddfb6..000000000 --- a/mission_9/src/test/integration/product-auth.test.ts.no +++ /dev/null @@ -1,3 +0,0 @@ -describe('Article Integration Test (Auth)', () => { - // Placeholder for future authenticated article tests -}); \ No newline at end of file diff --git a/mission_9/src/test/integration/product-noauth.test.ts b/mission_9/src/test/integration/product-noauth.test.ts new file mode 100644 index 000000000..51ac29c4d --- /dev/null +++ b/mission_9/src/test/integration/product-noauth.test.ts @@ -0,0 +1,84 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; + +const mockUser = { + email: "test@example.com", + nickname: "test", + password: "password123", +}; + +let productId: number; +let userId: number; + +const prisma = new PrismaClient(); + +beforeAll(async () => { + // Delete user if it exists to ensure a clean slate + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + const response = await request(app).post("/users").send(mockUser); + userId = response.body.userId; + + const res = await prisma.product.create({ + data: { + name: "Test Product", + description: "Test Product Desc", + price: 10010, + userId: userId, + }, + }); + + productId = res.id; +}); + +afterAll(async () => { + await prisma.user.deleteMany({ + where: { + email: mockUser.email, + }, + }); +}); + +describe("Product Integration Test (No Auth)", () => { + describe("GET /products", () => { + it("should return a list of products", async () => { + const response = await request(app).get("/products").expect(200); + expect(Array.isArray(response.body)).toBe(true); + }); + }); + + describe("GET /products/:id", () => { + it("should return a specific product by ID", async () => { + const response = await request(app) + .get(`/products/${productId}`) + .expect(200); + + expect(response.body).toHaveProperty("id"); + }); + + it("should return 404 for non-existing product", async () => { + const nonExistingId = 9999; + await request(app).get(`/products/${nonExistingId}`).expect(404); + }); + }); + + describe("GET /products/:id/comments", () => { + it("should return comments for a specific product", async () => { + const response = await request(app) + .get(`/products/${productId}/comments`) + .expect(200); + expect(Array.isArray(response.body.comments)).toBe(true); + }); + + it("should return 404 for comments of non-existing product", async () => { + const nonExistingId = 9999; + await request(app).get(`/products/${nonExistingId}/comments`).expect(404); + }); + }); +}); diff --git a/mission_9/src/test/integration/product-noauth.test.ts.no b/mission_9/src/test/integration/product-noauth.test.ts.no deleted file mode 100644 index caecb73b7..000000000 --- a/mission_9/src/test/integration/product-noauth.test.ts.no +++ /dev/null @@ -1,3 +0,0 @@ -describe('Product Integration Test (No Auth)', () => { - // Placeholder for future authenticated article tests -}); \ No newline at end of file diff --git a/mission_9/src/test/integration/user.test.js.no b/mission_9/src/test/integration/user.test.js.no deleted file mode 100644 index 02b38cb3f..000000000 --- a/mission_9/src/test/integration/user.test.js.no +++ /dev/null @@ -1,3 +0,0 @@ -describe('User Integration Test', () => { - // Placeholder for future authenticated article tests -}); \ No newline at end of file diff --git a/mission_9/src/test/integration/user.test.ts b/mission_9/src/test/integration/user.test.ts new file mode 100644 index 000000000..dde9b3e11 --- /dev/null +++ b/mission_9/src/test/integration/user.test.ts @@ -0,0 +1,43 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { getAuthToken } from "../util/getAuthToken.js"; +import { PrismaClient } from "@prisma/client"; + +const mockUser = { + email: "testtest@example.com", + nickname: "test", + password: "password123", +}; + +const prisma = new PrismaClient(); + +afterAll(async () => { + await prisma.user.deleteMany({ + where: { + email: mockUser.email, + }, + }); +}); + +describe("User Integration Test", () => { + describe("POST /users", () => { + it("should return a id of user newly created", async () => { + const response = await request(app) + .post("/users") + .send(mockUser) + .expect(200); + expect(response.body).toHaveProperty("userId"); + }); + + it("should return 400 status code", async () => { + const response = await request(app).post("/users").send({}).expect(400); + }); + }); + + describe("POST /login", () => { + it("should return a string of accessToken", async () => { + const accessToken = await getAuthToken(); + expect(typeof accessToken).toBe("string"); + }); + }); +}); diff --git a/mission_9/src/test/util/getAuthToken.ts b/mission_9/src/test/util/getAuthToken.ts new file mode 100644 index 000000000..34b1ff8be --- /dev/null +++ b/mission_9/src/test/util/getAuthToken.ts @@ -0,0 +1,14 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; + +export const getAuthToken = async () => { + const userData = { + email: "user1@example.com", + password: "password123", + }; + + const response = await request(app).post("/login").send(userData).expect(200); + + const { accessToken } = response.body; + return accessToken; +}; From d94fb3f29528948c07a193cc26ea4ec56f6bc040 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 18:19:46 +0900 Subject: [PATCH 108/130] fix --- mission_9/src/test/integration/user.test.ts | 2 +- mission_9/src/test/util/getAuthToken.ts | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mission_9/src/test/integration/user.test.ts b/mission_9/src/test/integration/user.test.ts index dde9b3e11..483657353 100644 --- a/mission_9/src/test/integration/user.test.ts +++ b/mission_9/src/test/integration/user.test.ts @@ -36,7 +36,7 @@ describe("User Integration Test", () => { describe("POST /login", () => { it("should return a string of accessToken", async () => { - const accessToken = await getAuthToken(); + const accessToken = await getAuthToken(mockUser.email, mockUser.password); expect(typeof accessToken).toBe("string"); }); }); diff --git a/mission_9/src/test/util/getAuthToken.ts b/mission_9/src/test/util/getAuthToken.ts index 34b1ff8be..ac05de4e2 100644 --- a/mission_9/src/test/util/getAuthToken.ts +++ b/mission_9/src/test/util/getAuthToken.ts @@ -1,10 +1,12 @@ import request from "supertest"; import { httpServer as app } from "../../app.js"; -export const getAuthToken = async () => { +export const getAuthToken = async (email: string, password: string) => { const userData = { - email: "user1@example.com", - password: "password123", + /* email: "user1@example.com", + password: "password123", */ + email, + password, }; const response = await request(app).post("/login").send(userData).expect(200); From 2fd4077f92a40cc911b8e2f9aa6b953f03f41957 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 18:31:32 +0900 Subject: [PATCH 109/130] feat: add "@jest/globals" package --- mission_9/package-lock.json | 158 +----------------------------------- mission_9/package.json | 1 + 2 files changed, 2 insertions(+), 157 deletions(-) diff --git a/mission_9/package-lock.json b/mission_9/package-lock.json index 799db1783..e4a66982a 100644 --- a/mission_9/package-lock.json +++ b/mission_9/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@jest/globals": "^30.2.0", "@prisma/client": "^6.13.0", "bcrypt": "^6.0.0", "cookie-parser": "^1.4.7", @@ -45,7 +46,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -60,7 +60,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -70,7 +69,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -101,7 +99,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.5", @@ -118,7 +115,6 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.2", @@ -135,7 +131,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -145,7 +140,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -159,7 +153,6 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -177,7 +170,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -187,7 +179,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -197,7 +188,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -207,7 +197,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -217,7 +206,6 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", @@ -231,7 +219,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.5" @@ -247,7 +234,6 @@ "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -260,7 +246,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -273,7 +258,6 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" @@ -286,7 +270,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -302,7 +285,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -318,7 +300,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -331,7 +312,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -344,7 +324,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -360,7 +339,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -373,7 +351,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -386,7 +363,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -399,7 +375,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -412,7 +387,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -425,7 +399,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -438,7 +411,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -454,7 +426,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -470,7 +441,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -486,7 +456,6 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -501,7 +470,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -520,7 +488,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -1009,7 +976,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, "license": "ISC", "dependencies": { "camelcase": "^5.3.1", @@ -1026,7 +992,6 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1102,7 +1067,6 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", - "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -1112,7 +1076,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", - "dev": true, "license": "MIT", "dependencies": { "@jest/fake-timers": "30.2.0", @@ -1128,7 +1091,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", - "dev": true, "license": "MIT", "dependencies": { "expect": "30.2.0", @@ -1142,7 +1104,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0" @@ -1155,7 +1116,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -1173,7 +1133,6 @@ "version": "30.1.0", "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", - "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -1183,7 +1142,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -1199,7 +1157,6 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -1256,7 +1213,6 @@ "version": "30.0.5", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", - "dev": true, "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.34.0" @@ -1269,7 +1225,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -1332,7 +1287,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -1359,7 +1313,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", - "dev": true, "license": "MIT", "dependencies": { "@jest/pattern": "30.0.1", @@ -1378,7 +1331,6 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -1389,7 +1341,6 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -1400,7 +1351,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1410,14 +1360,12 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1475,7 +1423,6 @@ "version": "0.2.9", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" @@ -1573,14 +1520,12 @@ "version": "0.34.41", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", - "dev": true, "license": "MIT" }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" @@ -1590,7 +1535,6 @@ "version": "13.0.5", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1" @@ -1779,14 +1723,12 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" @@ -1796,7 +1738,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" @@ -1923,7 +1864,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, "license": "MIT" }, "node_modules/@types/superagent": { @@ -1954,7 +1894,6 @@ "version": "17.0.35", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", - "dev": true, "license": "MIT", "dependencies": { "@types/yargs-parser": "*" @@ -1964,14 +1903,12 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, "license": "MIT" }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, "license": "ISC" }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { @@ -2289,7 +2226,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -2305,7 +2241,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -2325,7 +2260,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -2371,7 +2305,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", - "dev": true, "license": "BSD-3-Clause", "workspaces": [ "test/babel-8" @@ -2404,7 +2337,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -2448,7 +2380,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/base64id": { @@ -2464,7 +2395,6 @@ "version": "2.8.28", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.28.tgz", "integrity": "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==", - "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -2518,7 +2448,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -2531,7 +2460,6 @@ "version": "4.28.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2578,7 +2506,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" @@ -2701,7 +2628,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -2711,7 +2637,6 @@ "version": "1.0.30001755", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001755.tgz", "integrity": "sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2732,7 +2657,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -2775,7 +2699,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", - "dev": true, "funding": [ { "type": "github", @@ -2904,7 +2827,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -2917,7 +2839,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/combined-stream": { @@ -2947,7 +2868,6 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, "license": "MIT" }, "node_modules/concat-stream": { @@ -3007,7 +2927,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -3242,7 +3161,6 @@ "version": "1.5.254", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.254.tgz", "integrity": "sha512-DcUsWpVhv9svsKRxnSCZ86SjD+sp32SGidNB37KpqXJncp1mfUgKbHvBomE89WJDbfVKw1mdv5+ikrvd43r+Bg==", - "dev": true, "license": "ISC" }, "node_modules/emittery": { @@ -3474,7 +3392,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -3490,7 +3407,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3500,7 +3416,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -3564,7 +3479,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/expect-utils": "30.2.0", @@ -3700,7 +3614,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, "license": "MIT" }, "node_modules/fast-safe-stringify": { @@ -3714,7 +3627,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" @@ -3724,7 +3636,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -3754,7 +3665,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -3861,7 +3771,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, "license": "ISC" }, "node_modules/fsevents": { @@ -3891,7 +3800,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3935,7 +3843,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.0.0" @@ -4034,7 +3941,6 @@ "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/handlebars": { @@ -4063,7 +3969,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4187,7 +4092,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -4198,7 +4102,6 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -4251,7 +4154,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -4287,7 +4189,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=8" @@ -4297,7 +4198,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", @@ -4314,7 +4214,6 @@ "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4546,7 +4445,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", - "dev": true, "license": "MIT", "dependencies": { "@jest/diff-sequences": "30.0.1", @@ -4611,7 +4509,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -4650,7 +4547,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", - "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -4666,7 +4562,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -4687,7 +4582,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -4720,7 +4614,6 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", - "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -4832,7 +4725,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -4865,7 +4757,6 @@ "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4878,7 +4769,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -4896,7 +4786,6 @@ "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": ">=12" @@ -4960,7 +4849,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -4977,7 +4865,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -5003,14 +4890,12 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "3.14.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -5024,7 +4909,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -5044,7 +4928,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -5129,7 +5012,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -5191,7 +5073,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -5237,7 +5118,6 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" @@ -5277,7 +5157,6 @@ "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/methods": { @@ -5294,7 +5173,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -5482,7 +5360,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, "license": "MIT" }, "node_modules/negotiator": { @@ -5532,21 +5409,18 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true, "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5670,7 +5544,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -5683,7 +5556,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -5699,7 +5571,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5780,7 +5651,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5790,7 +5660,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5863,14 +5732,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -5883,7 +5750,6 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -5918,7 +5784,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -5933,7 +5798,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -6068,7 +5932,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, "license": "MIT" }, "node_modules/readable-stream": { @@ -6126,7 +5989,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6187,7 +6049,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6335,7 +6196,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -6348,7 +6208,6 @@ "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" @@ -6514,14 +6373,12 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" @@ -6769,7 +6626,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -6782,7 +6638,6 @@ "version": "0.11.11", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", - "dev": true, "license": "MIT", "dependencies": { "@pkgr/core": "^0.2.9" @@ -6798,7 +6653,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", @@ -6813,7 +6667,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -6825,7 +6678,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -6846,7 +6698,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -6869,14 +6720,12 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -7004,7 +6853,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -7125,7 +6973,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", - "dev": true, "funding": [ { "type": "opencollective", @@ -7195,7 +7042,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" @@ -7329,7 +7175,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", @@ -7383,7 +7228,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, "license": "ISC" }, "node_modules/yargs": { diff --git a/mission_9/package.json b/mission_9/package.json index a33634533..dc56f1f9f 100644 --- a/mission_9/package.json +++ b/mission_9/package.json @@ -13,6 +13,7 @@ "license": "ISC", "description": "", "dependencies": { + "@jest/globals": "^30.2.0", "@prisma/client": "^6.13.0", "bcrypt": "^6.0.0", "cookie-parser": "^1.4.7", From 62803887cb4800395136126540d555b1561c7d58 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 17 Nov 2025 19:10:29 +0900 Subject: [PATCH 110/130] feat: add additional test --- mission_9/src/test/unit/product.test.ts | 46 ++++++++++++++++++++++ mission_9/src/test/unit/product.test.ts.no | 3 -- 2 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 mission_9/src/test/unit/product.test.ts delete mode 100644 mission_9/src/test/unit/product.test.ts.no diff --git a/mission_9/src/test/unit/product.test.ts b/mission_9/src/test/unit/product.test.ts new file mode 100644 index 000000000..55dff3aed --- /dev/null +++ b/mission_9/src/test/unit/product.test.ts @@ -0,0 +1,46 @@ +import { jest } from "@jest/globals"; + +const mockCreateProductFunction = jest.fn(); + +jest.unstable_mockModule("../../repository/productRepository.js", () => ({ + createProduct: mockCreateProductFunction, +})); + +const { createProduct: createProductService } = await import( + "../../services/productService.js" +); + +describe("Product Service Unit Test", () => { + describe("createProduct", () => { + const mockCreateProductRepo = mockCreateProductFunction; + + afterEach(() => { + mockCreateProductRepo.mockClear(); + }); + + it("should call repository and return the created product", async () => { + const mockProductData = { + userId: 1, + name: "Test Product", + description: "This is a test product.", + price: 10000, + tags: ["test"], + }; + + const mockCreatedProduct = { + id: 123, + ...mockProductData, + createdAt: new Date(), + updatedAt: new Date(), + }; + + mockCreateProductRepo.mockResolvedValue(mockCreatedProduct); + + const result = await createProductService(mockProductData); + + expect(mockCreateProductRepo).toHaveBeenCalledTimes(1); + expect(mockCreateProductRepo).toHaveBeenCalledWith(mockProductData); + expect(result).toEqual(mockCreatedProduct); + }); + }); +}); \ No newline at end of file diff --git a/mission_9/src/test/unit/product.test.ts.no b/mission_9/src/test/unit/product.test.ts.no deleted file mode 100644 index 40bbac122..000000000 --- a/mission_9/src/test/unit/product.test.ts.no +++ /dev/null @@ -1,3 +0,0 @@ -describe('Product Service Unit Test', () => { - // Placeholder for future authenticated article tests -}); \ No newline at end of file From 0b2f789d7076b891fea1c17b7b2a5eebfa886ac4 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 24 Nov 2025 14:08:33 +0900 Subject: [PATCH 111/130] feat: update .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 12ac64720..0a0083c22 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ node_modules/ -.DS_Store \ No newline at end of file +.DS_Store +.env +migrations/ \ No newline at end of file From dfb71da6cc5f5e90c0658e840686a97c9def32f7 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 24 Nov 2025 14:09:09 +0900 Subject: [PATCH 112/130] feat: add .env.sample file for environment variable management --- .env.sample | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .env.sample diff --git a/.env.sample b/.env.sample new file mode 100644 index 000000000..c59da6fec --- /dev/null +++ b/.env.sample @@ -0,0 +1,2 @@ +JWT_SECRET="your-super-secret-key" +DATABASE_URL="postgresql://userid:passwd@localhost:5432/pandamarket" \ No newline at end of file From 25e255fc4f8cfeef8e7dc097851e67fb27da98a7 Mon Sep 17 00:00:00 2001 From: intwocave Date: Mon, 24 Nov 2025 14:48:17 +0900 Subject: [PATCH 113/130] chore: copy mission_9 to mission_10 --- mission_10/.env.sample | 2 + mission_10/.gitignore | 10 + mission_10/coverage/clover.xml | 6 + mission_10/coverage/coverage-final.json | 1 + mission_10/coverage/lcov-report/base.css | 224 + .../coverage/lcov-report/block-navigation.js | 87 + mission_10/coverage/lcov-report/favicon.png | Bin 0 -> 445 bytes mission_10/coverage/lcov-report/index.html | 101 + mission_10/coverage/lcov-report/prettify.css | 1 + mission_10/coverage/lcov-report/prettify.js | 2 + .../lcov-report/sort-arrow-sprite.png | Bin 0 -> 138 bytes mission_10/coverage/lcov-report/sorter.js | 210 + mission_10/coverage/lcov.info | 0 mission_10/env.d.ts | 13 + mission_10/jest.config.cjs | 20 + mission_10/package-lock.json | 7321 +++++++++++++++++ mission_10/package.json | 52 + mission_10/prisma/schema.prisma | 95 + mission_10/prisma/seed.ts | 158 + mission_10/src/app.ts | 59 + mission_10/src/container.ts | 1 + .../src/controller/articleController.ts | 253 + mission_10/src/controller/index.ts | 4 + .../src/controller/notificationController.ts | 61 + .../src/controller/productController.ts | 298 + mission_10/src/controller/userController.ts | 159 + mission_10/src/handler/errorHandler.ts | 12 + mission_10/src/lib/prisma.ts | 5 + mission_10/src/lib/socket.ts | 20 + mission_10/src/main.ts | 6 + mission_10/src/middleware/auth.ts | 173 + mission_10/src/middleware/index.ts | 1 + mission_10/src/middleware/validator.ts | 31 + .../src/repository/articleRepository.ts | 177 + mission_10/src/repository/index.ts | 4 + .../src/repository/notificationRepository.ts | 68 + .../src/repository/productRepository.ts | 235 + mission_10/src/repository/userRepository.ts | 61 + mission_10/src/router/articleRouter.ts | 73 + mission_10/src/router/imageRouter.ts | 19 + mission_10/src/router/index.ts | 5 + mission_10/src/router/notificationRouter.ts | 35 + mission_10/src/router/productRouter.ts | 79 + mission_10/src/router/userRouter.ts | 44 + mission_10/src/services/articleService.ts | 80 + mission_10/src/services/index.ts | 4 + .../src/services/notificationService.ts | 66 + mission_10/src/services/productService.ts | 103 + mission_10/src/services/userService.ts | 121 + .../src/test/integration/article-auth.test.ts | 169 + .../test/integration/article-noauth.test.ts | 79 + .../src/test/integration/product-auth.test.ts | 169 + .../test/integration/product-noauth.test.ts | 84 + mission_10/src/test/integration/user.test.ts | 43 + mission_10/src/test/setup.ts | 4 + mission_10/src/test/unit/product.test.ts | 46 + mission_10/src/test/util/getAuthToken.ts | 16 + mission_10/src/types/article.ts | 54 + mission_10/src/types/auth.d.ts | 5 + mission_10/src/types/express/index.d.ts | 10 + mission_10/src/types/global.ts | 5 + mission_10/src/types/product.ts | 63 + mission_10/src/types/user.ts | 21 + mission_10/test-client.html | 142 + mission_10/tsconfig.json | 49 + 65 files changed, 11519 insertions(+) create mode 100644 mission_10/.env.sample create mode 100644 mission_10/.gitignore create mode 100644 mission_10/coverage/clover.xml create mode 100644 mission_10/coverage/coverage-final.json create mode 100644 mission_10/coverage/lcov-report/base.css create mode 100644 mission_10/coverage/lcov-report/block-navigation.js create mode 100644 mission_10/coverage/lcov-report/favicon.png create mode 100644 mission_10/coverage/lcov-report/index.html create mode 100644 mission_10/coverage/lcov-report/prettify.css create mode 100644 mission_10/coverage/lcov-report/prettify.js create mode 100644 mission_10/coverage/lcov-report/sort-arrow-sprite.png create mode 100644 mission_10/coverage/lcov-report/sorter.js create mode 100644 mission_10/coverage/lcov.info create mode 100644 mission_10/env.d.ts create mode 100644 mission_10/jest.config.cjs create mode 100644 mission_10/package-lock.json create mode 100644 mission_10/package.json create mode 100644 mission_10/prisma/schema.prisma create mode 100644 mission_10/prisma/seed.ts create mode 100644 mission_10/src/app.ts create mode 100644 mission_10/src/container.ts create mode 100644 mission_10/src/controller/articleController.ts create mode 100644 mission_10/src/controller/index.ts create mode 100644 mission_10/src/controller/notificationController.ts create mode 100644 mission_10/src/controller/productController.ts create mode 100644 mission_10/src/controller/userController.ts create mode 100644 mission_10/src/handler/errorHandler.ts create mode 100644 mission_10/src/lib/prisma.ts create mode 100644 mission_10/src/lib/socket.ts create mode 100644 mission_10/src/main.ts create mode 100644 mission_10/src/middleware/auth.ts create mode 100644 mission_10/src/middleware/index.ts create mode 100644 mission_10/src/middleware/validator.ts create mode 100644 mission_10/src/repository/articleRepository.ts create mode 100644 mission_10/src/repository/index.ts create mode 100644 mission_10/src/repository/notificationRepository.ts create mode 100644 mission_10/src/repository/productRepository.ts create mode 100644 mission_10/src/repository/userRepository.ts create mode 100644 mission_10/src/router/articleRouter.ts create mode 100644 mission_10/src/router/imageRouter.ts create mode 100644 mission_10/src/router/index.ts create mode 100644 mission_10/src/router/notificationRouter.ts create mode 100644 mission_10/src/router/productRouter.ts create mode 100644 mission_10/src/router/userRouter.ts create mode 100644 mission_10/src/services/articleService.ts create mode 100644 mission_10/src/services/index.ts create mode 100644 mission_10/src/services/notificationService.ts create mode 100644 mission_10/src/services/productService.ts create mode 100644 mission_10/src/services/userService.ts create mode 100644 mission_10/src/test/integration/article-auth.test.ts create mode 100644 mission_10/src/test/integration/article-noauth.test.ts create mode 100644 mission_10/src/test/integration/product-auth.test.ts create mode 100644 mission_10/src/test/integration/product-noauth.test.ts create mode 100644 mission_10/src/test/integration/user.test.ts create mode 100644 mission_10/src/test/setup.ts create mode 100644 mission_10/src/test/unit/product.test.ts create mode 100644 mission_10/src/test/util/getAuthToken.ts create mode 100644 mission_10/src/types/article.ts create mode 100644 mission_10/src/types/auth.d.ts create mode 100644 mission_10/src/types/express/index.d.ts create mode 100644 mission_10/src/types/global.ts create mode 100644 mission_10/src/types/product.ts create mode 100644 mission_10/src/types/user.ts create mode 100644 mission_10/test-client.html create mode 100644 mission_10/tsconfig.json diff --git a/mission_10/.env.sample b/mission_10/.env.sample new file mode 100644 index 000000000..b572e4204 --- /dev/null +++ b/mission_10/.env.sample @@ -0,0 +1,2 @@ +JWT_SECRET="your-super-secret-key" +DATABASE_URL="postgresql://user:password@localhost:5432/mydatabase" \ No newline at end of file diff --git a/mission_10/.gitignore b/mission_10/.gitignore new file mode 100644 index 000000000..d58e9d958 --- /dev/null +++ b/mission_10/.gitignore @@ -0,0 +1,10 @@ +node_modules +/dist + +# Keep environment variables out of version control +.env + +/generated/prisma +/prisma/migrations + +todo.list \ No newline at end of file diff --git a/mission_10/coverage/clover.xml b/mission_10/coverage/clover.xml new file mode 100644 index 000000000..6ef1353be --- /dev/null +++ b/mission_10/coverage/clover.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/mission_10/coverage/coverage-final.json b/mission_10/coverage/coverage-final.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/mission_10/coverage/coverage-final.json @@ -0,0 +1 @@ +{} diff --git a/mission_10/coverage/lcov-report/base.css b/mission_10/coverage/lcov-report/base.css new file mode 100644 index 000000000..f418035b4 --- /dev/null +++ b/mission_10/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/mission_10/coverage/lcov-report/block-navigation.js b/mission_10/coverage/lcov-report/block-navigation.js new file mode 100644 index 000000000..530d1ed2b --- /dev/null +++ b/mission_10/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selector that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/mission_10/coverage/lcov-report/favicon.png b/mission_10/coverage/lcov-report/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c1525b811a167671e9de1fa78aab9f5c0b61cef7 GIT binary patch literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ Unknown% + Statements + 0/0 +
+ + +
+ Unknown% + Branches + 0/0 +
+ + +
+ Unknown% + Functions + 0/0 +
+ + +
+ Unknown% + Lines + 0/0 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/mission_10/coverage/lcov-report/prettify.css b/mission_10/coverage/lcov-report/prettify.css new file mode 100644 index 000000000..b317a7cda --- /dev/null +++ b/mission_10/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/mission_10/coverage/lcov-report/prettify.js b/mission_10/coverage/lcov-report/prettify.js new file mode 100644 index 000000000..b3225238f --- /dev/null +++ b/mission_10/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/mission_10/coverage/lcov-report/sort-arrow-sprite.png b/mission_10/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed68316eb3f65dec9063332d2f69bf3093bbfab GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc literal 0 HcmV?d00001 diff --git a/mission_10/coverage/lcov-report/sorter.js b/mission_10/coverage/lcov-report/sorter.js new file mode 100644 index 000000000..4ed70ae5a --- /dev/null +++ b/mission_10/coverage/lcov-report/sorter.js @@ -0,0 +1,210 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + + // Try to create a RegExp from the searchValue. If it fails (invalid regex), + // it will be treated as a plain text search + let searchRegex; + try { + searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive + } catch (error) { + searchRegex = null; + } + + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + let isMatch = false; + + if (searchRegex) { + // If a valid regex was created, use it for matching + isMatch = searchRegex.test(row.textContent); + } else { + // Otherwise, fall back to the original plain text search + isMatch = row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()); + } + + row.style.display = isMatch ? '' : 'none'; + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/mission_10/coverage/lcov.info b/mission_10/coverage/lcov.info new file mode 100644 index 000000000..e69de29bb diff --git a/mission_10/env.d.ts b/mission_10/env.d.ts new file mode 100644 index 000000000..f4b3b91de --- /dev/null +++ b/mission_10/env.d.ts @@ -0,0 +1,13 @@ +declare namespace NodeJS { + interface ProcessEnv { + NODE_ENV: "development" | "production"; + PORT?: string; + DATABASE_URL?: string; + /* DB_HOST: string; + DB_PORT: string; + DB_USERNAME: string; + DB_PASSWORD: string; + DB_NAME: string; */ + JWT_SECRET: string; + } +} diff --git a/mission_10/jest.config.cjs b/mission_10/jest.config.cjs new file mode 100644 index 000000000..870f23e3f --- /dev/null +++ b/mission_10/jest.config.cjs @@ -0,0 +1,20 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + // preset: "ts-jest/presets/default-esm", // transform을 명시적으로 사용하기 위해 주석 처리 또는 삭제 + transform: { + "^.+\\.tsx?$": [ + "ts-jest", + { + useESM: true, + }, + ], + }, + testEnvironment: "node", + moduleNameMapper: { + "^(\\.{1,2}/.*)\\.js$": "$1", + }, + extensionsToTreatAsEsm: [".ts"], + moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], + testMatch: ["/src/**/*.test.ts"], + setupFilesAfterEnv: ["/src/test/setup.ts"], +}; diff --git a/mission_10/package-lock.json b/mission_10/package-lock.json new file mode 100644 index 000000000..e4a66982a --- /dev/null +++ b/mission_10/package-lock.json @@ -0,0 +1,7321 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sprint_mission_3", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@jest/globals": "^30.2.0", + "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "dotenv": "^17.2.3", + "express": "^5.1.0", + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "socket.io": "^4.8.1", + "tsx": "^4.20.6" + }, + "devDependencies": { + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.9", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.3", + "@types/express-jwt": "^6.0.4", + "@types/jest": "^30.0.0", + "@types/multer": "^2.0.0", + "@types/node": "^24.3.1", + "@types/socket.io": "^3.0.1", + "@types/supertest": "^6.0.3", + "jest": "^30.2.0", + "prisma": "^6.13.0", + "supertest": "^7.1.4", + "ts-jest": "^29.4.5", + "typescript": "^5.9.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emnapi/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", + "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/core": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", + "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.2.0", + "jest-config": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-resolve-dependencies": "30.2.0", + "jest-runner": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "jest-watcher": "30.2.0", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", + "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "license": "MIT", + "dependencies": { + "expect": "30.2.0", + "jest-snapshot": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", + "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@sinonjs/fake-timers": "^13.0.0", + "@types/node": "*", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", + "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/types": "30.2.0", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", + "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", + "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", + "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/types": "30.2.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", + "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", + "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@prisma/client": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.19.0.tgz", + "integrity": "sha512-QXFT+N/bva/QI2qoXmjBzL7D6aliPffIwP+81AdTGq0FXDoLxLkWivGMawG8iM5B9BKfxLIXxfWWAF6wbuJU6g==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.19.0.tgz", + "integrity": "sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.18.4", + "empathic": "2.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.19.0.tgz", + "integrity": "sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.19.0.tgz", + "integrity": "sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/fetch-engine": "6.19.0", + "@prisma/get-platform": "6.19.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773.tgz", + "integrity": "sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.19.0.tgz", + "integrity": "sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/get-platform": "6.19.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.19.0.tgz", + "integrity": "sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.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", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie-parser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.10.tgz", + "integrity": "sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.5.tgz", + "integrity": "sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-jwt": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-6.0.4.tgz", + "integrity": "sha512-I53KRQ9D0eTA6hVCN9S73iOeprKS3JNWK+Cp2mDPB6uOIkTVpkgSkX394kHQzb5cd0U02I0adRmsMxHk+zX8tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/express-unless": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", + "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express-unless": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.3.tgz", + "integrity": "sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/methods": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", + "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/multer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", + "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/node": { + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/socket.io": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-3.0.1.tgz", + "integrity": "sha512-XSma2FhVD78ymvoxYV4xGXrIH/0EKQ93rR+YR0Y+Kw1xbPzLDCip/UWSejZ08FpxYeYNci/PZPQS9anrvJRqMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "socket.io": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "license": "MIT" + }, + "node_modules/@types/superagent": { + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/supertest": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.3.tgz", + "integrity": "sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", + "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "30.2.0", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", + "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", + "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.28", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.28.tgz", + "integrity": "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "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/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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/c12/node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001755", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001755.tgz", + "integrity": "sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/cjs-module-lexer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz", + "integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz", + "integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.254", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.254.tgz", + "integrity": "sha512-DcUsWpVhv9svsKRxnSCZ86SjD+sp32SGidNB37KpqXJncp1mfUgKbHvBomE89WJDbfVKw1mdv5+ikrvd43r+Bg==", + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-jwt": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.5.1.tgz", + "integrity": "sha512-Dv6QjDLpR2jmdb8M6XQXiCcpEom7mK8TOqnr0/TngDKsG2DHVkO8+XnVxkJVN7BuS1I3OrGw6N8j5DaaGgkDRQ==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "^9", + "express-unless": "^2.1.3", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express-unless": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz", + "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==", + "license": "MIT" + }, + "node_modules/express/node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fast-check/node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "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", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "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", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/formidable": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "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/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "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/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", + "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.2.0", + "@jest/types": "30.2.0", + "import-local": "^3.2.0", + "jest-cli": "30.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", + "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.1.1", + "jest-util": "30.2.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-circus": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", + "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "p-limit": "^3.1.0", + "pretty-format": "30.2.0", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-cli": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", + "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", + "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.2.0", + "@jest/types": "30.2.0", + "babel-jest": "30.2.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-circus": "30.2.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-runner": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "micromatch": "^4.0.8", + "parse-json": "^5.2.0", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-each": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", + "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "jest-util": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", + "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", + "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "micromatch": "^4.0.8", + "walker": "^1.0.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" + } + }, + "node_modules/jest-leak-detector": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", + "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", + "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", + "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", + "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/environment": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-leak-detector": "30.2.0", + "jest-message-util": "30.2.0", + "jest-resolve": "30.2.0", + "jest-runtime": "30.2.0", + "jest-util": "30.2.0", + "jest-watcher": "30.2.0", + "jest-worker": "30.2.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", + "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/globals": "30.2.0", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", + "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "pretty-format": "30.2.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", + "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", + "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.2.0", + "string-length": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", + "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.2.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "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==", + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "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/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/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", + "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "mkdirp": "^0.5.6", + "object-assign": "^4.1.1", + "type-is": "^1.6.18", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "license": "MIT" + }, + "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/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/nypm": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", + "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "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/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "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/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prisma": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.19.0.tgz", + "integrity": "sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.19.0", + "@prisma/engines": "6.19.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", + "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.7.0", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "license": "MIT", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superagent": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz", + "integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.1", + "cookiejar": "^2.1.4", + "debug": "^4.3.7", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.4", + "formidable": "^3.5.4", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supertest": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.4.tgz", + "integrity": "sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^10.2.3" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "license": "BSD-3-Clause" + }, + "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" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-jest": { + "version": "29.4.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.5.tgz", + "integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/mission_10/package.json b/mission_10/package.json new file mode 100644 index 000000000..dc56f1f9f --- /dev/null +++ b/mission_10/package.json @@ -0,0 +1,52 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "NODE_OPTIONS='--experimental-vm-modules' jest --verbose", + "build": "tsc", + "start": "NODE_ENV=production node dist/main.js", + "dev": "tsx watch src/main.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@jest/globals": "^30.2.0", + "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "dotenv": "^17.2.3", + "express": "^5.1.0", + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "socket.io": "^4.8.1", + "tsx": "^4.20.6" + }, + "devDependencies": { + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.9", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.3", + "@types/express-jwt": "^6.0.4", + "@types/jest": "^30.0.0", + "@types/multer": "^2.0.0", + "@types/node": "^24.3.1", + "@types/socket.io": "^3.0.1", + "@types/supertest": "^6.0.3", + "jest": "^30.2.0", + "prisma": "^6.13.0", + "supertest": "^7.1.4", + "ts-jest": "^29.4.5", + "typescript": "^5.9.2" + }, + "prisma": { + "seed": "tsx prisma/seed.ts" + }, + "type": "module" +} diff --git a/mission_10/prisma/schema.prisma b/mission_10/prisma/schema.prisma new file mode 100644 index 000000000..7702d7a5c --- /dev/null +++ b/mission_10/prisma/schema.prisma @@ -0,0 +1,95 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" + // output = "../generated/prisma" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model Product { + id Int @id @default(autoincrement()) + name String + description String + price Int + tags String[] + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] + likedBy LikedProduct[] + notifications Notification[] +} + +model Article { + id Int @id @default(autoincrement()) + title String + content String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] + notifications Notification[] +} + +model Comment { + id Int @id @default(autoincrement()) + name String + content String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int? + Article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) + articleId Int? +} + +model User { + id Int @id @default(autoincrement()) + email String @unique + nickname String + image String? + password String + refreshToken String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Article Article[] + Product Product[] + Comment Comment[] + likedProducts LikedProduct[] + notifications Notification[] +} + +model LikedProduct { + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + product Product @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int + createdAt DateTime @default(now()) + + @@id([userId, productId]) +} + +model Notification { + id Int @id @default(autoincrement()) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + message String + read Boolean @default(false) + createdAt DateTime @default(now()) + article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) + articleId Int? + product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int? +} diff --git a/mission_10/prisma/seed.ts b/mission_10/prisma/seed.ts new file mode 100644 index 000000000..bd79ab898 --- /dev/null +++ b/mission_10/prisma/seed.ts @@ -0,0 +1,158 @@ +import { PrismaClient } from '@prisma/client'; +import bcrypt from 'bcrypt'; + +// initialize Prisma Client +const prisma = new PrismaClient(); + +async function main() { + // create two dummy users + const password = await bcrypt.hash('password123', 10); + const user1 = await prisma.user.create({ + data: { + email: 'user1@example.com', + nickname: 'Alice', + password, + image: 'https://i.pravatar.cc/150?u=user1@example.com', + refreshToken: 'some-refresh-token', + }, + }); + + const user2 = await prisma.user.create({ + data: { + email: 'user2@example.com', + nickname: 'Bob', + password, + image: 'https://i.pravatar.cc/150?u=user2@example.com', + }, + }); + + // create two dummy articles + const article1 = await prisma.article.create({ + data: { + title: 'Prisma is the best ORM', + content: + 'Prisma makes database access easy with an intuitive data model and type-safety.', + userId: user1.id, + }, + }); + + const article2 = await prisma.article.create({ + data: { + title: 'Getting started with Next.js', + content: + 'Next.js is a React framework for building full-stack web applications.', + userId: user2.id, + }, + }); + + // create two dummy products + const product1 = await prisma.product.create({ + data: { + name: 'Laptop', + description: 'A very powerful laptop for all your needs.', + price: 1200, + tags: ['electronics', 'computer'], + userId: user1.id, + }, + }); + + const product2 = await prisma.product.create({ + data: { + name: 'Coffee Mug', + description: 'A mug to hold your favorite beverage.', + price: 15, + tags: ['kitchen', 'home'], + userId: user2.id, + }, + }); + + // create comments + const comment1 = await prisma.comment.create({ + data: { + name: 'Commenter1', + content: 'Great article!', + userId: user2.id, + articleId: article1.id, + }, + }); + + const comment2 = await prisma.comment.create({ + data: { + name: 'Commenter2', + content: 'I love this laptop!', + userId: user1.id, + productId: product1.id, + }, + }); + + const comment3 = await prisma.comment.create({ + data: { + name: 'Commenter3', + content: 'This is a general comment.', + userId: user1.id, + }, + }); + + const comment4 = await prisma.comment.create({ + data: { + name: 'Commenter4', + content: 'This comment is for both an article and a product.', + userId: user2.id, + articleId: article2.id, + productId: product2.id, + }, + }); + + + // create a liked product + const likedProduct = await prisma.likedProduct.create({ + data: { + userId: user1.id, + productId: product2.id, + }, + }); + + // create notifications + const notification1 = await prisma.notification.create({ + data: { + userId: user1.id, + message: 'Your article has a new comment!', + articleId: article1.id, + }, + }); + + const notification2 = await prisma.notification.create({ + data: { + userId: user2.id, + message: 'Your product has a new comment!', + productId: product1.id, + read: true, + }, + }); + + console.log({ + user1, + user2, + article1, + article2, + product1, + product2, + comment1, + comment2, + comment3, + comment4, + likedProduct, + notification1, + notification2, + }); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + // close Prisma Client at the end + await prisma.$disconnect(); + }); \ No newline at end of file diff --git a/mission_10/src/app.ts b/mission_10/src/app.ts new file mode 100644 index 000000000..7c97b396a --- /dev/null +++ b/mission_10/src/app.ts @@ -0,0 +1,59 @@ +import path from "path"; +import http from "http"; + +import express from "express"; +import type { Request, Response, NextFunction } from "express"; +import cors from "cors"; +import cookieParser from "cookie-parser"; +import productRouter from "./router/productRouter.js"; +import articleRouter from "./router/articleRouter.js"; +import imageRouter from "./router/imageRouter.js"; +import notificationRouter from "./router/notificationRouter.js"; +import userRouter from "./router/userRouter.js"; +import { initializeSocket } from "./lib/socket.js"; + +import errorHandler from "./handler/errorHandler.js"; + +const app = express(); +export const httpServer = http.createServer(app); + +// Socket.IO 초기화 +const io = initializeSocket(httpServer); + +io.on("connection", (socket) => { + console.log("A user connected:", socket.id); + + socket.on("join", (userId) => { + console.log(`User ${userId} joined room`); + socket.join(userId); + }); + + socket.on("disconnect", () => { + console.log("User disconnected:", socket.id); + }); +}); + +app.use(express.json()); +app.use( + cors({ + methods: ["GET", "POST", "PUT", "PATCH", "DELETE"], + }) +); +app.use(cookieParser()); + +function logRequest(req: Request, _: Response, next: NextFunction) { + console.log(`[${req.method}] ${req.originalUrl}`); + next(); +} + +// middleware for logging all http request +app.use(logRequest); + +app.use("/products", productRouter); +app.use("/articles", articleRouter); +app.use("/upload", imageRouter); +app.use(notificationRouter); +app.use(userRouter); + +app.use(errorHandler); +app.use("/upload", express.static(path.resolve("uploads"))); diff --git a/mission_10/src/container.ts b/mission_10/src/container.ts new file mode 100644 index 000000000..ba0183f59 --- /dev/null +++ b/mission_10/src/container.ts @@ -0,0 +1 @@ +import prisma from './lib/prisma.js'; \ No newline at end of file diff --git a/mission_10/src/controller/articleController.ts b/mission_10/src/controller/articleController.ts new file mode 100644 index 000000000..2f603387d --- /dev/null +++ b/mission_10/src/controller/articleController.ts @@ -0,0 +1,253 @@ +import * as articleService from "../services/articleService.js"; +import type { RequestHandler } from "express"; + +const createPost: RequestHandler = async function (req, res, next) { + const { title, content } = req.body; + + const userId = req.user ? req.user.userId : null; + if (userId === null) { + const err = new Error("Access token is missing or invalid"); + err.statusCode = 401; + return next(err); + } + + if (!title || !content) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + const article = await articleService.createPost({ userId, title, content }); + res.status(201).json(article); + } catch (err) { + next(err); + } +}; + +const getPosts: RequestHandler = async function (req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search } = req.query; + + try { + const articles = await articleService.getPosts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search: String(search), + }); + + if (articles) res.status(200).json(articles); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with given parameters`; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const getPost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const article = await articleService.getPost({ id: Number(id) }); + + if (article) res.status(200).json(article); + else { + const err = new Error(`Cannot find article with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchPost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + // Columns in model Article + const articleCols = ["title", "content"]; + + // ? + const filteredBody = Object.entries(req.body) + .filter(([key]) => articleCols.includes(key)) + .reduce>((obj, [key, value]) => { + obj[key] = value; + return obj; + }, {}); + + try { + const article = await articleService.patchPost({ + id: Number(id), + ...filteredBody, + }); + + if (article) res.status(200).json(article); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const deletePost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const deleted = await articleService.deletePost({ id: Number(id) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const postComment: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Access token is missing or invalid"); + err.statusCode = 401; + return next(err); + } + + if (!name || !content || !pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + return next(err); + } + + try { + const comment = await articleService.postComment({ + userId, + name, + content, + pid: Number(pid), + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +}; + +const getComments: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + const comments = await articleService.getComments({ + pid: Number(pid), + cursor: Number(cursor), + limit: Number(limit), + }); + + if (comments) + res.status(200).json({ + comments, + nextCursor: + comments.length === Number(limit) ? comments.at(-1)?.id : null, // llm + }); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comments with id ${pid}`; + return next(err); + } +}; + +const patchComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id' and 'cid'"; + return next(err); + } + + const { name, content } = req.body; + if (!name || !content) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid SQL Parameters"; + return next(err); + } + + const comment = await articleService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comment with ID ${pid}`; + return next(err); + } +}; + +const deleteComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await articleService.deleteComment({ cid: Number(cid) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find any comment with ID ${cid}`); + err.statusCode = 404; + return next(err); + } +}; + +export { + createPost, + getPosts, + getPost, + patchPost, + deletePost, + postComment, + getComments, + patchComment, + deleteComment, +}; diff --git a/mission_10/src/controller/index.ts b/mission_10/src/controller/index.ts new file mode 100644 index 000000000..7cee66bc9 --- /dev/null +++ b/mission_10/src/controller/index.ts @@ -0,0 +1,4 @@ +export * from './articleController.js'; +export * from './productController.js'; +export * from './userController.js'; +export * from './notificationController.js'; \ No newline at end of file diff --git a/mission_10/src/controller/notificationController.ts b/mission_10/src/controller/notificationController.ts new file mode 100644 index 000000000..ae5a2b667 --- /dev/null +++ b/mission_10/src/controller/notificationController.ts @@ -0,0 +1,61 @@ +import type { Request, Response, NextFunction } from 'express'; +import notificationService from '../services/notificationService.js'; + +async function getNotifications( + req: Request, + res: Response, + next: NextFunction +) { + try { + const userId = req.user.userId; + const notifications = await notificationService.getUserNotifications(userId); + res.status(200).json(notifications); + } catch (error) { + next(error); + } +} + +async function getUnreadCount( + req: Request, + res: Response, + next: NextFunction +) { + try { + const userId = req.user.userId; + const count = await notificationService.getUnreadNotificationCount(userId); + res.status(200).json({ count }); + } catch (error) { + next(error); + } +} + +async function markAsRead(req: Request, res: Response, next: NextFunction) { + try { + const userId = req.user.userId; + const notificationId = parseInt(req.params.id, 10); + const notification = await notificationService.markNotificationAsRead( + notificationId, + userId + ); + res.status(200).json(notification); + } catch (error) { + next(error); + } +} + +async function markAllAsRead(req: Request, res: Response, next: NextFunction) { + try { + const userId = req.user.userId; + await notificationService.markAllNotificationsAsRead(userId); + res.status(204).send(); + } catch (error) { + next(error); + } +} + +export default { + getNotifications, + getUnreadCount, + markAsRead, + markAllAsRead, +}; diff --git a/mission_10/src/controller/productController.ts b/mission_10/src/controller/productController.ts new file mode 100644 index 000000000..c8bb444a7 --- /dev/null +++ b/mission_10/src/controller/productController.ts @@ -0,0 +1,298 @@ +import * as productService from "../services/productService.js"; +import type { RequestHandler } from "express"; + +const createProduct: RequestHandler = async function createProduct( + req, + res, + next +) { + // destructuring field data from request body + const { name, description, price, tags } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!name || !description || !price || !tags) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Product table + const product = await productService.createProduct({ + userId, + name, + description, + price, + tags, + }); + + res.status(201).json(product); + } catch (err) { + next(err); + } +}; + +const getProducts: RequestHandler = async function (req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search = "" } = req.query; + + try { + const products = await productService.getProducts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search: String(search), + }); + + if (products) res.status(200).json(products); + else { + const err = new Error("Cannot find products"); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const getProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const product = await productService.getProduct({ id }); + + if (product) res.status(200).json(product); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + // Attributes in model Product + const productCols = ["name", "description", "price", "tags"]; + + // Possible improvement? + const filteredBody = Object.entries(req.body) + .filter(([key]) => productCols.includes(key)) + .reduce>((obj, [key, value]) => { + obj[key] = value; + return obj; + }, {}); + + try { + const product = await productService.patchProduct({ id, ...filteredBody }); + + if (product) res.status(200).json(product); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find product with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const deleteProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const deleted = await productService.deleteProduct({ id }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const postComment: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + // validation + if (!name || !content || !pid) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Comment table + const comment = await productService.postComment({ + userId, + pid: Number(pid), + name, + content, + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +}; + +const getComments: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + try { + const comments = await productService.getComments({ + pid: Number(pid), + cursor: cursor ? Number(cursor) : null, + limit: Number(limit), + }); + + // Cursor pagination + const nextCursor = + comments.length > 0 ? comments[comments.length - 1] : null; + + if (comments) + res.status(200).json({ + comments, + nextCursor, + }); + else { + const err = new Error(`Cannot find any comments`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + const { name, content } = req.body; + + if (!pid || !cid || !name || !content) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(`Cannot find any comment with ID ${cid}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const deleteComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await productService.deleteComment({ cid: Number(cid) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${pid}`); + err.statusCode = 404; + return next(err); + } +}; + +const toggleLike: RequestHandler = async function (req, res, next) { + if (!req.user) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!req.params.id) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const userId = req.user.userId; + const productId = parseInt(req.params.id, 10); + + if (isNaN(productId)) { + const err = new Error("Invalid product ID"); + err.statusCode = 400; + return next(err); + } + + const result = await productService.toggleLike(userId, productId); + res.status(200).json(result); + } catch (error) { + next(error); + } +}; + +export { + createProduct, + getProducts, + getProduct, + patchProduct, + deleteProduct, + postComment, + getComments, + patchComment, + deleteComment, + toggleLike, +}; diff --git a/mission_10/src/controller/userController.ts b/mission_10/src/controller/userController.ts new file mode 100644 index 000000000..00b5f5407 --- /dev/null +++ b/mission_10/src/controller/userController.ts @@ -0,0 +1,159 @@ +import * as userService from "../services/userService.js"; +import type { RequestHandler } from "express"; + +// for Creating user +const createUser: RequestHandler = async function (req, res, next) { + const { email, nickname, password } = req.body; + + if (!email || !nickname || !password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const userId = await userService.createUser({ email, nickname, password }); + + return res.status(200).json({ userId }); + } catch (err) { + next(err); + } +}; + +// for Login +const getAccessToken: RequestHandler = async function (req, res, next) { + const { email, password } = req.body; + + if (!email || !password) { + const err = new Error("Email or password is wrong"); + err.statusCode = 404; + return next(err); + } + + try { + const user = await userService.getUser(req.body); + const accessToken = userService.createToken(user); + const refreshToken = userService.createToken(user, "refresh"); + await userService.updateUserInfo(user.id, { refreshToken }); + res.cookie("refreshToken", refreshToken, { + httpOnly: true, + sameSite: "none", + secure: true, + }); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +}; + +const getMyInfo: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + + if (!userId) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + try { + const user = await userService.getUserById(userId); + + return res.status(200).json(user); + } catch (err) { + next(err); + } +}; + +const updateMyInfo: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + const { email, nickname } = req.body; + + if ((!email && !nickname) || userId === null) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const updatedUser = await userService.updateUserInfo(userId, req.body); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +}; + +const updateMyPassword: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + const { password } = req.body; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const updatedUser = await userService.updateUserPassword(userId, password); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +}; + +const getMyProducts: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + try { + const products = await userService.getMyProducts(userId); + + return res.status(200).json(products); + } catch (err) { + next(err); + } +}; + +const getRefreshToken: RequestHandler = async function (req, res, next) { + const userId = req.auth ? req.auth.userId : null; + const refreshToken = req.cookies.refreshToken; + + if (!refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + next(err); + } + + try { + const accessToken = await userService.refreshToken( + Number(userId), + refreshToken + ); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +}; + +export { + createUser, + getAccessToken, + getMyInfo, + updateMyInfo, + updateMyPassword, + getMyProducts, + getRefreshToken, +}; diff --git a/mission_10/src/handler/errorHandler.ts b/mission_10/src/handler/errorHandler.ts new file mode 100644 index 000000000..ed4c35489 --- /dev/null +++ b/mission_10/src/handler/errorHandler.ts @@ -0,0 +1,12 @@ +import type { ErrorRequestHandler } from "express"; + +const errorHandler: ErrorRequestHandler = function (err, req, res, next) { + console.error(`[ERROR] ${err.stack || err.message}`); + + const statusCode = err.statusCode || 500; + const message = err.message || "Internal server error!"; + + res.status(statusCode).json({ message }); +} + +export default errorHandler; \ No newline at end of file diff --git a/mission_10/src/lib/prisma.ts b/mission_10/src/lib/prisma.ts new file mode 100644 index 000000000..b904402d2 --- /dev/null +++ b/mission_10/src/lib/prisma.ts @@ -0,0 +1,5 @@ +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +export default prisma; \ No newline at end of file diff --git a/mission_10/src/lib/socket.ts b/mission_10/src/lib/socket.ts new file mode 100644 index 000000000..6b7195b05 --- /dev/null +++ b/mission_10/src/lib/socket.ts @@ -0,0 +1,20 @@ +import { Server } from 'socket.io'; + +let io: Server; + +export const initializeSocket = (server: any) => { + io = new Server(server, { + cors: { + origin: '*', // In a real application, restrict this to your frontend's URL + methods: ['GET', 'POST'], + }, + }); + return io; +}; + +export const getIO = () => { + if (!io) { + throw new Error('Socket.io not initialized!'); + } + return io; +}; diff --git a/mission_10/src/main.ts b/mission_10/src/main.ts new file mode 100644 index 000000000..ded3928d4 --- /dev/null +++ b/mission_10/src/main.ts @@ -0,0 +1,6 @@ +import "dotenv/config"; +import { httpServer } from "./app.js"; + +const PORT = Number(process.env.PORT) || 3000; + +httpServer.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); diff --git a/mission_10/src/middleware/auth.ts b/mission_10/src/middleware/auth.ts new file mode 100644 index 000000000..0d040e8c6 --- /dev/null +++ b/mission_10/src/middleware/auth.ts @@ -0,0 +1,173 @@ +import type { RequestHandler } from "express"; +import { expressjwt } from "express-jwt"; +import * as articleRepository from "../repository/articleRepository.js"; +import * as productRepository from "../repository/productRepository.js"; + +// 토큰 검증 +const verifyAccessToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + requestProperty: "user", +}); + +// refresh 토큰 검증 +const verifyRefreshToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + getToken: (req) => req.cookies.refreshToken, +}); + +// 게시글 유저 검증 +const verifyArticleAuth: RequestHandler = async (req, res, next) => { + // Get article id + const { id } = req.params; + + // Get article author's id + try { + const article = await articleRepository.getPost({ id: Number(id) }); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + return next(err); + } + + // Call next if valid user + if (req.user && req.user.userId === article.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 유저 검증 +const verifyProductAuth: RequestHandler = async (req, res, next) => { + // Get product id + const { id } = req.params; + + // Get product uploaders's id + try { + const product = await productRepository.getProduct({ id: Number(id) }); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + return next(err); + } + + // Call next if valid user + if (req.user && req.user.userId === product.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 게시글 존재 여부 확인 +const checkArticleExist: RequestHandler = async (req, res, next) => { + const { id } = req.params; + + try { + const article = await articleRepository.getPost({ id: Number(id) }); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + return next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 상품 존재 여부 확인 +const checkProductExist: RequestHandler = async (req, res, next) => { + const { id } = req.params; + + try { + const product = await productRepository.getProduct({ id: Number(id) }); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + return next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 게시글 댓글 유저 검증 +const verifyArticleCommentAuth: RequestHandler = async (req, res, next) => { + const { cid } = req.params; + + if (!cid) { + const err = new Error("Comment id is required"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await articleRepository.getComment({ cid: parseInt(cid) }); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + return next(err); + } + + if (req.user && req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 댓글 유저 검증 +const verifyProductCommentAuth: RequestHandler = async (req, res, next) => { + const { cid } = req.params; + + if (!cid) { + const err = new Error("Comment id is required"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productRepository.getComment({ cid: parseInt(cid) }); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + return next(err); + } + + if (req.user && req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +export default { + verifyAccessToken, + verifyRefreshToken, + verifyArticleAuth, + verifyProductAuth, + checkArticleExist, + checkProductExist, + verifyArticleCommentAuth, + verifyProductCommentAuth, +}; diff --git a/mission_10/src/middleware/index.ts b/mission_10/src/middleware/index.ts new file mode 100644 index 000000000..02584180c --- /dev/null +++ b/mission_10/src/middleware/index.ts @@ -0,0 +1 @@ +export * from './validator.js'; \ No newline at end of file diff --git a/mission_10/src/middleware/validator.ts b/mission_10/src/middleware/validator.ts new file mode 100644 index 000000000..48cf69245 --- /dev/null +++ b/mission_10/src/middleware/validator.ts @@ -0,0 +1,31 @@ +import type { RequestHandler } from "express"; + +// Verify required parameters are okay +const validateProduct: RequestHandler = async function (req, res, next) { + const { name, description, price, tags } = req.body; + + // validation logic (possible improvements with Zod library in the future) + if (!name || !description || !price || !tags) + return res.status(400).json({ message: "Missing required fields" }); + + if (isNaN(price)) + return res.status(400).json({ message: "Price must be a number" }); + + if (!Array.isArray(tags) || !tags.every((tag) => typeof tag === "string")) + return res.status(400).json({ message: "Tags must be an array of string" }); + + next(); +}; + +// Verify required parameters are okay +const validateArticle: RequestHandler = async function (req, res, next) { + const { title, content } = req.body; + + // validation + if (!title || !content) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + next(); +}; + +export { validateProduct, validateArticle }; diff --git a/mission_10/src/repository/articleRepository.ts b/mission_10/src/repository/articleRepository.ts new file mode 100644 index 000000000..a3a79f670 --- /dev/null +++ b/mission_10/src/repository/articleRepository.ts @@ -0,0 +1,177 @@ +import prisma from "../lib/prisma.js"; +import type { + CreatePostDTO, + GetPostsDTO, + GetPostDTO, + PatchPostDTO, + DeletePostDTO, + PostCommentDTO, + GetCommentsDTO, + GetCommentDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/article.js"; + +export async function createPost(data: CreatePostDTO) { + return await prisma.article.create({ + data, + }); +} + +export async function getPosts(data: GetPostsDTO) { + // search에 값이 있을 때만 where로 문자열 검색 + const where = data.search + ? { + OR: [ + { + title: { + contains: data.search, + mode: "insensitive" as const, + }, + }, + { + content: { + contains: data.search, + mode: "insensitive" as const, + }, + }, + ], + } + : {}; + + const result = await prisma.article.findMany({ + select: { + id: true, + title: true, + content: true, + createdAt: true, + }, + orderBy: { + createdAt: data.sort, + }, + where, + skip: data.offset * data.limit, + take: data.limit, + }); + + return result; +} + +export async function getPost(data: GetPostDTO) { + const result = await prisma.article.findUnique({ + where: { + id: data.id, + }, + }); + + return result; +} + +export async function patchPost(data: PatchPostDTO) { + const { id, ...filteredBody } = data; + + const result = await prisma.article.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deletePost(data: DeletePostDTO) { + const { id } = data; + + const result = await prisma.article.delete({ + where: { + id, + }, + }); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const { pid: articleId, name, content, userId } = data; + + const result = await prisma.comment.create({ + data: { + name, + content, + articleId, + userId, + }, + }); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const { pid, cursor, limit } = data; + + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + articleId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(data: GetCommentDTO) { + const { cid: id } = data; + + const result = await prisma.comment.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const { cid, name, content } = data; + + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const { cid } = data; + + const result = prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} diff --git a/mission_10/src/repository/index.ts b/mission_10/src/repository/index.ts new file mode 100644 index 000000000..cab62f42d --- /dev/null +++ b/mission_10/src/repository/index.ts @@ -0,0 +1,4 @@ +export * from './articleRepository.js'; +export * from './productRepository.js'; +export * from './userRepository.js'; +export * from './notificationRepository.js'; \ No newline at end of file diff --git a/mission_10/src/repository/notificationRepository.ts b/mission_10/src/repository/notificationRepository.ts new file mode 100644 index 000000000..88829f4fe --- /dev/null +++ b/mission_10/src/repository/notificationRepository.ts @@ -0,0 +1,68 @@ +import prisma from '../lib/prisma.js'; + +async function create( + userId: number, + message: string, + articleId?: number, + productId?: number +) { + return prisma.notification.create({ + data: { + userId, + message, + articleId: articleId ?? null, + productId: productId ?? null, + }, + }); +} + +async function findManyByUserId(userId: number) { + return prisma.notification.findMany({ + where: { userId }, + orderBy: { createdAt: 'desc' }, + }); +} + +async function getUnreadCount(userId: number) { + return prisma.notification.count({ + where: { + userId, + read: false, + }, + }); +} + +async function markAsRead(notificationId: number, userId: number) { + const notification = await prisma.notification.findUnique({ + where: { id: notificationId }, + }); + + if (!notification || notification.userId !== userId) { + throw new Error('인증되지 않음 접근 혹은 알림 ID가 존재하지 않음'); + } + + return prisma.notification.update({ + where: { id: notificationId }, + data: { read: true }, + }); +} + +async function markAllAsRead(userId: number) { + return prisma.notification.updateMany({ + where: { + userId, + read: false, + }, + data: { + read: true, + }, + }); +} + +export default { + create, + findManyByUserId, + getUnreadCount, + markAsRead, + markAllAsRead, +}; diff --git a/mission_10/src/repository/productRepository.ts b/mission_10/src/repository/productRepository.ts new file mode 100644 index 000000000..1a8ea9922 --- /dev/null +++ b/mission_10/src/repository/productRepository.ts @@ -0,0 +1,235 @@ +import prisma from "../lib/prisma.js"; +import type { + CreateProductDTO, + GetProductsDTO, + GetProductDTO, + PatchProductDTO, + DeleteProductDTO, + PostCommentDTO, + GetCommentsDTO, + GetCommentDTO, + PatchCommentDTO, + DeleteCommentDTO, + GetProductsByUserDTO, +} from "../types/product.js"; + +export async function createProduct(data: CreateProductDTO) { + const { userId, name, description, price, tags } = data; + + return await prisma.product.create({ + data: { + name, + description, + price, + tags, + userId, + }, + }); +} + +export async function getProducts(data: GetProductsDTO) { + const { offset, limit, sort, search } = data; + + const result = await prisma.product.findMany({ + select: { + id: true, + name: true, + price: true, + createdAt: true, + }, + orderBy: { + createdAt: sort, + }, + where: { + OR: [ + { + name: { + contains: search, + mode: "insensitive", + }, + }, + { + description: { + contains: search, + mode: "insensitive", + }, + }, + ], + }, + skip: offset * limit, + take: limit, + }); + + return result; +} + +export async function getProduct(data: GetProductDTO) { + const { id } = data; + const result = await prisma.product.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchProduct(data: PatchProductDTO) { + const { id, ...filteredBody } = data; + + const result = await prisma.product.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deleteProduct(data: DeleteProductDTO) { + const { id } = data; + + const result = await prisma.product.delete({ + where: { + id, + }, + }); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const { pid, userId, name, content } = data; + + const result = await prisma.comment.create({ + data: { + userId, + name, + content, + productId: pid, + }, + }); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const { pid, cursor, limit } = data; + + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + productId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(data: GetCommentDTO) { + const { cid: id } = data; + + const result = await prisma.comment.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const { cid, name, content } = data; + + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const { cid } = data; + + const result = await prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} + +export async function getProductsByUser(data: GetProductsByUserDTO) { + const { userId: id } = data; + + const products = await prisma.user.findUnique({ + where: { id }, + select: { + Product: true, + }, + }); + + return products; +} + +export async function findLike(userId: number, productId: number) { + return prisma.likedProduct.findUnique({ + where: { + userId_productId: { + userId, + productId, + }, + }, + }); +} + +export async function likeProduct(userId: number, productId: number) { + return prisma.likedProduct.create({ + data: { + userId, + productId, + }, + }); +} + +export async function unlikeProduct(userId: number, productId: number) { + return prisma.likedProduct.delete({ + where: { + userId_productId: { + userId, + productId, + }, + }, + }); +} + +export async function getLikedUsersByProductId(productId: number) { + return prisma.likedProduct.findMany({ + where: { productId }, + select: { userId: true }, + }); +} diff --git a/mission_10/src/repository/userRepository.ts b/mission_10/src/repository/userRepository.ts new file mode 100644 index 000000000..3ec40d685 --- /dev/null +++ b/mission_10/src/repository/userRepository.ts @@ -0,0 +1,61 @@ +import prisma from "../lib/prisma.js"; +import bcrypt from "bcrypt"; +import type { CreateUserDTO, UserInfoDTO, GetUserDTO } from "../types/user.js"; + +export async function createUser(user: CreateUserDTO) { + const hashedPassword = await hashPassword(user.password); + + const createdUser = await prisma.user.create({ + data: { + ...user, + password: hashedPassword, // This line overwrites user.password + }, + }); + + return createdUser; +} + +export async function findByEmail(email: string) { + const result = await prisma.user.findFirst({ + where: { + email, + }, + }); + + return result; +} + +export async function findById(id: number) { + const result = await prisma.user.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function hashPassword(password: string) { + const salt = await bcrypt.genSalt(10); + const hash = await bcrypt.hash(password, salt); + + return hash; +} + +export function filterSensitiveUserData(user: UserInfoDTO) { + const { password, refreshToken, ...rest } = user; + return rest; +} + +export async function updateUser(id: number, toUpdate: any) { + if (toUpdate.password) { + toUpdate.password = await hashPassword(toUpdate.password); + } + + const updatedUser = await prisma.user.update({ + where: { id }, + data: toUpdate, + }); + + return updatedUser; +} diff --git a/mission_10/src/router/articleRouter.ts b/mission_10/src/router/articleRouter.ts new file mode 100644 index 000000000..07b603722 --- /dev/null +++ b/mission_10/src/router/articleRouter.ts @@ -0,0 +1,73 @@ +import express from "express"; +import { validateArticle } from "../middleware/index.js"; +import auth from "../middleware/auth.js"; +import * as articleController from "../controller/articleController.js"; + +const router = express.Router(); + +router + .route("/") + + // Create a post + .post( + auth.verifyAccessToken, + validateArticle, + articleController.createPost + ) + + // Retrieve all articles + .get(articleController.getPosts); + +router + .route("/:id") + + // Get informations of a specific article + .get(articleController.getPost) + + // Modify a article property + .patch( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.patchPost + ) + + // Delete a particular article + .delete( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.deletePost + ); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkArticleExist, + articleController.postComment + ) + + // Inquery all comments + .get(auth.checkArticleExist, articleController.getComments); + +router + .route("/:id/comments/:cid") + + // Modify comment + .patch( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.patchComment + ) + + // Delete comment + .delete( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.deleteComment + ); + +export default router; diff --git a/mission_10/src/router/imageRouter.ts b/mission_10/src/router/imageRouter.ts new file mode 100644 index 000000000..e73d6d5fd --- /dev/null +++ b/mission_10/src/router/imageRouter.ts @@ -0,0 +1,19 @@ +import express from 'express'; +import multer from "multer"; + +const router = express.Router(); + +const upload = multer({ dest: 'uploads/' }); + +// 이미지 리사이징 기능 구현 예정 +router.post('/', upload.single('image'), async (req, res) => { + // console.log(req.file); + if (!req.file) { + return res.status(400).json({ message: 'No file uploaded' }); + } + + res.status(201).json({ message: 'Upload OK', filePath: req.file.path }); +}); + + +export default router; \ No newline at end of file diff --git a/mission_10/src/router/index.ts b/mission_10/src/router/index.ts new file mode 100644 index 000000000..2ef8681ab --- /dev/null +++ b/mission_10/src/router/index.ts @@ -0,0 +1,5 @@ +export * from './articleRouter.js'; +export * from './productRouter.js'; +export * from './imageRouter.js'; +export * from './userRouter.js'; +export * from './notificationRouter.js'; \ No newline at end of file diff --git a/mission_10/src/router/notificationRouter.ts b/mission_10/src/router/notificationRouter.ts new file mode 100644 index 000000000..9266195ad --- /dev/null +++ b/mission_10/src/router/notificationRouter.ts @@ -0,0 +1,35 @@ +import { Router } from 'express'; +import notificationController from '../controller/notificationController.js'; +import auth from '../middleware/auth.js'; + +const router = Router(); + +// 모든 알림을 받아옴 +router.get( + '/notifications', + auth.verifyAccessToken, + notificationController.getNotifications +); + +// 알림 수를 받아옴 +router.get( + '/notifications/unread-count', + auth.verifyAccessToken, + notificationController.getUnreadCount +); + +// 알림을 읽음으로 표시 +router.patch( + '/notifications/:id/read', + auth.verifyAccessToken, + notificationController.markAsRead +); + +// 모든 알림을 읽음으로 표시 +router.patch( + '/notifications/read-all', + auth.verifyAccessToken, + notificationController.markAllAsRead +); + +export default router; diff --git a/mission_10/src/router/productRouter.ts b/mission_10/src/router/productRouter.ts new file mode 100644 index 000000000..9383b6fa7 --- /dev/null +++ b/mission_10/src/router/productRouter.ts @@ -0,0 +1,79 @@ +import express from "express"; +import type { Router } from "express"; +import { validateProduct } from "../middleware/validator.js"; +import auth from "../middleware/auth.js"; +import * as productController from "../controller/productController.js"; + +const router = express.Router(); + +router + .route("/") + + // Upload a new product + .post( + auth.verifyAccessToken, + validateProduct, + productController.createProduct + ) + + // Retrieve all products + .get(productController.getProducts); + +router + .route("/:id") + + // Get informations of a specific product + .get(productController.getProduct) + + // Modify a product property + .patch( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.patchProduct + ) + + // Delete a particular product + .delete( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.deleteProduct + ); + +// Like or unlike a product +router.post( + "/:id/like", + auth.verifyAccessToken, + productController.toggleLike +); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkProductExist, + productController.postComment + ) + + // Inquery all comments + .get(auth.checkProductExist, productController.getComments); + +router + .route("/:id/comments/:cid") + + .patch( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.patchComment + ) + + .delete( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.deleteComment + ); + +export default router; diff --git a/mission_10/src/router/userRouter.ts b/mission_10/src/router/userRouter.ts new file mode 100644 index 000000000..9ab871231 --- /dev/null +++ b/mission_10/src/router/userRouter.ts @@ -0,0 +1,44 @@ +import express from "express"; +import * as userController from "../controller/userController.js"; +import auth from "../middleware/auth.js"; + +const userRouter = express.Router(); + +userRouter + .route("/users") + + // Create user + .post(userController.createUser) + + // Get my(user) info + .get(auth.verifyAccessToken, userController.getMyInfo); + +// Update user info (nickname, email) +userRouter.patch( + "/users/info", + auth.verifyAccessToken, + userController.updateMyInfo +); + +// Update user password +userRouter.patch( + "/users/password", + auth.verifyAccessToken, + userController.updateMyPassword +); + +// Get product lists uploaded by user +userRouter.get( + "/users/products", + auth.verifyAccessToken, + userController.getMyProducts +); + +userRouter.post("/login", userController.getAccessToken); +userRouter.post( + "/login/refresh", + auth.verifyRefreshToken, + userController.getRefreshToken +); + +export default userRouter; diff --git a/mission_10/src/services/articleService.ts b/mission_10/src/services/articleService.ts new file mode 100644 index 000000000..caaca1aac --- /dev/null +++ b/mission_10/src/services/articleService.ts @@ -0,0 +1,80 @@ +import * as articleRepository from "../repository/articleRepository.js"; +import notificationService from "./notificationService.js"; +import type { + CreatePostDTO, + GetPostsDTO, + GetPostDTO, + PatchPostDTO, + DeletePostDTO, + PostCommentDTO, + GetCommentsDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/article.js"; + +export async function createPost(data: CreatePostDTO) { + const result = await articleRepository.createPost(data); + + return result; +} + +export async function getPosts(data: GetPostsDTO) { + const result = await articleRepository.getPosts(data); + + return result; +} + +export async function getPost(id: GetPostDTO) { + const result = await articleRepository.getPost(id); + + return result; +} + +export async function patchPost(data: PatchPostDTO) { + const result = await articleRepository.patchPost(data); + + return result; +} + +export async function deletePost(id: DeletePostDTO) { + const result = await articleRepository.deletePost(id); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const newComment = await articleRepository.postComment(data); + + const article = await articleRepository.getPost({ id: data.pid }); + if (!article) { + return newComment; + } + + if (article.userId !== data.userId) { + const message = `내가 판매 신청한 매물에 새로운 댓글이 달렸습니다.`; + await notificationService.createNotification( + article.userId, + message, + article.id + ); + } + + return newComment; +} + +export async function getComments(data: GetCommentsDTO) { + const result = await articleRepository.getComments(data); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const result = await articleRepository.patchComment(data); + + return result; +} +export async function deleteComment(data: DeleteCommentDTO) { + const result = await articleRepository.deleteComment(data); + + return result; +} diff --git a/mission_10/src/services/index.ts b/mission_10/src/services/index.ts new file mode 100644 index 000000000..69a5a5e9d --- /dev/null +++ b/mission_10/src/services/index.ts @@ -0,0 +1,4 @@ +export * from './articleService.js'; +export * from './productService.js'; +export * from './userService.js'; +export * from './notificationService.js'; \ No newline at end of file diff --git a/mission_10/src/services/notificationService.ts b/mission_10/src/services/notificationService.ts new file mode 100644 index 000000000..51d3cad92 --- /dev/null +++ b/mission_10/src/services/notificationService.ts @@ -0,0 +1,66 @@ +import notificationRepository from '../repository/notificationRepository.js'; +import { getIO } from '../lib/socket.js'; + +async function createNotification( + userId: number, + message: string, + articleId?: number, + productId?: number +) { + const newNotification = await notificationRepository.create( + userId, + message, + articleId, + productId + ); + + // 특정 유저ID에게 실시간 알림 전송 + const io = getIO(); + io.to(String(userId)).emit('new_notification', newNotification); + + // Also emit an unread count update + const unreadCount = await notificationRepository.getUnreadCount(userId); + io.to(String(userId)).emit('unread_count', unreadCount); + + return newNotification; +} + +async function getUserNotifications(userId: number) { + return notificationRepository.findManyByUserId(userId); +} + +async function getUnreadNotificationCount(userId: number) { + return notificationRepository.getUnreadCount(userId); +} + +async function markNotificationAsRead(notificationId: number, userId: number) { + const updatedNotification = await notificationRepository.markAsRead( + notificationId, + userId + ); + + // Emit an unread count update + const io = getIO(); + const unreadCount = await notificationRepository.getUnreadCount(userId); + io.to(String(userId)).emit('unread_count', unreadCount); + + return updatedNotification; +} + +async function markAllNotificationsAsRead(userId: number) { + const result = await notificationRepository.markAllAsRead(userId); + + // Emit an unread count update + const io = getIO(); + io.to(String(userId)).emit('unread_count', 0); + + return result; +} + +export default { + createNotification, + getUserNotifications, + getUnreadNotificationCount, + markNotificationAsRead, + markAllNotificationsAsRead, +}; diff --git a/mission_10/src/services/productService.ts b/mission_10/src/services/productService.ts new file mode 100644 index 000000000..0444fdb75 --- /dev/null +++ b/mission_10/src/services/productService.ts @@ -0,0 +1,103 @@ +import * as productRepository from "../repository/productRepository.js"; +import notificationService from "./notificationService.js"; +import type { + CreateProductDTO, + GetProductsDTO, + GetProductDTO, + PatchProductDTO, + DeleteProductDTO, + PostCommentDTO, + GetCommentsDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/product.js"; + +export async function createProduct(data: CreateProductDTO) { + const result = await productRepository.createProduct(data); + + return result; +} + +export async function getProducts(data: GetProductsDTO) { + const result = await productRepository.getProducts(data); + + return result; +} + +export async function getProduct(data: GetProductDTO) { + const result = await productRepository.getProduct(data); + + return result; +} + +export async function patchProduct(data: PatchProductDTO) { + const { id, price: newPrice } = data; + + const originalProduct = await productRepository.getProduct({ id: Number(id) }); + if (!originalProduct) { + throw new Error("상품이 존재하지 않습니다."); + } + const oldPrice = originalProduct.price; + + const updatedProduct = await productRepository.patchProduct(data); + + if (newPrice !== undefined && newPrice !== oldPrice) { + const likedUsers = await productRepository.getLikedUsersByProductId( + Number(id) + ); + + for (const liked of likedUsers) { + const message = `'${originalProduct.name}' 상품의 가격이 ${oldPrice}원에서 ${newPrice}원으로 변경되었습니다.`; + await notificationService.createNotification( + liked.userId, + message, + undefined, + Number(id) + ); + } + } + + return updatedProduct; +} + +export async function deleteProduct(data: DeleteProductDTO) { + const result = await productRepository.deleteProduct(data); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const result = await productRepository.postComment(data); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const result = await productRepository.getComments(data); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const result = await productRepository.patchComment(data); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const result = await productRepository.deleteComment(data); + + return result; +} + +export async function toggleLike(userId: number, productId: number) { + const existingLike = await productRepository.findLike(userId, productId); + + if (existingLike) { + await productRepository.unlikeProduct(userId, productId); + return { message: '관심 목록에서 삭제했습니다.' }; + } else { + await productRepository.likeProduct(userId, productId); + return { message: '관심 목록에 추가했습니다.' }; + } +} diff --git a/mission_10/src/services/userService.ts b/mission_10/src/services/userService.ts new file mode 100644 index 000000000..2060ef614 --- /dev/null +++ b/mission_10/src/services/userService.ts @@ -0,0 +1,121 @@ +import * as userRepository from "../repository/userRepository.js"; +import * as productRepository from "../repository/productRepository.js"; +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; +import type { CreateUserDTO, GetUserDTO, UserInfoDTO } from "../types/user.js"; + +export async function createUser(user: CreateUserDTO) { + // 이미 가입된 이메일인지 검증 + const existedUser = await userRepository.findByEmail(user.email); + + if (existedUser) { + const err = new Error("User already exists"); + err.statusCode = 422; + throw err; + } + + const createdUser = await userRepository.createUser(user); + const createdUserId = await userRepository.filterSensitiveUserData( + createdUser + ).id; + + return createdUserId; +} + +export async function getUser({ email, password }: GetUserDTO) { + const user: UserInfoDTO | null = await userRepository.findByEmail(email); + + // If user is invalid + if (!user || !user.password) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + throw err; + } + + // Verifying password + await verifyPassword(password, user.password); + + // Return without password + return userRepository.filterSensitiveUserData(user); +} + +export async function getUserById(userId: number) { + const user = await userRepository.findById(userId); + + if (!user) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return userRepository.filterSensitiveUserData(user); +} + +async function verifyPassword(inputPassword: string, password: string) { + const isVerified = await bcrypt.compare(inputPassword, password); + + if (!isVerified) { + const err = new Error("Password is wrong"); + err.statusCode = 401; + throw err; + } +} + +export function createToken(user: UserInfoDTO, token: string | null = null) { + const payload = { userId: user.id }; + const options: jwt.SignOptions = { + expiresIn: token === "refresh" ? "2W" : "1H", + }; + + if (!process.env.JWT_SECRET) { + throw new Error("JWT_SECRET is not defined"); + } + + return jwt.sign(payload, process.env.JWT_SECRET, options); +} + +export async function refreshToken(userId: number, refreshToken: string) { + const user = await userRepository.findById(userId); + + if (!user || user.refreshToken !== refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 404; + throw err; + } + + const accessToken = createToken(user); + return accessToken; +} + +export async function updateUserInfo(userId: number, toUpdate: any) { + // 수정할 내용이 없다면 에러 처리 + if (Object.keys(toUpdate).length === 0) { + const err = new Error("No data to update"); + err.statusCode = 400; + throw err; + } + + const updatedUser = await userRepository.updateUser(userId, toUpdate); + + return userRepository.filterSensitiveUserData(updatedUser); +} + +export async function updateUserPassword(userId: number, newPassword: string) { + const hashedPassword = await userRepository.hashPassword(newPassword); + const user = await userRepository.updateUser(userId, { + password: hashedPassword, + }); + + return userRepository.filterSensitiveUserData(user); +} + +export async function getMyProducts(userId: number) { + const products = await productRepository.getProductsByUser({ userId }); + if (!products) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return products.Product; +} diff --git a/mission_10/src/test/integration/article-auth.test.ts b/mission_10/src/test/integration/article-auth.test.ts new file mode 100644 index 000000000..81c8ac2d0 --- /dev/null +++ b/mission_10/src/test/integration/article-auth.test.ts @@ -0,0 +1,169 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; +import { getAuthToken } from "../util/getAuthToken.js"; + +const prisma = new PrismaClient(); + +let authToken: string; +let userId: number; +let articleId: number; +let commentId: number; + +const mockUser = { + email: "article-auth-user@test.com", + nickname: "test-auth", + password: "password123", +}; + +const mockArticle = { + title: "Auth Test Article", + content: "This is the content of the auth test article.", +}; + +const mockComment = { + name: "test-author", + content: "Example auth comment", +}; + +beforeAll(async () => { + // Ensure user does not exist + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + await request(app).post("/users").send(mockUser); + authToken = await getAuthToken(mockUser.email, mockUser.password); + const user = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + userId = user!.id; + + const articleResponse = await request(app) + .post("/articles") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockArticle, userId }); + articleId = articleResponse.body.id; + + const commentResponse = await request(app) + .post(`/articles/${articleId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockComment, userId }); + commentId = commentResponse.body.id; +}); + +afterAll(async () => { + await prisma.user.delete({ where: { id: userId } }); + authToken = ""; +}); + +describe("Article Integration Test (Auth)", () => { + describe("POST /articles", () => { + it("should create another article and return its properties", async () => { + const anotherMockArticle = { + title: "Another New Article", + content: "This is another article.", + }; + + const response = await request(app) + .post("/articles") + .set("Authorization", `Bearer ${authToken}`) + .send(anotherMockArticle) + .expect(201); + expect(response.body).toEqual( + expect.objectContaining({ id: expect.any(Number) }) + ); + await prisma.article.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /articles/:id", () => { + it("should update a specific article by ID", async () => { + const updatedData = { + title: "Modified Title", + }; + + const response = await request(app) + .patch(`/articles/${articleId}`) + .set("Authorization", `Bearer ${authToken}`) + .send(updatedData) + .expect(200); + + expect(response.body).toEqual( + expect.objectContaining({ id: articleId, title: updatedData.title }) + ); + }); + }); + + describe("DELETE /articles/:id", () => { + it("should delete a specific article by ID", async () => { + const tempArticleRes = await request(app) + .post("/articles") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockArticle, title: "To Be Deleted" }); + const tempArticleId = tempArticleRes.body.id; + + const response = await request(app) + .delete(`/articles/${tempArticleId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempArticleId); + }); + }); + + describe("POST /articles/:id/comments", () => { + it("should post another comment to a specific article", async () => { + const anotherMockComment = { + name: "another-author", + content: "Another example comment", + }; + + const response = await request(app) + .post(`/articles/${articleId}/comments`) + .send(anotherMockComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(201); + + expect(response.body).toHaveProperty("id"); + await prisma.comment.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /articles/:id/comments/:cid", () => { + it("should update a specific comment by ID", async () => { + const updatedComment = { + name: "updated-author", + content: "Updated comment content", + }; + + const response = await request(app) + .patch(`/articles/${articleId}/comments/${commentId}`) + .send(updatedComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("content", updatedComment.content); + }); + }); + + describe("DELETE /articles/:id/comments/:cid", () => { + it("should delete a specific comment by ID", async () => { + const tempCommentRes = await request(app) + .post(`/articles/${articleId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ name: "temp-user", content: "to be deleted" }); + const tempCommentId = tempCommentRes.body.id; + + const response = await request(app) + .delete(`/articles/${articleId}/comments/${tempCommentId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempCommentId); + }); + }); +}); diff --git a/mission_10/src/test/integration/article-noauth.test.ts b/mission_10/src/test/integration/article-noauth.test.ts new file mode 100644 index 000000000..bccb9fb11 --- /dev/null +++ b/mission_10/src/test/integration/article-noauth.test.ts @@ -0,0 +1,79 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); +let articleId: number; +let userId: number; + +const mockUser = { + email: "article-noauth-user@test.com", + nickname: "test-noauth", + password: "password123", +}; + +beforeAll(async () => { + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + // Create user + const userResponse = await request(app).post("/users").send(mockUser); + userId = userResponse.body.userId; + + // Create article + const article = await prisma.article.create({ + data: { + title: "Test Article", + content: "Test Content", + userId: userId, + }, + }); + articleId = article.id; +}); + +afterAll(async () => { + // Clean up + await prisma.user.delete({ where: { id: userId } }); +}); + +describe("Article Integration Test (No Auth)", () => { + describe("GET /articles", () => { + it("should return a list of articles", async () => { + const response = await request(app).get("/articles").expect(200); + expect(Array.isArray(response.body)).toBe(true); + }); + }); + + describe("GET /articles/:id", () => { + it("should return a specific article by ID", async () => { + const response = await request(app) + .get(`/articles/${articleId}`) + .expect(200); + + expect(response.body).toEqual(expect.objectContaining({ id: articleId })); + }); + + it("should return 404 for non-existing article", async () => { + const nonExistingId = 9999; + await request(app).get(`/articles/${nonExistingId}`).expect(404); + }); + }); + + describe("GET /articles/:id/comments", () => { + it("should return comments for a specific article", async () => { + const response = await request(app) + .get(`/articles/${articleId}/comments`) + .expect(200); + expect(Array.isArray(response.body.comments)).toBe(true); + }); + + it("should return 404 for comments of non-existing article", async () => { + const nonExistingId = 9999; + await request(app).get(`/articles/${nonExistingId}/comments`).expect(404); + }); + }); +}); diff --git a/mission_10/src/test/integration/product-auth.test.ts b/mission_10/src/test/integration/product-auth.test.ts new file mode 100644 index 000000000..ed556c171 --- /dev/null +++ b/mission_10/src/test/integration/product-auth.test.ts @@ -0,0 +1,169 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; +import { getAuthToken } from "../util/getAuthToken.js"; + +const prisma = new PrismaClient(); + +let authToken: string; +let userId: number; +let productId: number; +let commentId: number; + +const mockUser = { + email: "product-auth-user@test.com", + nickname: "test-product-auth", + password: "password123", +}; + +const mockProduct = { + name: "Auth Test Product", + description: "This is an auth test product.", + price: 50000, + tags: [], +}; + +const mockComment = { + name: "product-comment-author", + content: "Example product auth comment", +}; + +beforeAll(async () => { + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + await request(app).post("/users").send(mockUser); + authToken = await getAuthToken(mockUser.email, mockUser.password); + const user = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + userId = user!.id; + + const productResponse = await request(app) + .post("/products") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockProduct, userId }); + productId = productResponse.body.id; + + const commentResponse = await request(app) + .post(`/products/${productId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockComment, userId }); + commentId = commentResponse.body.id; +}); + +afterAll(async () => { + await prisma.user.delete({ where: { id: userId } }); + authToken = ""; +}); + +describe("Product Integration Test (Auth)", () => { + describe("POST /products", () => { + it("should upload another product and return its properties", async () => { + const anotherMockProduct = { + name: "Another Auth Product", + description: "Another one.", + price: 100, + tags: ["new"], + }; + + const response = await request(app) + .post("/products") + .set("Authorization", `Bearer ${authToken}`) + .send(anotherMockProduct) + .expect(201); + expect(response.body).toEqual( + expect.objectContaining({ id: expect.any(Number) }) + ); + await prisma.product.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /products/:id", () => { + it("should update a specific product by ID", async () => { + const updatedData = { + price: 9999, + }; + + const response = await request(app) + .patch(`/products/${productId}`) + .send(updatedData) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("price", updatedData.price); + }); + }); + + describe("DELETE /products/:id", () => { + it("should delete a specific product by ID", async () => { + const tempProductRes = await request(app) + .post("/products") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockProduct, name: "To Be Deleted" }); + const tempProductId = tempProductRes.body.id; + + const response = await request(app) + .delete(`/products/${tempProductId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempProductId); + }); + }); + + describe("POST /products/:id/comments", () => { + it("should post another comment to a specific product", async () => { + const anotherMockComment = { + name: "another-product-commenter", + content: "Another product comment", + }; + + const response = await request(app) + .post(`/products/${productId}/comments`) + .send(anotherMockComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(201); + + expect(response.body).toHaveProperty("id"); + await prisma.comment.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /products/:id/comments/:cid", () => { + it("should update a specific comment by ID", async () => { + const updatedComment = { + name: "updated-product-commenter", + content: "Updated product comment", + }; + const response = await request(app) + .patch(`/products/${productId}/comments/${commentId}`) + .send(updatedComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("content", updatedComment.content); + }); + }); + + describe("DELETE /products/:id/comments/:cid", () => { + it("should delete a specific comment by ID", async () => { + const tempCommentRes = await request(app) + .post(`/products/${productId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ name: "temp-user", content: "to be deleted" }); + const tempCommentId = tempCommentRes.body.id; + + const response = await request(app) + .delete(`/products/${productId}/comments/${tempCommentId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempCommentId); + }); + }); +}); diff --git a/mission_10/src/test/integration/product-noauth.test.ts b/mission_10/src/test/integration/product-noauth.test.ts new file mode 100644 index 000000000..51ac29c4d --- /dev/null +++ b/mission_10/src/test/integration/product-noauth.test.ts @@ -0,0 +1,84 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; + +const mockUser = { + email: "test@example.com", + nickname: "test", + password: "password123", +}; + +let productId: number; +let userId: number; + +const prisma = new PrismaClient(); + +beforeAll(async () => { + // Delete user if it exists to ensure a clean slate + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + const response = await request(app).post("/users").send(mockUser); + userId = response.body.userId; + + const res = await prisma.product.create({ + data: { + name: "Test Product", + description: "Test Product Desc", + price: 10010, + userId: userId, + }, + }); + + productId = res.id; +}); + +afterAll(async () => { + await prisma.user.deleteMany({ + where: { + email: mockUser.email, + }, + }); +}); + +describe("Product Integration Test (No Auth)", () => { + describe("GET /products", () => { + it("should return a list of products", async () => { + const response = await request(app).get("/products").expect(200); + expect(Array.isArray(response.body)).toBe(true); + }); + }); + + describe("GET /products/:id", () => { + it("should return a specific product by ID", async () => { + const response = await request(app) + .get(`/products/${productId}`) + .expect(200); + + expect(response.body).toHaveProperty("id"); + }); + + it("should return 404 for non-existing product", async () => { + const nonExistingId = 9999; + await request(app).get(`/products/${nonExistingId}`).expect(404); + }); + }); + + describe("GET /products/:id/comments", () => { + it("should return comments for a specific product", async () => { + const response = await request(app) + .get(`/products/${productId}/comments`) + .expect(200); + expect(Array.isArray(response.body.comments)).toBe(true); + }); + + it("should return 404 for comments of non-existing product", async () => { + const nonExistingId = 9999; + await request(app).get(`/products/${nonExistingId}/comments`).expect(404); + }); + }); +}); diff --git a/mission_10/src/test/integration/user.test.ts b/mission_10/src/test/integration/user.test.ts new file mode 100644 index 000000000..483657353 --- /dev/null +++ b/mission_10/src/test/integration/user.test.ts @@ -0,0 +1,43 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { getAuthToken } from "../util/getAuthToken.js"; +import { PrismaClient } from "@prisma/client"; + +const mockUser = { + email: "testtest@example.com", + nickname: "test", + password: "password123", +}; + +const prisma = new PrismaClient(); + +afterAll(async () => { + await prisma.user.deleteMany({ + where: { + email: mockUser.email, + }, + }); +}); + +describe("User Integration Test", () => { + describe("POST /users", () => { + it("should return a id of user newly created", async () => { + const response = await request(app) + .post("/users") + .send(mockUser) + .expect(200); + expect(response.body).toHaveProperty("userId"); + }); + + it("should return 400 status code", async () => { + const response = await request(app).post("/users").send({}).expect(400); + }); + }); + + describe("POST /login", () => { + it("should return a string of accessToken", async () => { + const accessToken = await getAuthToken(mockUser.email, mockUser.password); + expect(typeof accessToken).toBe("string"); + }); + }); +}); diff --git a/mission_10/src/test/setup.ts b/mission_10/src/test/setup.ts new file mode 100644 index 000000000..a80cd98d9 --- /dev/null +++ b/mission_10/src/test/setup.ts @@ -0,0 +1,4 @@ +import { jest } from '@jest/globals'; + +jest.spyOn(console, "error").mockImplementation(() => {}); +jest.spyOn(console, "log").mockImplementation(() => {}); \ No newline at end of file diff --git a/mission_10/src/test/unit/product.test.ts b/mission_10/src/test/unit/product.test.ts new file mode 100644 index 000000000..55dff3aed --- /dev/null +++ b/mission_10/src/test/unit/product.test.ts @@ -0,0 +1,46 @@ +import { jest } from "@jest/globals"; + +const mockCreateProductFunction = jest.fn(); + +jest.unstable_mockModule("../../repository/productRepository.js", () => ({ + createProduct: mockCreateProductFunction, +})); + +const { createProduct: createProductService } = await import( + "../../services/productService.js" +); + +describe("Product Service Unit Test", () => { + describe("createProduct", () => { + const mockCreateProductRepo = mockCreateProductFunction; + + afterEach(() => { + mockCreateProductRepo.mockClear(); + }); + + it("should call repository and return the created product", async () => { + const mockProductData = { + userId: 1, + name: "Test Product", + description: "This is a test product.", + price: 10000, + tags: ["test"], + }; + + const mockCreatedProduct = { + id: 123, + ...mockProductData, + createdAt: new Date(), + updatedAt: new Date(), + }; + + mockCreateProductRepo.mockResolvedValue(mockCreatedProduct); + + const result = await createProductService(mockProductData); + + expect(mockCreateProductRepo).toHaveBeenCalledTimes(1); + expect(mockCreateProductRepo).toHaveBeenCalledWith(mockProductData); + expect(result).toEqual(mockCreatedProduct); + }); + }); +}); \ No newline at end of file diff --git a/mission_10/src/test/util/getAuthToken.ts b/mission_10/src/test/util/getAuthToken.ts new file mode 100644 index 000000000..ac05de4e2 --- /dev/null +++ b/mission_10/src/test/util/getAuthToken.ts @@ -0,0 +1,16 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; + +export const getAuthToken = async (email: string, password: string) => { + const userData = { + /* email: "user1@example.com", + password: "password123", */ + email, + password, + }; + + const response = await request(app).post("/login").send(userData).expect(200); + + const { accessToken } = response.body; + return accessToken; +}; diff --git a/mission_10/src/types/article.ts b/mission_10/src/types/article.ts new file mode 100644 index 000000000..1398c1c95 --- /dev/null +++ b/mission_10/src/types/article.ts @@ -0,0 +1,54 @@ +export interface CreatePostDTO { + title: string; + content: string; + userId: number; +} + +export interface GetPostsDTO { + cursor?: number; + limit: number; + sort: "asc" | "desc"; + offset: number; + search?: string; +} + +export interface GetPostDTO { + id: number; +} + +export interface PatchPostDTO { + id: number; + title?: string; + content?: string; +} + +export interface DeletePostDTO { + id: number; +} + +export interface PostCommentDTO { + pid: number; + name: string; + content: string; + userId: number; +} + +export interface GetCommentsDTO { + pid: number; + cursor: number; + limit: number; +} + +export interface GetCommentDTO { + cid: number; +} + +export interface PatchCommentDTO { + cid: number; + name: string; + content: string; +} + +export interface DeleteCommentDTO { + cid: number; +} diff --git a/mission_10/src/types/auth.d.ts b/mission_10/src/types/auth.d.ts new file mode 100644 index 000000000..7353fbba8 --- /dev/null +++ b/mission_10/src/types/auth.d.ts @@ -0,0 +1,5 @@ +export interface JwtPayload { + userId: number; + iat?: number; + exp?: number; +} diff --git a/mission_10/src/types/express/index.d.ts b/mission_10/src/types/express/index.d.ts new file mode 100644 index 000000000..25cbc8d62 --- /dev/null +++ b/mission_10/src/types/express/index.d.ts @@ -0,0 +1,10 @@ +import "express"; +import type { JwtPayload } from "../auth.d.js"; + +declare module "express-serve-static-core" { + interface Request { + // user?: import("../types/auth").JwtPayload; + user?: JwtPayload; + auth?: JwtPayload; + } +} diff --git a/mission_10/src/types/global.ts b/mission_10/src/types/global.ts new file mode 100644 index 000000000..452228e41 --- /dev/null +++ b/mission_10/src/types/global.ts @@ -0,0 +1,5 @@ +declare global { + interface Error { + statusCode?: number; + } +} \ No newline at end of file diff --git a/mission_10/src/types/product.ts b/mission_10/src/types/product.ts new file mode 100644 index 000000000..52d1aa2f2 --- /dev/null +++ b/mission_10/src/types/product.ts @@ -0,0 +1,63 @@ +export interface CreateProductDTO { + userId: number; + name: string; + description: string; + price: number; + tags: string[]; +} + +export interface GetProductsDTO { + offset: number; + limit: number; + sort: "asc" | "desc"; + search: string; +} + +export interface GetProductDTO { + id: number; +} + +export interface PatchProductDTO { + id: number; + name?: string; + description?: string; + price?: number; + tags?: string[]; +} + +export interface DeleteProductDTO { + id: number; +} + +export interface PostCommentDTO { + pid: number; + userId: number; + content: string; + name: string; +} + +export interface GetCommentsDTO { + pid: number; + cursor: number | null; + limit: number; +} + +export interface GetCommentDTO { + cid: number; +} + +export interface PatchCommentDTO { + cid: number; + name: string; + content: string; +} + +export interface DeleteCommentDTO { + cid: number; +} + +export interface GetProductsByUserDTO { + userId: number; + offset?: number; + limit?: number; +} diff --git a/mission_10/src/types/user.ts b/mission_10/src/types/user.ts new file mode 100644 index 000000000..adf66d149 --- /dev/null +++ b/mission_10/src/types/user.ts @@ -0,0 +1,21 @@ +export interface CreateUserDTO { + email: string; + nickname: string; + password: string; +} + +export interface GetUserDTO { + email: string; + password: string; +} + +export interface UserInfoDTO { + password?: string; + email: string; + nickname: string; + image: string | null; + refreshToken?: string | null; + createdAt: Date; + updatedAt: Date; + id: number; +} diff --git a/mission_10/test-client.html b/mission_10/test-client.html new file mode 100644 index 000000000..a7bc85c49 --- /dev/null +++ b/mission_10/test-client.html @@ -0,0 +1,142 @@ + + + + + + Socket.IO Test Client + + + +
+

1. 실시간 알림 수신 설정

+ + + +

2. 알림 트리거 (댓글 작성)

+ + + + +
+ +
+

서버 로그

+
+

서버 로그가 여기에 표시됩니다...

+
+
+ + + + + \ No newline at end of file diff --git a/mission_10/tsconfig.json b/mission_10/tsconfig.json new file mode 100644 index 000000000..cd741fa49 --- /dev/null +++ b/mission_10/tsconfig.json @@ -0,0 +1,49 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "moduleResolution": "nodenext", + "target": "es2022", + // "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, + + "esModuleInterop": true + }, + "include": ["src", "env.d.ts"], + "exclude": ["**/*.test.ts"] +} From d9e86b2abd30a1e5823a73cf67a19e87e613da7d Mon Sep 17 00:00:00 2001 From: intwocave Date: Tue, 25 Nov 2025 16:44:12 +0900 Subject: [PATCH 114/130] chore: gitkeep --- mission_10/infra/ec2/.gitkeep | 0 mission_10/infra/rds/.gitkeep | 0 mission_10/infra/s3/.gitkeep | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 mission_10/infra/ec2/.gitkeep create mode 100644 mission_10/infra/rds/.gitkeep create mode 100644 mission_10/infra/s3/.gitkeep diff --git a/mission_10/infra/ec2/.gitkeep b/mission_10/infra/ec2/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/mission_10/infra/rds/.gitkeep b/mission_10/infra/rds/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/mission_10/infra/s3/.gitkeep b/mission_10/infra/s3/.gitkeep new file mode 100644 index 000000000..e69de29bb From 511dc946311d170949314f6b2f58aa3551472016 Mon Sep 17 00:00:00 2001 From: intwocave Date: Tue, 25 Nov 2025 16:56:36 +0900 Subject: [PATCH 115/130] feat: update .env.sample with new S3 configurations --- mission_10/.env.sample | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/mission_10/.env.sample b/mission_10/.env.sample index b572e4204..a88795e05 100644 --- a/mission_10/.env.sample +++ b/mission_10/.env.sample @@ -1,2 +1,14 @@ +# Node Env +NODE_ENV="development" + +# JWT JWT_SECRET="your-super-secret-key" -DATABASE_URL="postgresql://user:password@localhost:5432/mydatabase" \ No newline at end of file + +# POSTGRESQL +DATABASE_URL="postgresql://user:password@localhost:5432/mydatabase" + +# AWS S3 +AWS_ACCESS_KEY_ID="your-aws-access-key-id" +AWS_SECRET_ACCESS_KEY="your-aws-secret-access-key" +AWS_S3_BUCKET_NAME="your-s3-bucket-name" +AWS_REGION="your-aws-region" From 7129744e1755af7136d29e0f0ec44a87adccc779 Mon Sep 17 00:00:00 2001 From: intwocave Date: Tue, 25 Nov 2025 17:06:59 +0900 Subject: [PATCH 116/130] feat: add screenshots of ec2 secure group --- mission_10/infra/ec2/secure-group-inbound.png | Bin 0 -> 109571 bytes mission_10/infra/ec2/secure-group-outbound.png | Bin 0 -> 99953 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 mission_10/infra/ec2/secure-group-inbound.png create mode 100644 mission_10/infra/ec2/secure-group-outbound.png diff --git a/mission_10/infra/ec2/secure-group-inbound.png b/mission_10/infra/ec2/secure-group-inbound.png new file mode 100644 index 0000000000000000000000000000000000000000..324a33fa97136324c4e404842d9b0e207defb660 GIT binary patch literal 109571 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 Date: Thu, 27 Nov 2025 17:28:43 +0900 Subject: [PATCH 117/130] =?UTF-8?q?feat:=20s3=20=EC=97=85=EB=A1=9C?= =?UTF-8?q?=EB=93=9C=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission_10/package-lock.json | 4043 ++++++++++++++++++++++++---------- mission_10/package.json | 3 + 2 files changed, 2940 insertions(+), 1106 deletions(-) diff --git a/mission_10/package-lock.json b/mission_10/package-lock.json index e4a66982a..7e01d3ce3 100644 --- a/mission_10/package-lock.json +++ b/mission_10/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@aws-sdk/client-s3": "^3.940.0", "@jest/globals": "^30.2.0", "@prisma/client": "^6.13.0", "bcrypt": "^6.0.0", @@ -19,6 +20,7 @@ "express-jwt": "^8.5.1", "jsonwebtoken": "^9.0.2", "multer": "^2.0.2", + "multer-s3": "^3.0.1", "passport": "^0.7.0", "passport-jwt": "^4.0.1", "socket.io": "^4.8.1", @@ -32,6 +34,7 @@ "@types/express-jwt": "^6.0.4", "@types/jest": "^30.0.0", "@types/multer": "^2.0.0", + "@types/multer-s3": "^3.0.3", "@types/node": "^24.3.1", "@types/socket.io": "^3.0.1", "@types/supertest": "^6.0.3", @@ -42,1502 +45,3139 @@ "typescript": "^5.9.2" } }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "license": "MIT", + "node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" + "node_modules/@aws-crypto/crc32c": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", + "integrity": "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" } }, - "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "license": "MIT", + "node_modules/@aws-crypto/sha1-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz", + "integrity": "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==", + "license": "Apache-2.0", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "node": ">=14.0.0" } }, - "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "license": "MIT", + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "license": "MIT", + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "license": "MIT", + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "license": "MIT", + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "license": "MIT", + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "license": "MIT", + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" } }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "license": "MIT", + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "license": "MIT", + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "license": "MIT", + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "license": "MIT", + "node_modules/@aws-sdk/client-s3": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.940.0.tgz", + "integrity": "sha512-Wi4qnBT6shRRMXuuTgjMFTU5mu2KFWisgcigEMPptjPGUtJvBVi4PTGgS64qsLoUk/obqDAyOBOfEtRZ2ddC2w==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@aws-crypto/sha1-browser": "5.2.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/credential-provider-node": "3.940.0", + "@aws-sdk/middleware-bucket-endpoint": "3.936.0", + "@aws-sdk/middleware-expect-continue": "3.936.0", + "@aws-sdk/middleware-flexible-checksums": "3.940.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-location-constraint": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-sdk-s3": "3.940.0", + "@aws-sdk/middleware-ssec": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/signature-v4-multi-region": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/eventstream-serde-browser": "^4.2.5", + "@smithy/eventstream-serde-config-resolver": "^4.3.5", + "@smithy/eventstream-serde-node": "^4.2.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-blob-browser": "^4.2.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/hash-stream-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/md5-js": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "@smithy/util-waiter": "^4.2.5", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "license": "MIT", + "node_modules/@aws-sdk/client-sso": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.940.0.tgz", + "integrity": "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "license": "MIT", + "node_modules/@aws-sdk/core": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.940.0.tgz", + "integrity": "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@aws-sdk/types": "3.936.0", + "@aws-sdk/xml-builder": "3.930.0", + "@smithy/core": "^3.18.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.940.0.tgz", + "integrity": "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.940.0.tgz", + "integrity": "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-stream": "^4.5.6", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.940.0.tgz", + "integrity": "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@aws-sdk/core": "3.940.0", + "@aws-sdk/credential-provider-env": "3.940.0", + "@aws-sdk/credential-provider-http": "3.940.0", + "@aws-sdk/credential-provider-login": "3.940.0", + "@aws-sdk/credential-provider-process": "3.940.0", + "@aws-sdk/credential-provider-sso": "3.940.0", + "@aws-sdk/credential-provider-web-identity": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.940.0.tgz", + "integrity": "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.940.0.tgz", + "integrity": "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@aws-sdk/credential-provider-env": "3.940.0", + "@aws-sdk/credential-provider-http": "3.940.0", + "@aws-sdk/credential-provider-ini": "3.940.0", + "@aws-sdk/credential-provider-process": "3.940.0", + "@aws-sdk/credential-provider-sso": "3.940.0", + "@aws-sdk/credential-provider-web-identity": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.940.0.tgz", + "integrity": "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.940.0.tgz", + "integrity": "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@aws-sdk/client-sso": "3.940.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/token-providers": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.940.0.tgz", + "integrity": "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "license": "MIT", + "node_modules/@aws-sdk/lib-storage": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.940.0.tgz", + "integrity": "sha512-4pHgz9tuFJNSy/qoTbW5FqXPjoR4B18jB656UsE+TP5GWd7EPx7m4F0EUwIsD3OF5+KPiiyICi8zkxOs7erfQw==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@smithy/abort-controller": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/smithy-client": "^4.9.8", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@aws-sdk/client-s3": "^3.940.0" } }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.936.0.tgz", + "integrity": "sha512-XLSVVfAorUxZh6dzF+HTOp4R1B5EQcdpGcPliWr0KUj2jukgjZEcqbBmjyMF/p9bmyQsONX80iURF1HLAlW0qg==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-config-provider": "^4.2.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.936.0.tgz", + "integrity": "sha512-Eb4ELAC23bEQLJmUMYnPWcjD3FZIsmz2svDiXEcxRkQU9r7NRID7pM7C5NPH94wOfiCk0b2Y8rVyFXW0lGQwbA==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@aws-sdk/types": "3.936.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.940.0.tgz", + "integrity": "sha512-WdsxDAVj5qaa5ApAP+JbpCOMHFGSmzjs2Y2OBSbWPeR9Ew7t/Okj+kUub94QJPsgzhvU1/cqNejhsw5VxeFKSQ==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@aws-crypto/crc32": "5.2.0", + "@aws-crypto/crc32c": "5.2.0", + "@aws-crypto/util": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18.0.0" } }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.936.0.tgz", + "integrity": "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@aws-sdk/types": "3.936.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18.0.0" } }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.936.0.tgz", + "integrity": "sha512-SCMPenDtQMd9o5da9JzkHz838w3327iqXk3cbNnXWqnNRx6unyW8FL0DZ84gIY12kAyVHz5WEqlWuekc15ehfw==", + "license": "Apache-2.0", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=18.0.0" } }, - "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.936.0.tgz", + "integrity": "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw==", + "license": "Apache-2.0", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", - "debug": "^4.3.1" + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=18.0.0" } }, - "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.936.0.tgz", + "integrity": "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@aws-sdk/types": "3.936.0", + "@aws/lambda-invoke-store": "^0.2.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=18.0.0" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@emnapi/core": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", - "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.940.0.tgz", + "integrity": "sha512-JYkLjgS1wLoKHJ40G63+afM1ehmsPsjcmrHirKh8+kSCx4ip7+nL1e/twV4Zicxr8RJi9Y0Ahq5mDvneilDDKQ==", + "license": "Apache-2.0", "dependencies": { - "@emnapi/wasi-threads": "1.1.0", - "tslib": "^2.4.0" + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/core": "^3.18.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@emnapi/runtime": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", - "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.936.0.tgz", + "integrity": "sha512-/GLC9lZdVp05ozRik5KsuODR/N7j+W+2TbfdFL3iS+7un+gnP6hC8RDOZd6WhpZp7drXQ9guKiTAxkZQwzS8DA==", + "license": "Apache-2.0", "dependencies": { - "tslib": "^2.4.0" + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.940.0.tgz", + "integrity": "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA==", + "license": "Apache-2.0", "dependencies": { - "tslib": "^2.4.0" + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@smithy/core": "^3.18.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], + "node_modules/@aws-sdk/nested-clients": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.940.0.tgz", + "integrity": "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.936.0.tgz", + "integrity": "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.940.0.tgz", + "integrity": "sha512-ugHZEoktD/bG6mdgmhzLDjMP2VrYRAUPRPF1DpCyiZexkH7DCU7XrSJyXMvkcf0DHV+URk0q2sLf/oqn1D2uYw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "node_modules/@aws-sdk/token-providers": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.940.0.tgz", + "integrity": "sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/@aws-sdk/types": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.936.0.tgz", + "integrity": "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.893.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.893.0.tgz", + "integrity": "sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.936.0.tgz", + "integrity": "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-endpoints": "^3.2.5", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.893.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.893.0.tgz", + "integrity": "sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.936.0.tgz", + "integrity": "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.940.0.tgz", + "integrity": "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@aws-sdk/xml-builder": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.930.0.tgz", + "integrity": "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "fast-xml-parser": "5.2.5", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@aws/lambda-invoke-store": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.1.tgz", + "integrity": "sha512-sIyFcoPZkTtNu9xFeEoynMef3bPJIAbOfUh+ueYcfhVl6xm2VRtMcMclSxmZCMnHHd4hlYKJeq/aggmBEWynww==", + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], "engines": { - "node": ">=18" + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emnapi/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", + "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/core": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", + "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.2.0", + "jest-config": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-resolve-dependencies": "30.2.0", + "jest-runner": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "jest-watcher": "30.2.0", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", + "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "license": "MIT", + "dependencies": { + "expect": "30.2.0", + "jest-snapshot": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", + "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@sinonjs/fake-timers": "^13.0.0", + "@types/node": "*", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", + "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/types": "30.2.0", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", + "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", + "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", + "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/types": "30.2.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", + "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", + "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@prisma/client": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.19.0.tgz", + "integrity": "sha512-QXFT+N/bva/QI2qoXmjBzL7D6aliPffIwP+81AdTGq0FXDoLxLkWivGMawG8iM5B9BKfxLIXxfWWAF6wbuJU6g==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.19.0.tgz", + "integrity": "sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.18.4", + "empathic": "2.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.19.0.tgz", + "integrity": "sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.19.0.tgz", + "integrity": "sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/fetch-engine": "6.19.0", + "@prisma/get-platform": "6.19.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773.tgz", + "integrity": "sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.19.0.tgz", + "integrity": "sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/get-platform": "6.19.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.19.0.tgz", + "integrity": "sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.5.tgz", + "integrity": "sha512-j7HwVkBw68YW8UmFRcjZOmssE77Rvk0GWAIN1oFBhsaovQmZWYCIcGa9/pwRB0ExI8Sk9MWNALTjftjHZea7VA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.0.tgz", + "integrity": "sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.2.1.tgz", + "integrity": "sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-base64": "^4.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.3.tgz", + "integrity": "sha512-ezHLe1tKLUxDJo2LHtDuEDyWXolw8WGOR92qb4bQdWq/zKenO5BvctZGrVJBK08zjezSk7bmbKFOXIVyChvDLw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.18.5", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.18.5.tgz", + "integrity": "sha512-6gnIz3h+PEPQGDj8MnRSjDvKBah042jEoPgjFGJ4iJLBE78L4lY/n98x14XyPF4u3lN179Ub/ZKFY5za9GeLQw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.2.6", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.5.tgz", + "integrity": "sha512-BZwotjoZWn9+36nimwm/OLIcVe+KYRwzMjfhd4QT7QxPm9WY0HiOV8t/Wlh+HVUif0SBVV7ksq8//hPaBC/okQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], + "node_modules/@smithy/eventstream-codec": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.5.tgz", + "integrity": "sha512-Ogt4Zi9hEbIP17oQMd68qYOHUzmH47UkK7q7Gl55iIm9oKt27MUGrC5JfpMroeHjdkOliOA4Qt3NQ1xMq/nrlA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.9.0", + "@smithy/util-hex-encoding": "^4.2.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "node_modules/@smithy/eventstream-serde-browser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.5.tgz", + "integrity": "sha512-HohfmCQZjppVnKX2PnXlf47CW3j92Ki6T/vkAT2DhBR47e89pen3s4fIa7otGTtrVxmj7q+IhH0RnC5kpR8wtw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.5.tgz", + "integrity": "sha512-ibjQjM7wEXtECiT6my1xfiMH9IcEczMOS6xiCQXoUIYSj5b1CpBbJ3VYbdwDy8Vcg5JHN7eFpOCGk8nyZAltNQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "node_modules/@smithy/eventstream-serde-node": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.5.tgz", + "integrity": "sha512-+elOuaYx6F2H6x1/5BQP5ugv12nfJl66GhxON8+dWVUEDJ9jah/A0tayVdkLRP0AeSac0inYkDz5qBFKfVp2Gg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", + "node_modules/@smithy/eventstream-serde-universal": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.5.tgz", + "integrity": "sha512-G9WSqbST45bmIFaeNuP/EnC19Rhp54CcVdX9PDL1zyEB514WsDVXhlyihKlGXnRycmHNmVv88Bvvt4EYxWef/Q==", + "license": "Apache-2.0", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "@smithy/eventstream-codec": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=12" + "node": ">=18.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "license": "ISC", + "node_modules/@smithy/fetch-http-handler": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.6.tgz", + "integrity": "sha512-3+RG3EA6BBJ/ofZUeTFJA7mHfSYrZtQIrDP9dI8Lf7X6Jbos2jptuLrAAteDiFVrmbEmLSuRG/bUKzfAXk7dhg==", + "license": "Apache-2.0", "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "@smithy/protocol-http": "^5.3.5", + "@smithy/querystring-builder": "^4.2.5", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=8" + "node": ">=18.0.0" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "license": "MIT", + "node_modules/@smithy/hash-blob-browser": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.6.tgz", + "integrity": "sha512-8P//tA8DVPk+3XURk2rwcKgYwFvwGwmJH/wJqQiSKwXZtf/LiZK+hbUZmPj/9KzM+OVSwe4o85KTp5x9DUZTjw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/chunked-blob-reader": "^5.2.0", + "@smithy/chunked-blob-reader-native": "^4.2.1", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=8" + "node": ">=18.0.0" } }, - "node_modules/@jest/console": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", - "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/hash-node": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.5.tgz", + "integrity": "sha512-DpYX914YOfA3UDT9CN1BM787PcHfWRBB43fFGCYrZFUH0Jv+5t8yYl+Pd5PW4+QzoGEDvn5d5QIO4j2HyYZQSA==", + "license": "Apache-2.0", "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "slash": "^3.0.0" + "@smithy/types": "^4.9.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/core": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", - "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/hash-stream-node": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.5.tgz", + "integrity": "sha512-6+do24VnEyvWcGdHXomlpd0m8bfZePpUKBy7m311n+JuRwug8J4dCanJdTymx//8mi0nlkflZBvJe+dEO/O12Q==", + "license": "Apache-2.0", "dependencies": { - "@jest/console": "30.2.0", - "@jest/pattern": "30.0.1", - "@jest/reporters": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "ansi-escapes": "^4.3.2", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "exit-x": "^0.2.2", - "graceful-fs": "^4.2.11", - "jest-changed-files": "30.2.0", - "jest-config": "30.2.0", - "jest-haste-map": "30.2.0", - "jest-message-util": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-resolve-dependencies": "30.2.0", - "jest-runner": "30.2.0", - "jest-runtime": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "jest-watcher": "30.2.0", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", - "slash": "^3.0.0" + "@smithy/types": "^4.9.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.5.tgz", + "integrity": "sha512-2L2erASEro1WC5nV+plwIMxrTXpvpfzl4e+Nre6vBVRR2HKeGGcvpJyyL3/PpiSg+cJG2KpTmZmq934Olb6e5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.0.tgz", + "integrity": "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@jest/diff-sequences": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", - "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", - "license": "MIT", + "node_modules/@smithy/md5-js": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.5.tgz", + "integrity": "sha512-Bt6jpSTMWfjCtC0s79gZ/WZ1w90grfmopVOWqkI2ovhjpD5Q2XRXuecIPB9689L2+cCySMbaXDhBPU56FKNDNg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/environment": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", - "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", - "license": "MIT", + "node_modules/@smithy/middleware-content-length": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.5.tgz", + "integrity": "sha512-Y/RabVa5vbl5FuHYV2vUCwvh/dqzrEY/K2yWPSqvhFUwIY0atLqO4TienjBXakoy4zrKAMCZwg+YEqmH7jaN7A==", + "license": "Apache-2.0", "dependencies": { - "@jest/fake-timers": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "jest-mock": "30.2.0" + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", - "license": "MIT", + "node_modules/@smithy/middleware-endpoint": { + "version": "4.3.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.3.12.tgz", + "integrity": "sha512-9pAX/H+VQPzNbouhDhkW723igBMLgrI8OtX+++M7iKJgg/zY/Ig3i1e6seCcx22FWhE6Q/S61BRdi2wXBORT+A==", + "license": "Apache-2.0", "dependencies": { - "expect": "30.2.0", - "jest-snapshot": "30.2.0" + "@smithy/core": "^3.18.5", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-middleware": "^4.2.5", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/expect-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", - "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", - "license": "MIT", + "node_modules/@smithy/middleware-retry": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.12.tgz", + "integrity": "sha512-S4kWNKFowYd0lID7/DBqWHOQxmxlsf0jBaos9chQZUWTVOjSW1Ogyh8/ib5tM+agFDJ/TCxuCTvrnlc+9cIBcQ==", + "license": "Apache-2.0", "dependencies": { - "@jest/get-type": "30.1.0" + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/service-error-classification": "^4.2.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/fake-timers": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", - "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", - "license": "MIT", + "node_modules/@smithy/middleware-serde": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.6.tgz", + "integrity": "sha512-VkLoE/z7e2g8pirwisLz8XJWedUSY8my/qrp81VmAdyrhi94T+riBfwP+AOEEFR9rFTSonC/5D2eWNmFabHyGQ==", + "license": "Apache-2.0", "dependencies": { - "@jest/types": "30.2.0", - "@sinonjs/fake-timers": "^13.0.0", - "@types/node": "*", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", - "license": "MIT", + "node_modules/@smithy/middleware-stack": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.5.tgz", + "integrity": "sha512-bYrutc+neOyWxtZdbB2USbQttZN0mXaOyYLIsaTbJhFsfpXyGWUxJpEuO1rJ8IIJm2qH4+xJT0mxUSsEDTYwdQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/globals": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", - "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", - "license": "MIT", + "node_modules/@smithy/node-config-provider": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.5.tgz", + "integrity": "sha512-UTurh1C4qkVCtqggI36DGbLB2Kv8UlcFdMXDcWMbqVY2uRg0XmT9Pb4Vj6oSQ34eizO1fvR0RnFV4Axw4IrrAg==", + "license": "Apache-2.0", "dependencies": { - "@jest/environment": "30.2.0", - "@jest/expect": "30.2.0", - "@jest/types": "30.2.0", - "jest-mock": "30.2.0" + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.5.tgz", + "integrity": "sha512-CMnzM9R2WqlqXQGtIlsHMEZfXKJVTIrqCNoSd/QpAyp+Dw0a1Vps13l6ma1fH8g7zSPNsA59B/kWgeylFuA/lw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/querystring-builder": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/pattern": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", - "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", - "license": "MIT", + "node_modules/@smithy/property-provider": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.5.tgz", + "integrity": "sha512-8iLN1XSE1rl4MuxvQ+5OSk/Zb5El7NJZ1td6Tn+8dQQHIjp59Lwl6bd0+nzw6SKm2wSSriH2v/I9LPzUic7EOg==", + "license": "Apache-2.0", "dependencies": { - "@types/node": "*", - "jest-regex-util": "30.0.1" + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/reporters": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", - "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/protocol-http": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.5.tgz", + "integrity": "sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ==", + "license": "Apache-2.0", "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@jridgewell/trace-mapping": "^0.3.25", - "@types/node": "*", - "chalk": "^4.1.2", - "collect-v8-coverage": "^1.0.2", - "exit-x": "^0.2.2", - "glob": "^10.3.10", - "graceful-fs": "^4.2.11", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^5.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "jest-worker": "30.2.0", - "slash": "^3.0.0", - "string-length": "^4.0.2", - "v8-to-istanbul": "^9.0.1" + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": ">=18.0.0" } }, - "node_modules/@jest/schemas": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", - "license": "MIT", + "node_modules/@smithy/querystring-builder": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.5.tgz", + "integrity": "sha512-y98otMI1saoajeik2kLfGyRp11e5U/iJYH/wLCh3aTV/XutbGT9nziKGkgCaMD1ghK7p6htHMm6b6scl9JRUWg==", + "license": "Apache-2.0", "dependencies": { - "@sinclair/typebox": "^0.34.0" + "@smithy/types": "^4.9.0", + "@smithy/util-uri-escape": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/snapshot-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", - "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", - "license": "MIT", + "node_modules/@smithy/querystring-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.5.tgz", + "integrity": "sha512-031WCTdPYgiQRYNPXznHXof2YM0GwL6SeaSyTH/P72M1Vz73TvCNH2Nq8Iu2IEPq9QP2yx0/nrw5YmSeAi/AjQ==", + "license": "Apache-2.0", "dependencies": { - "@jest/types": "30.2.0", - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "natural-compare": "^1.4.0" + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/source-map": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", - "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/service-error-classification": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.5.tgz", + "integrity": "sha512-8fEvK+WPE3wUAcDvqDQG1Vk3ANLR8Px979te96m84CbKAjBVf25rPYSzb4xU4hlTyho7VhOGnh5i62D/JVF0JQ==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "callsites": "^3.1.0", - "graceful-fs": "^4.2.11" + "@smithy/types": "^4.9.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/test-result": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", - "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.0.tgz", + "integrity": "sha512-5WmZ5+kJgJDjwXXIzr1vDTG+RhF9wzSODQBfkrQ2VVkYALKGvZX1lgVSxEkgicSAFnFhPj5rudJV0zoinqS0bA==", + "license": "Apache-2.0", "dependencies": { - "@jest/console": "30.2.0", - "@jest/types": "30.2.0", - "@types/istanbul-lib-coverage": "^2.0.6", - "collect-v8-coverage": "^1.0.2" + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/test-sequencer": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", - "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/signature-v4": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.5.tgz", + "integrity": "sha512-xSUfMu1FT7ccfSXkoLl/QRQBi2rOvi3tiBZU2Tdy3I6cgvZ6SEi9QNey+lqps/sJRnogIS+lq+B1gxxbra2a/w==", + "license": "Apache-2.0", "dependencies": { - "@jest/test-result": "30.2.0", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "slash": "^3.0.0" + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-uri-escape": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/transform": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", - "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", - "license": "MIT", + "node_modules/@smithy/smithy-client": { + "version": "4.9.8", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.9.8.tgz", + "integrity": "sha512-8xgq3LgKDEFoIrLWBho/oYKyWByw9/corz7vuh1upv7ZBm0ZMjGYBhbn6v643WoIqA9UTcx5A5htEp/YatUwMA==", + "license": "Apache-2.0", "dependencies": { - "@babel/core": "^7.27.4", - "@jest/types": "30.2.0", - "@jridgewell/trace-mapping": "^0.3.25", - "babel-plugin-istanbul": "^7.0.1", - "chalk": "^4.1.2", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-util": "30.2.0", - "micromatch": "^4.0.8", - "pirates": "^4.0.7", - "slash": "^3.0.0", - "write-file-atomic": "^5.0.1" + "@smithy/core": "^3.18.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-stream": "^4.5.6", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jest/types": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", - "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", - "license": "MIT", + "node_modules/@smithy/types": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.9.0.tgz", + "integrity": "sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA==", + "license": "Apache-2.0", "dependencies": { - "@jest/pattern": "30.0.1", - "@jest/schemas": "30.0.5", - "@types/istanbul-lib-coverage": "^2.0.6", - "@types/istanbul-reports": "^3.0.4", - "@types/node": "*", - "@types/yargs": "^17.0.33", - "chalk": "^4.1.2" + "tslib": "^2.6.2" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "license": "MIT", + "node_modules/@smithy/url-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.5.tgz", + "integrity": "sha512-VaxMGsilqFnK1CeBX+LXnSuaMx4sTL/6znSZh2829txWieazdVxr54HmiyTsIbpOTLcf5nYpq9lpzmwRdxj6rQ==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@smithy/querystring-parser": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "license": "MIT", + "node_modules/@smithy/util-base64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.0.tgz", + "integrity": "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", + "node_modules/@smithy/util-body-length-browser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.0.tgz", + "integrity": "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.0.0" + "node": ">=18.0.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "license": "MIT", + "node_modules/@smithy/util-body-length-node": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.1.tgz", + "integrity": "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/@smithy/util-buffer-from": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.0.tgz", + "integrity": "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==", + "license": "Apache-2.0", "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" + "@smithy/is-array-buffer": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" + "node_modules/@smithy/util-config-provider": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.0.tgz", + "integrity": "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@paralleldrive/cuid2": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", - "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.11.tgz", + "integrity": "sha512-yHv+r6wSQXEXTPVCIQTNmXVWs7ekBTpMVErjqZoWkYN75HIFN5y9+/+sYOejfAuvxWGvgzgxbTHa/oz61YTbKw==", + "license": "Apache-2.0", "dependencies": { - "@noble/hashes": "^1.1.5" + "@smithy/property-provider": "^4.2.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.14.tgz", + "integrity": "sha512-ljZN3iRvaJUgulfvobIuG97q1iUuCMrvXAlkZ4msY+ZuVHQHDIqn7FKZCEj+bx8omz6kF5yQXms/xhzjIO5XiA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/config-resolver": "^4.4.3", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=18.0.0" } }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "node_modules/@smithy/util-endpoints": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.5.tgz", + "integrity": "sha512-3O63AAWu2cSNQZp+ayl9I3NapW1p1rR5mlVHcF6hAB1dPZUQFfRPYtplWX/3xrzWthPGj5FqB12taJJCfH6s8A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, - "funding": { - "url": "https://opencollective.com/pkgr" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@prisma/client": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.19.0.tgz", - "integrity": "sha512-QXFT+N/bva/QI2qoXmjBzL7D6aliPffIwP+81AdTGq0FXDoLxLkWivGMawG8iM5B9BKfxLIXxfWWAF6wbuJU6g==", - "hasInstallScript": true, + "node_modules/@smithy/util-hex-encoding": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.0.tgz", + "integrity": "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==", "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "peerDependencies": { - "prisma": "*", - "typescript": ">=5.1.0" + "dependencies": { + "tslib": "^2.6.2" }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - }, - "typescript": { - "optional": true - } + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@prisma/config": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.19.0.tgz", - "integrity": "sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg==", - "devOptional": true, + "node_modules/@smithy/util-middleware": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.5.tgz", + "integrity": "sha512-6Y3+rvBF7+PZOc40ybeZMcGln6xJGVeY60E7jy9Mv5iKpMJpHgRE6dKy9ScsVxvfAYuEX4Q9a65DQX90KaQ3bA==", "license": "Apache-2.0", "dependencies": { - "c12": "3.1.0", - "deepmerge-ts": "7.1.5", - "effect": "3.18.4", - "empathic": "2.0.0" + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@prisma/debug": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.19.0.tgz", - "integrity": "sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA==", - "devOptional": true, - "license": "Apache-2.0" - }, - "node_modules/@prisma/engines": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.19.0.tgz", - "integrity": "sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw==", - "devOptional": true, - "hasInstallScript": true, + "node_modules/@smithy/util-retry": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.5.tgz", + "integrity": "sha512-GBj3+EZBbN4NAqJ/7pAhsXdfzdlznOh8PydUijy6FpNIMnHPSMO2/rP4HKu+UFeikJxShERk528oy7GT79YiJg==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.19.0", - "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", - "@prisma/fetch-engine": "6.19.0", - "@prisma/get-platform": "6.19.0" + "@smithy/service-error-classification": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@prisma/engines-version": { - "version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773.tgz", - "integrity": "sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ==", - "devOptional": true, - "license": "Apache-2.0" - }, - "node_modules/@prisma/fetch-engine": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.19.0.tgz", - "integrity": "sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ==", - "devOptional": true, + "node_modules/@smithy/util-stream": { + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.6.tgz", + "integrity": "sha512-qWw/UM59TiaFrPevefOZ8CNBKbYEP6wBAIlLqxn3VAIo9rgnTNc4ASbVrqDmhuwI87usnjhdQrxodzAGFFzbRQ==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.19.0", - "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", - "@prisma/get-platform": "6.19.0" + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@prisma/get-platform": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.19.0.tgz", - "integrity": "sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA==", - "devOptional": true, + "node_modules/@smithy/util-uri-escape": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.0.tgz", + "integrity": "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.19.0" + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@sinclair/typebox": { - "version": "0.34.41", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", - "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", - "license": "MIT" + "node_modules/@smithy/util-utf8": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.0.tgz", + "integrity": "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "license": "BSD-3-Clause", + "node_modules/@smithy/util-waiter": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.5.tgz", + "integrity": "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g==", + "license": "Apache-2.0", "dependencies": { - "type-detect": "4.0.8" + "@smithy/abort-controller": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", - "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", - "license": "BSD-3-Clause", + "node_modules/@smithy/uuid": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.0.tgz", + "integrity": "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==", + "license": "Apache-2.0", "dependencies": { - "@sinonjs/commons": "^3.0.1" + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@socket.io/component-emitter": { @@ -1794,6 +3434,18 @@ "@types/express": "*" } }, + "node_modules/@types/multer-s3": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/multer-s3/-/multer-s3-3.0.3.tgz", + "integrity": "sha512-VgWygI9UwyS7loLithUUi0qAMIDWdNrERS2Sb06UuPYiLzKuIFn2NgL7satyl4v8sh/LLoU7DiPanvbQaRg9Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@aws-sdk/client-s3": "^3.0.0", + "@types/multer": "*", + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "24.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", @@ -2382,6 +4034,26 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -2434,6 +4106,12 @@ "node": ">=18" } }, + "node_modules/bowser": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.0.tgz", + "integrity": "sha512-yHAbSRuT6LTeKi6k2aS40csueHqgAsFEgmrOsfRyFpJnFv5O2hl9FYmWEUZ97gZ/dG17U4IQQcTx4YAFYPuWRQ==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -2511,6 +4189,16 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -3434,6 +5122,15 @@ "node": ">= 0.6" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -3623,6 +5320,24 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-xml-parser": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz", + "integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^2.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -3632,6 +5347,15 @@ "bser": "2.1.1" } }, + "node_modules/file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -4014,6 +5738,12 @@ "node": ">= 0.4" } }, + "node_modules/html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "license": "MIT" + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -4068,6 +5798,26 @@ "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==", + "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/import-local": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", @@ -5297,6 +7047,24 @@ "node": ">= 10.16.0" } }, + "node_modules/multer-s3": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/multer-s3/-/multer-s3-3.0.1.tgz", + "integrity": "sha512-BFwSO80a5EW4GJRBdUuSHblz2jhVSAze33ZbnGpcfEicoT0iRolx4kWR+AJV07THFRCQ78g+kelKFdjkCCaXeQ==", + "license": "MIT", + "dependencies": { + "@aws-sdk/lib-storage": "^3.46.0", + "file-type": "^3.3.0", + "html-comment-regex": "^1.1.2", + "run-parallel": "^1.1.6" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.0.0" + } + }, "node_modules/multer/node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -5877,6 +7645,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6019,6 +7807,29 @@ "node": ">= 18" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -6396,6 +8207,16 @@ "node": ">= 0.8" } }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -6587,6 +8408,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", + "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/superagent": { "version": "10.2.3", "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz", @@ -6826,9 +8659,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "optional": true + "license": "0BSD" }, "node_modules/tsx": { "version": "4.20.6", diff --git a/mission_10/package.json b/mission_10/package.json index dc56f1f9f..4fb9505eb 100644 --- a/mission_10/package.json +++ b/mission_10/package.json @@ -13,6 +13,7 @@ "license": "ISC", "description": "", "dependencies": { + "@aws-sdk/client-s3": "^3.940.0", "@jest/globals": "^30.2.0", "@prisma/client": "^6.13.0", "bcrypt": "^6.0.0", @@ -23,6 +24,7 @@ "express-jwt": "^8.5.1", "jsonwebtoken": "^9.0.2", "multer": "^2.0.2", + "multer-s3": "^3.0.1", "passport": "^0.7.0", "passport-jwt": "^4.0.1", "socket.io": "^4.8.1", @@ -36,6 +38,7 @@ "@types/express-jwt": "^6.0.4", "@types/jest": "^30.0.0", "@types/multer": "^2.0.0", + "@types/multer-s3": "^3.0.3", "@types/node": "^24.3.1", "@types/socket.io": "^3.0.1", "@types/supertest": "^6.0.3", From 0ccfe219f8aa6266552fee93976535ab3003aa84 Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 27 Nov 2025 17:32:17 +0900 Subject: [PATCH 118/130] =?UTF-8?q?feat:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=20=EC=9C=84=EC=B9=98=EB=A5=BC=20?= =?UTF-8?q?=EB=A1=9C=EC=BB=AC=EC=97=90=EC=84=9C=20s3=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=EC=86=8C=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission_10/src/controller/imageController.ts | 21 +++++++++++++++ mission_10/src/controller/index.ts | 3 ++- mission_10/src/middleware/s3.ts | 28 ++++++++++++++++++++ mission_10/src/router/imageRouter.ts | 15 ++++++++--- 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 mission_10/src/controller/imageController.ts create mode 100644 mission_10/src/middleware/s3.ts diff --git a/mission_10/src/controller/imageController.ts b/mission_10/src/controller/imageController.ts new file mode 100644 index 000000000..ebab2136c --- /dev/null +++ b/mission_10/src/controller/imageController.ts @@ -0,0 +1,21 @@ +import type { Request, Response } from 'express'; + +class ImageController { + uploadImage = async (req: Request, res: Response) => { + if (!req.file) { + return res.status(400).json({ message: '파일이 없습니다.' }); + } + + const file = req.file as Express.MulterS3.File; + + return res.status(201).json({ + message: '이미지 업로드 성공', + file: { + url: file.location, + name: file.key, + }, + }); + }; +} + +export const imageController = new ImageController(); \ No newline at end of file diff --git a/mission_10/src/controller/index.ts b/mission_10/src/controller/index.ts index 7cee66bc9..9d4bcaaeb 100644 --- a/mission_10/src/controller/index.ts +++ b/mission_10/src/controller/index.ts @@ -1,4 +1,5 @@ export * from './articleController.js'; export * from './productController.js'; export * from './userController.js'; -export * from './notificationController.js'; \ No newline at end of file +export * from './notificationController.js'; +export * from './imageController.js'; \ No newline at end of file diff --git a/mission_10/src/middleware/s3.ts b/mission_10/src/middleware/s3.ts new file mode 100644 index 000000000..0949940bc --- /dev/null +++ b/mission_10/src/middleware/s3.ts @@ -0,0 +1,28 @@ +import { S3Client } from '@aws-sdk/client-s3'; +import multer from 'multer'; +import multerS3 from 'multer-s3'; +import path from 'path'; + +const s3 = new S3Client({ + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID as string, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY as string, + }, + region: process.env.AWS_REGION as string, +}); + +export const s3upload = multer({ + storage: multerS3({ + s3: s3, + bucket: process.env.AWS_S3_BUCKET_NAME as string, + // acl: 'public-read', + contentType: multerS3.AUTO_CONTENT_TYPE, + metadata: function (req, file, cb) { + cb(null, { fieldName: file.fieldname }); + }, + key: function (req, file, cb) { + cb(null, `contents/${Date.now()}_${path.basename(file.originalname)}`); + }, + }), + limits: { fileSize: 5 * 1024 * 1024 }, +}); \ No newline at end of file diff --git a/mission_10/src/router/imageRouter.ts b/mission_10/src/router/imageRouter.ts index e73d6d5fd..144f9d275 100644 --- a/mission_10/src/router/imageRouter.ts +++ b/mission_10/src/router/imageRouter.ts @@ -1,11 +1,13 @@ import express from 'express'; -import multer from "multer"; +import { imageController } from '../controller/imageController.js'; +import { s3upload } from '../middleware/s3.js'; +// import multer from "multer"; const router = express.Router(); -const upload = multer({ dest: 'uploads/' }); +// const upload = multer({ dest: 'uploads/' }); -// 이미지 리사이징 기능 구현 예정 +/* // 이미지 리사이징 기능 구현 예정 router.post('/', upload.single('image'), async (req, res) => { // console.log(req.file); if (!req.file) { @@ -13,7 +15,12 @@ router.post('/', upload.single('image'), async (req, res) => { } res.status(201).json({ message: 'Upload OK', filePath: req.file.path }); -}); +}); */ +router.post( + '/', + s3upload.single('image'), + imageController.uploadImage +); export default router; \ No newline at end of file From e848461b9800c5a0a657c087028fc393445a7013 Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 27 Nov 2025 18:01:14 +0900 Subject: [PATCH 119/130] =?UTF-8?q?feat:=20NODE=5FENV=EA=B0=80=20productio?= =?UTF-8?q?n=EC=9D=BC=20=EB=95=8C=EB=A7=8C=20S3=20=EC=97=85=EB=A1=9C?= =?UTF-8?q?=EB=93=9C=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission_10/.gitignore | 3 +- mission_10/src/app.ts | 4 +-- mission_10/src/controller/imageController.ts | 2 +- mission_10/src/middleware/local.ts | 36 ++++++++++++++++++++ mission_10/src/middleware/upload.ts | 6 ++++ mission_10/src/router/imageRouter.ts | 4 +-- 6 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 mission_10/src/middleware/local.ts create mode 100644 mission_10/src/middleware/upload.ts diff --git a/mission_10/.gitignore b/mission_10/.gitignore index d58e9d958..01557d99a 100644 --- a/mission_10/.gitignore +++ b/mission_10/.gitignore @@ -7,4 +7,5 @@ node_modules /generated/prisma /prisma/migrations -todo.list \ No newline at end of file +todo.list +uploads/ \ No newline at end of file diff --git a/mission_10/src/app.ts b/mission_10/src/app.ts index 7c97b396a..a5fd2e69d 100644 --- a/mission_10/src/app.ts +++ b/mission_10/src/app.ts @@ -40,6 +40,7 @@ app.use( }) ); app.use(cookieParser()); +app.use("/uploads", express.static("uploads")); function logRequest(req: Request, _: Response, next: NextFunction) { console.log(`[${req.method}] ${req.originalUrl}`); @@ -51,9 +52,8 @@ app.use(logRequest); app.use("/products", productRouter); app.use("/articles", articleRouter); -app.use("/upload", imageRouter); +app.use("/images", imageRouter); app.use(notificationRouter); app.use(userRouter); app.use(errorHandler); -app.use("/upload", express.static(path.resolve("uploads"))); diff --git a/mission_10/src/controller/imageController.ts b/mission_10/src/controller/imageController.ts index ebab2136c..7d97fc261 100644 --- a/mission_10/src/controller/imageController.ts +++ b/mission_10/src/controller/imageController.ts @@ -6,7 +6,7 @@ class ImageController { return res.status(400).json({ message: '파일이 없습니다.' }); } - const file = req.file as Express.MulterS3.File; + const file = req.file as any; return res.status(201).json({ message: '이미지 업로드 성공', diff --git a/mission_10/src/middleware/local.ts b/mission_10/src/middleware/local.ts new file mode 100644 index 000000000..603ba06d7 --- /dev/null +++ b/mission_10/src/middleware/local.ts @@ -0,0 +1,36 @@ +import fs from "fs"; +import path from "path"; +import multer from "multer"; +import { NextFunction, Request, Response } from "express"; + +const uploadDir = "uploads"; +if (!fs.existsSync(uploadDir)) { + fs.mkdirSync(uploadDir); +} + +const storage = multer.diskStorage({ + destination: function (req, file, cb) { + cb(null, uploadDir); + }, + filename: function (req, file, cb) { + cb(null, `${Date.now()}_${file.originalname}`); + }, +}); + +const upload = multer({ storage }); + +export const localUpload = { + single: (fieldName: string) => (req: Request, res: Response, next: NextFunction) => { + upload.single(fieldName)(req, res, (err) => { + if (err) { + return next(err); + } + if (req.file) { + const file = req.file as Express.Multer.File; + (file as any).location = `/uploads/${file.filename}`; + (file as any).key = file.filename; + } + next(); + }); + }, +}; diff --git a/mission_10/src/middleware/upload.ts b/mission_10/src/middleware/upload.ts new file mode 100644 index 000000000..e0465827a --- /dev/null +++ b/mission_10/src/middleware/upload.ts @@ -0,0 +1,6 @@ +import { localUpload } from "./local.js"; +import { s3upload } from "./s3.js"; + +const upload = process.env.NODE_ENV === "production" ? s3upload : localUpload; + +export default upload; diff --git a/mission_10/src/router/imageRouter.ts b/mission_10/src/router/imageRouter.ts index 144f9d275..ee4b4e093 100644 --- a/mission_10/src/router/imageRouter.ts +++ b/mission_10/src/router/imageRouter.ts @@ -1,6 +1,6 @@ import express from 'express'; import { imageController } from '../controller/imageController.js'; -import { s3upload } from '../middleware/s3.js'; +import upload from '../middleware/upload.js'; // import multer from "multer"; const router = express.Router(); @@ -19,7 +19,7 @@ router.post('/', upload.single('image'), async (req, res) => { router.post( '/', - s3upload.single('image'), + upload.single('image'), imageController.uploadImage ); From 167d90227d32273a89d181f4591c351af1685b45 Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 27 Nov 2025 18:01:32 +0900 Subject: [PATCH 120/130] chore --- mission_10/infra/s3/policy.png | Bin 0 -> 54908 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mission_10/infra/s3/policy.png diff --git a/mission_10/infra/s3/policy.png b/mission_10/infra/s3/policy.png new file mode 100644 index 0000000000000000000000000000000000000000..04af13ffd181e89cc8bacb896ad722e0c78f7638 GIT binary patch literal 54908 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 Date: Thu, 27 Nov 2025 19:09:51 +0900 Subject: [PATCH 121/130] =?UTF-8?q?feat:=20production=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EC=97=90=EC=84=9C=20rds=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission_10/.env.sample | 1 + mission_10/prisma/schema.prisma | 2 +- mission_10/src/lib/prisma.ts | 11 ++++++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/mission_10/.env.sample b/mission_10/.env.sample index a88795e05..5ef3f80a1 100644 --- a/mission_10/.env.sample +++ b/mission_10/.env.sample @@ -6,6 +6,7 @@ JWT_SECRET="your-super-secret-key" # POSTGRESQL DATABASE_URL="postgresql://user:password@localhost:5432/mydatabase" +PRODUCTION_DATABASE_URL="YOUR_PRODUCTION_DATABASE_URL" # AWS S3 AWS_ACCESS_KEY_ID="your-aws-access-key-id" diff --git a/mission_10/prisma/schema.prisma b/mission_10/prisma/schema.prisma index 7702d7a5c..657f4f3c6 100644 --- a/mission_10/prisma/schema.prisma +++ b/mission_10/prisma/schema.prisma @@ -11,7 +11,7 @@ generator client { datasource db { provider = "postgresql" - url = env("DATABASE_URL") + url = env("PRODUCTION_DATABASE_URL") } model Product { diff --git a/mission_10/src/lib/prisma.ts b/mission_10/src/lib/prisma.ts index b904402d2..b71f1485f 100644 --- a/mission_10/src/lib/prisma.ts +++ b/mission_10/src/lib/prisma.ts @@ -1,5 +1,14 @@ import { PrismaClient } from '@prisma/client'; -const prisma = new PrismaClient(); +const prisma = new PrismaClient({ + datasources: { + db: { + url: + process.env.NODE_ENV === 'production' + ? process.env.PRODUCTION_DATABASE_URL + : process.env.DATABASE_URL, + }, + }, +}); export default prisma; \ No newline at end of file From 383824a739a20439ca68d3662f68e35b31a6f764 Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 27 Nov 2025 19:10:11 +0900 Subject: [PATCH 122/130] =?UTF-8?q?chore:=20rds=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A6=B0=EC=83=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/rds/secure-group-inoutbound.png | Bin 0 -> 46501 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mission_10/infra/rds/secure-group-inoutbound.png diff --git a/mission_10/infra/rds/secure-group-inoutbound.png b/mission_10/infra/rds/secure-group-inoutbound.png new file mode 100644 index 0000000000000000000000000000000000000000..b08a0ed14b0bb6601397d54578cf25e354021a15 GIT binary patch literal 46501 zcmb@tbwE_z8#Ouzf=CG{Atj z$_n$t&Gb-vf)5BrA0po(=T~|nvXT&p%R30f%NGK<28X=1AP{?c2xLba z0^y8-Kya-RYGt^=7sys3Dz*>^3iiVv93(CQ4;)0Y6O|N1+D0Kjra`Ijs0jv_gou9n zDDO18x8UgXTw$s6$dWal_{lbDBqUV?EfF&Mcw6BM4zY}k{PQ~A>*+&L)DJC#1_zTMczXN5jqjgjk}@Mca)aZy~t?fhVNC z&-lU1B}$~c_uqHm1v%*9(8H%U^iTi&!O!OR|NQb9|D*K(iyt1a?|9Zi3KYdPHQ@vW zJDx{J$f(GGrqHlZ{d;}M7klG=c=0jXUvz{5aiWyf)KX>dPR>8V2WP4}@{mx|6}{r& z3GeSG+}ks=vMTPFpGU2jeFhH?Kcn|=vqwJJaT2|hWXZ@d&^O%pnV1;p<3l4Qg&q?Z z$84@GAz340sK`o8OglX@lO`+r;rTzOec#~EoA{NOC?Grfm~e03%HGud1YXbC`SIqT zu;Oz1wy`mduWA22IrGVK%+H?^)}r|PbI$6vrh4h{dNMM|n}Z#HwzoqP6D!8+|NZ6s zyV9}~5fPEjzC0QlRb}RD+u&N1()#+ZwwtTl!!2^H|6Ow4aBnXk90>6!EjQq%PRHjw#uyew=T943`jV}8Zi z93>-l9v?qtEGs=awTq5>@$Ut=yt1;mVpV2>cj8{4k-ZQM z4BXK%rXoIilL}QvCfnk&vdEYJJO6uPB28>8hjGR1E=myS9ngs)yZ?I#9eGN4FfQGF zRMm~m%JT9-K0f8N|IVTI#O{`ssI;`zyuow}V}8(i2M30-f&UJgb@0>P@;y|#HmEvB zOHSmQ4deIkCmdnrj7lS&ijs6ndVbEaj3s&aiiWxGw1jPKnSO}(7ShoxD$1uQ67(kh z*Fi#0#q)H7wMYr1nCESjKIgtIFAp1z5Ho1Jf~Qg8&VRd*5FBTwF<~M=Nks`xH({Q@ z!|T5LuMs17bQXO^8PE*ZN5T$_24+S~h)!|CEt#F0XsnOt&U+e`_wz1VF zpppNWu}X`1OID!FnxPP$U*zo#_fqog?6J_li{_ap9d*GEe~<2W%o$i--vm?-`-gGt z?DCr`h6hKVafu7KaZ4&QroCmrSIFm)Z8s7QRNhwevNXdd*qmYcVyY(~U+VhppNX`3 zO&CmNv=wK^FGsn(ZqYjORw}<~D6^$lIXNUm2)y-67f;w)x8OGxdn+*Y+m^Xd{eSCp zKBRRtH|ACl=W&Lr;d$w+LqT$I<3d+w-lTU3ja%*gnmErROk%+gbiOEH;r(|~;!c{_^wB&4|?d|%imBsCSd5QABAD*h61}91}Bgn7T(CvWMoO`8!x8F_7!%cR$&{fTr{|J ziYvAfLE+_6ZGYLs-x#NN1AP+2P_n6feb0ElwPJ4Z^-$zi?G{1)t z_Ipi#(*2eL0&RqOa$k41fw0wEm4zP|@?+)p3IW1AG5e0DuDaScz3UMqhFu30QdEDB zuAmTy$j4;eiuW#r#K(xhQC(ftcBNJD{NQB0F;-6B=28SJN) z0-BGK#+qH}Jp+O5wJLpqKLjhoSkdrv;UbcrA+mxUcVA02;A&Cxm=Gq64e6)Pz2Dq_q#7JW*I8{IizUN zz8GZcreq;o2Ah6^VUZ`O;oF?^8~Ci-+cE3vlaFy4uw}fn)Nxy{V0%wV3#Z+^03YkV zBmr*EL4qqRZ%4hoy4kn)*Ejg%0c^-#bY>suzC~ zoHfd2;uy?{ud+;~VGKT;(%Ccl{=PGrxKhu_|Js#waX~KfO)V_&%s;q(k9h&-#rmXVRKf*7o2CDC4RYME$vkOF-rcEGR&8#31%fY#`Fn z!MxTY<#ZY;H9)bkJ^3Cu<=Aq1Fhf+KDk)_6PG<%4baza+2Dh-fI!4YrDXjGBRG`KMckQa@Bfw9f5FITp+0eZG zlc~L<=ri{(ONHi%&bhhFdwf z!@sO{JQ~vzgis%rn9);Dl0<2L%DUbxqRFe=dzUdHzq@m@3H4NUWIEk}rk9o4kEqPl zZZ$3*E-VcuCu^m++O5d-8kxYH9k$ZuJcp|W>sv^T?BJoq)*bbsJV)hHS!3H9ytm(v zlVAambz3gSeZ@ts`ZdAzyTv=C-F!0*yD`JTiNvSe1-sK3S%bZkf^5#6)EWi`k;kzi z8ZJ9_oQVf8UUd(_nF<(j3@rPgj>JP&lg`OaCea?|ej{Zti!IGFr|tgy#f$BOz@M&iU|g=!*Dw%>H2U=EvFoE|a_?C;M-y z8RC7ezwMbsFSK9uyqaK(7y@VJJv;zyrqO%o!!@TYmly1#mS!6oEapNqlol>LtL~FM zjv|k*+t%|UhSoRMsh}4Je3w7&z8LJL^$qkXEfy6PP8O&)NEt!*G>wS%33=@LlnP`v z0z(2O?6*fQe$?97e95DF|K7}s>zsr=AM~efZ5B?GEcA3|$7JEhMDiA~#%0368C%p& zZ*T8zB6N5qy;c~PH_P>S8`u6XYFV8u_MlM7a-o!oR`{Lcc-_2?YoD8iW$#MXXQ3Rc zBKR_KC+Ab*nRpMIo9peJ^zO@E-0U+$Gh?=7N~~BhYzJ?C1n(UPF|){7ty<2!~Z1I{yzEa&?@~~#^afp z8klk7-Q8U*y))ydgr2h#yAEju_s=%gWP9*9q(Q9g)VNS`gMtkz30MS$ErX-5EJGRRgQT$L^x3KYXlwegM z_g&9)w~IFE`nv-pc}4j@8waho{+p{SD?*V%ZFNx3_MYZf5FDNp!knBhDWi^ANz6Kg ziFJ0rRkKo6=MGr~UYH zPuM-a508h+tX4NtsRj1IB$RJa66h&O>#2(*l==pQ4uZ5jhj>NP+UgF zK^wPLZOnV)gocBIBN5Mt>~&lJNNNHB)62&nor-kINE_x7t);Bo?uT~$(K|>I6`9>7 zra+Aq6C1y^A76=tW306`!Jjx`;D-V9WafIpsk-iD(iKVtkHJ%71((`F{se`$EKh;E@%^Y zh?;ZPNme)Oa0SR-80&NmYCt~u3d0RIg|cyZF7-Pud9(zOHL6R5WJN0UY zI`%FEBZh#OD5KeQzag9Cx`OtIZnsvWZ}DJsb8L)h&5Y)uq!>ZP$KUbiq{%aJtFBZ2 z9K13nTJAwpF=H+rjwFQP=y>aPakz#Zs%>GtEi{tWsykVD6C|Ve?tMXU)+1@EF;@p@ zXY6npNFZvPSI$Ss0T4o-ouZ|WCMBVc`p2cSt}C7ubm4;eA~ATo2p`4c1>=Ta9H$gtjHUHA6q>oAj1~BB0WIcAQY}njq{3V=t>H zJmnd&$C~vzv7&%L8{!522SdY3-opuOJWw5uR)`y2pC05O^oE6DHQrvkeiay;jGdZ1 zALXgTk5#c@{afW!KhEzz!=$XMzK5fAt=;K@L$2|=K{JI)o;olUI=YyvR2VFccw;sX zPDWiUxyMg`f5xj>mw-+*M>VFa`zPX+0@pHfbF1JGquCm}Uoc_Ur6^Ox1=@t)!$QCv zmKqEZWB(FzeZDQ2C3W3Jxwqi?%*&@@K}Lbzb+R9kFFwI#8`u9}q3%BY>^(KL?ANeh zbE?^jGx^LjkdF!Rt&fh_>e1B`=ql*5G^?$|FS^#}E@p6--giwG|N6u3D8*Oc@F8AF z%Z1p8jeNMZa^I8Qr2kW=WZYoQiM0|W)_aCG(3Znz`M6H5KRW-+G3I?~F_zmj8FPl;DE&?jC@7- z@3S1?y-Ob_tOa`WStr$Xt_EOQMdBA$&PFU z5YZ4*JePPAZcpg@6bo0nl08Vt$uT@(;qyFZ%t#lokI{9UQ)+&;rsM!Ai41k$&Ydx^ zvHeMsX`8OS!vM#IO)9eGuTM4SWRU^>^7>mV8oM;82O~@7ym^)SDA`3w%zeHq%%JhH z8K2q@O9>7#F3md^7ioQbPv7WNRz_`a={p`Wcr40@Qka5wNt9SdnpQHen0Ef;7WV0S zfo6lN^T}!2H#FL|oC^4DTqe<>?);0H@16>>sxD(yyT>2RX&qtiW6rw^7uosQhJDaE zc4sk9x<3hd<+P8=&&<+q@3LUllvH`AEl^HS$*k_|Ntl?tG{|`I>5~veC?axwK9yBn z6Sv}{4|!uUii!>k1?sP1%$vpKz?I|k!R{7Kd`o4a)+vVZxJdAGKD ziHC~4LB@a@-+G-L$J}g!n#gj%lkw{Kkx6^_P*(1uEm>0@GK==~{La+W-aSurE7y%=lwN9VfWzbNM$*G}&v3tA zXX~}S14L9#4(=h(URL>R&`XB;cLUAy{=_SrlJPx*J*143aewZwy{!pNle(T1JNGGy ziHSWy=V%MjsIxS_tSB*m{6R{JxXJ837}SJVSaduwW0ReJ)_P|{BWiW$*twJ}F|qOV z_Q&mcv~v>^-(<-A;eJMiNe$h@t2CO>6g3?2RZgMy+t3^kxrQEJa6#Qg?ChvPU@bEl z=!)LJXS$XZv9|iWbLpS#ky>A$0N?1({=)7$cU|9Lz1Y5s7R;~d1|yQ9hO0`(0i$KF z-9l4gfAIpd8}#e2q@<6sHjH3m7cO2csB1(tVGwglC_1nnSQM697Qu8@y`Vak&|3lI zYXA}u61W9F=|6uF8F|}ijx;h-BCqg;o`KbHk0(81eIjI1jbwB3`mBG5uKIaxg=$** zkc_M>+g7HAgwgIfALP)=QAQQ_>@21Lp|@`d_b>92G}2XaPYa5grc<80j|g1T2X zN%;~FrgHcOBGhS;pjP#cMbZ_#$GJ}J6slGW&MT5$mE|e-rg(GaqAsr#xB!8OC|_-t&Jbfs0vo6 zGn4g4!o+>pgolQMFE=Kk4&PG4^?;F?o>1u-0PH9glkxaZVe>_k8fZ^YjQ!E+sY!Xbz9Fmm(! zf&SZS@O)gVzMlMo4JUYcD{VcKgsy`Dk9ng|EsXf7m|n2rP$E__t&Ducxup9tfD~T9 zV3C49#FzSYCU3FPAxi&oe2gpSriN&)U{DBiO%= zkyGEjT$QGWg5u5FjN!CzZwm`)+0`dIPHkQW3vEBz*;!TJ)Z_vJgS;K8prD}L!8kHi zUcAy#M@PqV9GsEb3b}?*4Ls)|Cn+TV)xFhEPTe`4;{%6<#O@+>DV~d3tyfR-cky3s znLI@a{2mg}(Jdm`g{~PBKeeQ*qNzDJQ~V?-ICyJ3hb;5m8Q)K493r$3IRMyLPsn_V43^E?ic4B6-F>HI$F9o*_ca-M$iQNHP(^};iflIOmEX2-hTEJ1!a5oj26fy6x7tZCzfiF z#nTz$U8d-PDW1H#=Hh!3Aoa7FH2U$nUY#&lKF4spp!&Kn!Tj9s*O(eN|5C<^xnIK zp|zDvCU0VTZf2xT2_r}1Z@@Ct{lm@WS14*^TYP`tPVnL-xVfRN6|&+6CF@{aMfx9c zZ8Kev0>zZ=932fhN-s((O1_+K-kctHmIZSm2lVJ0u2Vv*Orb5g1|%a*mLxfAhPj?i zi>FY>{erTF`ns{cx;pukhhhE1G&V5veLr-D=_-(#6)E~zbb-zQ>aI)j&@|pX@(b$4 zFkvg3$Kb}5e1_6&M(Jv`!BuO-ot|ZJRZdd3sIPoYUuORCQSW4jjdJeOqxB#*3M ze=a{izX3z8yu7>`Cz&NlMRR@M@N{lt&3`acEYJ>|w*1Y2?f|FE{`>I|s`*FZuFh`_ zF+r4*#1yiK)!QqE{hiJZl2|yf17e~7iHFwkVBx-sm77*S` zos|3379T78Kib9{py*thgwRlBs+IwIxXE@MAxkkVCOtJp9=2>tW%~kPyi*$%!vCh{-505AVn(r4OLO~#Opgt$2Q>(_B> zYx2h@DEgNF^ryFKMQQ88LL{vQ=gQvRn-{Mw2*{-nn5?wvkb|mPz2Q9`!dkkplFP+` zcW`h8;jh09a!i?@=U!dKnrXO!5EEMj5%Wk;3Vxq!r`ZmxHRwZ!;7~hxHM%#vrT&NK zZ!t5=-=3R_e~dz$ZARLkfW%5W;Uxd!u z(a}*+F|l98e}I*edZQHtLg8R7;{NWG83zJE7%Io+bHpnWLokLadA6JNhh%Xs~8 zZPAAyH(T*b^)EQPj5eJrMC<9vk;UW}(XM~P*Yp9g8uRaCOiwHK=}q`nqh)72eYg&2 z$?8Vn_aMXd9cfVsF~sJ+JR)%%zK=*n4p?}WzFy%UeG`z$cuA4HDwBu-8$IZC->|-g z{m+Rn<>lqWqN2RBvgU|Nc#e*Gs;k*`bam&=rmQ=5q(#KUWHghxaJy>Hv`Q_`kg)Jz z0j;gC8*evUb#(`)ocY!y@JNkX*)gAWlbvjimKp@c%X-+`vs_(0o}Qge8QY#dzCq`7 zI81Y`sEXMMh$cgt<1 zJuZmJ5M{M0-4#8IKQo;TJ?BdYJV-N@dTc;o`%qQrD5I?WNznm)f41^h8Ot+b%#IcT zPn(NpBsr)LQ;zwga=v_PT1^c;kQvwt@`3)q>H#BzBbQ!TUhbY%AX$j8Nk}049x9zy zUXJPsd*$YK%^Dch2{gFw$$d}AGZ$7uuaCTU^o)$H-QC|88(eHSFHueT?)hVd^Tv)Y zzxuzSXPvZ$L3DM8#v0Ucad?hI62Aa}{`fRaSf%P-ytOs`kk1;xoV&ujgfbnOm>4`J zx2+UT=-kZgaFeHHtz#VuP$6{F8khd&9T_&QT;pVWtCCoTUQ5A6+!bOU^m7b#`Y1BN{i!&DA?F~;JGR1HlQR{U_C z(|90fJ)%EYltCM0@|foVvJ566mV<_O38?b`xrB(ZGZf=0G#;y{s@m!8;~|0Ph~Z@e z`yHRhME>Xzhux(#C`G~A5c#Cfj4==|cype#wvK!FM>;+rAh>OO+_$F8Xt+#R31E~` zXtNF=*CLmy4q8WAlALXgCMlSBKa#v!#llj#=urZ+($S%h?bcitd7q+NP@uT!Mt@u( z!X!piK}Vhjm!U-RXCn^b`%~cz*`w36$6`vuNzpt=a_J+b&V8(3hY~V?SprnHjLxgd z5Kxg`u4K`Gxt?CD+SiV(_kchbJuLA7b8UDz+yY5>@E)v>KDy?u2Z5 z9|r{mf!fnxaXyxvgR|Ie-Ng@;xcS?7AVM-npIji0wvlODrdAae-t(_Q=_`eUM9%v6 z>JpNYq9PI-@s^(YEw|22PSq6Ntb9#B$#DnC>FAOpO?lV(Fop~+lHflHbu91fw4w~r zw03Xx7D>CW!%A)-K-Rk5T;cF)6ub@}YScN{!?)Yn5_IFo0$LU2O?K*?tU`uPTW9hU zlu&*ki?!s@gz{Z~F54-6^$<>x11n~$O#224)F5~)hO3fGjT<;GJ!i}Di8wnKxZ;F2 zhU5xMqKj^0QpSuRTVr+Pp)^k4MOmhnXJ%#qtJMmg=J>Wunlt&W^W_mRI-2 zm$^gGucKmruSM)qlI3jRe;}%#)nuS~d-ez)Uqy^>>+erL@ZbhXD)C5l(}mNFJr*rnBss*R29mxbAq#SgzHOs@7X z5>K}#zwMaNxSkUsoZh7f4Ej=>B%uYqAtePQYSC>+CXk8&_TS~Zi%VNwVo66e~SHAW27xIdV$1BJ7po@q5>X6cfQQKM;Ljt$)e`gu#{%#!S$HyTS zR8&OI%zXFeZPw3UzdCv+lAqzf2#n7|nV6UWYb9;MBqw(?W#Wse)T<=By4X>xZ1uyizVq>%M&5fw$>4mk#d@vQhPP*jW;W}=Qr0nCMH4ld5UhZKZf_*E?*B8 zYKIGUHGGqTm#2@yAqjjW(m<>POfRJYpw3h4)6{2hK_^mcT`{N@pbxPUzj^Zp6F2%Z z6a(WdQj0)7k_2HDySux)b+q*nC~3gC=BBFoMU`5Wx0OC%5b;=S-pjpP2+YX|@D=x&yKXqV}DUmUZ*R6X&bP zU};-{ce{KyVl{=lZfooilM0^A9`we-V3-*z}K98AHTihx2 zx{~=}=uEoHMal%tFKEDtNY#9xgC0OokMTb^eL|h#sNp_crd}^g_GpBQ?EN{VrSdf( zfMU+^par0NNI<}KX_AKxoJOr(uA{rG932pid(|u(gY2oOo(BG4CnEeIl?6OkKA)QO zj4M=u%-rY?YX|%RG-;twd2mZc0N{lUGvzmQjkh>*BNLQnWX!Aul0@F8dz zFD-_9xYq}S@OI_jWUcP3q7HAF=N1+kPRvRJIelZHN)vd_f|e=|UQ=^p;Tn+}XjL3p zZPs+4fF%Itj`izTKS71UV3FS#dA&ZhxU!b>N+@`IDpV{(HVH#jM&_faC^GSZg}sL_ zp6$>RU=0wrupkB=4%(8=5X2)!At94YN&KQ)g6XDEEIiQBtdj-ZJw1YX z6O_0Y6=ND2v=tsWxY5sS-UY3+AzB}}aYGxL5=u*Lh+URFAfvQ~%L`>{J~|9+bjhHi zWXh86tc{$=ST_6J+1%{KN_?$Y)t^sz{PgL=Fz}@NPjOvm2LvEX^VE0=lQ=&ENz!Ak zHn8Ew4ess(b5as<_Jp6?@eCrU&|F<|E4uptO^hp$q^~Srb=nh=hP9nJ7u}a3JK;M17 z3HQzT*74#@L+h%Cg>>{!X>&|W#McUYDpWKy(d-8D%1mibft!x@_81EdXj)p@*B5zw zZ>5Rts6iW}6kA9?O@EvMU8x}no8D(u5>G42#0@D~7S+u^+?r{z-ZShusFdn0m*XZl5 ziTmDz8lV=I8|wt97Vw!dGM4T5rbdjTh~=eXF@~R#=CVe-efw5VPfuf0e0bWN(~+0h zD}-ov3i($>fum?o4(RZ`J=$Pxg5((A2KR+7X8=+^PjYaPR}FGb`K|V;MJ%Y(p)n=O zVtdVvmtpKu!T2R14Y!%=<>hwk{y%43b=9gI>UTWgVi>nIJLj3c`ue`PzuAz@F!gyT zLfV(Mr-leXn0)&5>Cpv7t-%6wJpcatVnAEQ#K(_R6@;q|(&!&@+$J3#FX_&DLz}a>xUe-@!DQ6-`sy;g zsK&8hBq1>|dr~p{S5n781JaYw@13Kgt3QfI@ggH5LD!E~ISx@}PE@9#5szyjBY0uG zvavZXd;)*PLc=$fC8fQ!zzdiZ&8K8a$OK~SK~qSbvpCh=*?0gL;i;Z$Wo0t>#}Ba|KYrj3H#sgq5)!@!2ebJ3U3*M#+Dk>MMrV{?Q^&-BF9MDL|*cQDxse;2vw10qf@@@whng=b8h4`cvviQgQTAQbcD} zj5Mm%kVvtP?d7s;RMf4pE;VOgp)T}&e2_R@FRpA#GBL#->5=iAHd6y@4H+0Gb^;t3 zD0fH4TWYl<20C8Yb45iOf`&a{!DYE{;ZGQysK|U=a<1Z+gF9+GRfz^DMzQXv=p2FR zJ`FbXYim1gYgg3>x6%o#-Zd8#1xgkcXnc4qybPEqC@4>#27c$k?F!{HZ&?_KWw=09 z;`a#;hevV`)z;N*&Hg2@t1(!lR;j0B0h*|Zho3X!xJ++guztEb2aM2BzzF;XjITiC zkJBIt^cy0*({7#liJEj?)N7)2U<-bouG`bo^8i;t!UR(p6!R;~seByHJ9d)V4z>AI zMhh+yk_{h#rl@uPwlF0-`zM$=07Gfi*;$;j+HVbq{2`Y*I`bm|);Lnm>x4!LHYFfn z0bkfDREe$l95f@b?i>@~-EZGGKrIP~P?mIIG&v6yap|E~@6NfK%oaPpq2OBEjQTgu zPJS}ojrwh*UuwBTiWM%ad^z2w6!dfU^Ob6WB62QpL0-A%c^r~m#5JpY{`?(W5tq(z zxVA#i=jJUL8Me4M3L(*c)Y5d`Cj$9# zq1Iue#ra}tyLEeGhu_8JT`2GI2cLq#w{J5Dd2pJ~6J6mx=g3RseK|vjp+6w@xL4C8I&ZbOwKXy@g>us5`nX-&&coj1O?eEyO1=k0Yt6{q+CmvYNr|`1yRt{dXH@I!&j&#!la5|{%0#^yZQU^Z70kHM>o z)(p2q2Kb;q15;X%<$)@`WqIvlkJ*oWkWA@Bk*dPPc*%vA0H~g!)41%6<0GQ)*$bek zmFV&e@ilE_nu&bW!6c#45(Y)|`MEpu zY;+{TNOeN?_yw-bN>Bs%xkQpXOJPyb9AAH7 zE!L;`J!mQi0oX0D_t*-cN?M;-v3YDd#i(*|tvuiH~aMm}TEm^`VxC>p2jt1RWpRXwoH02vMK&jBgheF?lLTHuEU z8o#J0oGGGQ2?>dan`>H(l)4MzwG=33t$jnFKS{zuwgKoJ4Fk3D-mL^r1O4BH7x=#> zr-m1*NGnqJRV#A<9vV<{SYDrq+DlLeYb@*cZ{N)%=Xx1~%KF|=B(%pZzkfdm$+Wnb zUg;pde(}z^B79Oy`U%>8G>DZ-=86A!WukVmNs@VgXBaG=>tLS33jv$>pVd{nw${~P zZ8Nj}G;(4YO_B?YS76!dk@w3lnu3^)a?eyWGr3PRA)#Y15r&)W`J*}IXFL{;Wd;bm zA-B#6J=k3~&}o@7UZFoyiAO|&g4&Bh3rll8cdY7e3Y{=0;}wS zv>e!prIxIb1lZc?ETaR2b&vw%-q6$CEYn=^1w3FE-)bGOdeee1Z0d|hPe*biU(~Rq z`~TRTR&o5ST)${8nUo$hSn`k^N#Z@g@X66JySBnZh5W!eRM&#Vw^Xyj5(k6c;f>o`ZW;i}@ z$jZSXtQTw#($h#6#z;>|`ON=!qfmPjGd0fh=Zr3=^neF^LqBQR86*mEJDa#bK=kYW z!2a+M&m4;Zzx@ba;BqGqx~q=zlr*kM?OZu{B;Eg4RFu@GPt0mn_a8kxy!X)lHka!& zc#i72I!23m<882c1=K-c=Sx_)-`_5ImZtKOy?Cmr5nbK}?{72#FaLjSVEX@{3q1SZ zo(jN+|GV1=bme~Cep4S{85Vj=%AxVFM5&}pV8G_srpbZHBc(&??9Qu7@Q_I8D$^}FP2BS&4ocE-k z!qvbcKSp^9p{J)$0W6H);=WIOo_Kon(E>)(Gfeyee<%z?jleWV9*nSN9q@_!g}xL9 zMjtX^RK2aAEzfbDV-gbD^ik^et_4IyMKatkGC+VHyE0LOba#EO11&7D`TfM202H6| zY@4KD7ZK~-A&p5z?M#s^2-qNHmzSD|W=Rq0lRvfgS3X`P@J&K%+TnJ0xmatvfKBC3 za$WYT0K)^`+8BwR9*gTau|A;5ssZ5ER6dT_QzpGP*hHun)R0Y2do3y{+1An$BFX2` z*JY}B2$K6@pY+m1EVPWSDYI$lv-+%^_WbW{z%t5Zu5WA{jjwKQ^JqV76I$r&o!Esa zR~s|vbxD(QzQgeXmKi)QkEh}=DA`>A{TeDbzLF)`RBC@C)hQLztJA~>y7SHZ_c6;q zKZD}b$*G0Ee1h}!>-2}SEE{fk0VZK^xP4CSd5mws!$0WD2tFh^UC+2womG26;Qd3| z)9*B>-AouB+&rBj$^5`$130Q6BEE0YTJAo@hfjd{`W0|CKVEMA#=OCONiyrO*Q>#E zUF_5o_#77({-GnV(6LD4L;$(5G$^O2IB7No3+UQ7SyIwk9t(}u^MZ3dzmio~=ii#KdbpQ# z({xJz&ADrza{ZbDAaP%+Yq|)%D{49-mdoO4&aXkayzkOle}!oyRV_J)T=jNyq!Tv^9G8$z3!dnaORf8pc#@Km z#;&gFdfZ7aJ;i%TEY;le>PMhBq{#ij7q{-C7JT{w~4_tBjnF^SA18k($}RTWOZ3Pu*T#yF+3`Oa2)it&4jTvlW$kPDxHYqDG#GyP-T0h{J-^;@ z8v1?(bHvHTzI{uuysYdURvzR6Ng(bBR! zwtcGHs7nMUs!j2e5d=;5Z5054DI@n(C!78gpzX?SD`%?=JS=kY|l%hzs+7m3rp3!%jm@bI7wM ztnAdzV!k;h%@YE{)N1_-3Hmuq4`H>O z@kS@IY`lL2{;)8Hk_B{R7<5*C*))T314-RU`@kLGjwp}fA7EQVZeE_sbqgh^88P}B zFfcHx4C}x)jFOK_HkY?~kp2W#WMHx0Rh=Yl;_K<{-MEjHbAs+qIc=KXF#>ir0$#A2 zV}+HSe7;mh)@UfMhoK36p3RoB^PS(rXffWkLEeqAfs|Z#yz1lAP#( zr|hgYIx-^S=?7(}H&E)k@0Lw-zxhZydap!4_d0;?9qlr4sytc_l%BFazDzDR-}MGI zwncZO_XXQcY8ncXV2Hm7c2w6^gI0f5Pf(MSmq)OY{0J4QaqWJUkg&(GcR`*d^;kwm zrsFgxd^b@kYeK8uBsaG(C+LClS)0hcyGcGZw*W?5NR4yNL&6A}EzGXa8G*b&WXWPB znw_gO-Pytvh=e%3llKh2Jxq0EV{fXd;YcAVMoGz6_bdb(<5GYBM%B|J1BUm2tSo;* zW`1T&0Re#rlNpE=1WilrolrKQnL6D?Zbp!}#pR)C73%Ga-4%QwmrlGFZeRhPFw=WA zz^3D8WMrIfFN6~>)OCM+y_R4_kboW6@$74oIrr9ZOW@_@8!_>|;;OQ?{(0XYxi*d0 zdwOQ~jBm>7;u~wuw~nyuXPX&Kk-pa){9qVYlAO>wC}3u0*1s}edTo#G zU<9@KW32mxDq8pRdG+>Ej++RS2UmM`w`nxFry8|IT$sSltsIpW^YSM@Ysz@%1c;_r zZcA*bKmZl-eo5K7%jvc!E2nUjlC(r|e|LwHMw-UM+sD;$UU6>y;NS-kuM*IC1$HMx z*f}_Cl#GfHH~D~9J_RtZ2h>s_A#adsNtFKc0+4HIUylc%5)Lb&KPR>LHEUr^&@@$* z%W_ee9lblB1J4V8v*Nk>oXcU)V745&w>~u=Zof+#UxPppOYMRh!hx(cdvkD&6^1Jq6XlXZ7?{mIsx_? zIW%Z3{bEV4cMTb^5%~A_{(A{W<-_FM(=M~@zD z&v?Fi=hvxkc;~*mSWXe{1cULeF6;0mIUl@bWE>T(`}tsz1UyWdBEjmGwzQBT4v>R5 zfk}05v94*+;I8({5yYyMm0t;b$zFAJd5xyI&m6zcMxEp_uqrM^&9R!SedfJ$gRiN% z>aT_M9%uu5f4=%1G9u***9#K<0#^OuW{>Nk5WL=;X6?yBSQto)fR+-Kxb+0kn)1i) zKK!L4RbqyZ*H^U9pMqadmvp_XE9t-!AIEd;STv;t%6oDD*0!O>{ms(Z*=wz}+I=xZL85!^GKjBv_!E&sZC_SZ#g68Wi*! zc2$@SeaTqO$Ist-xZBdUHC%!=Pg(N_lGOCQdFaMNz)nJayM$dvCUmBx?xaV}^W7Tl&k@KiJEwt3iWAb0cW{@1-w8Z zh4sk>4YgK@pCu0gxA7}8^8!pPtRF;N7g4hsr|w|WB>jOuRELzQD@4QfnN6ORwu5=H z>fvEN;+A;Qo?mEZhi(G*H36rC8B)E>79m#rsL(&d9Thnf?qNb)Zm6U9~viicw zNwMvKNKMDkP)M5c%9HHy651^iOmhP5?@3QytEn)VA>>behKgFC#zMzH=YF`%@JKq@ zA25-fq4)tN6S)wGYL!XIy}Rpc9v&hj45E%&v^lGzQI@SUW^qbV81pX?-+i@7?KbH? z*olVBl0rr)mujWiS728qgc)JJJ|jDq()&toj<=5=c{giwrwfJqPgk>7*C|{t z_gF1vjBTfk7z3JF*J_Vu&Y?ZMOZsqcM1viufu?Gfi$ZCdZHC3g%)U1z`^oxZ z>g{7xHy)?wAdePPrC1#&)vaLAn|Hd6=dT2y@zDs^a>Gw5mSP#v_xJS)@bhE6!9w2K z-zUXE*>1(+cOFZQ3JZIRjg1`>AFYX8FtP>)880F^EG#T_WUZy81s!Oeb_~c@p=%Vu zFDGd1ubL*M#a}&3(G^sZ&)-trZ~;5(vQ^Sg59H9#JGA6LmwwJDz0p#H|IDncUUN-8 zUrXeNgh33d(V{-oR*+(5?Y6$EvY57Z&c59AsaEnty>s|nb58U8smx5nDKce#fxcH{ zzWU~eme-`o=*~j#Jh<#o9S;@-EG%dnudeeLr>aUSDeYrFz5bXXRv3}(`?D#c;qHc< znEE9(PQ)E>GEp2oxoZDTfy~=~6rOd+xr)YFZt3G(W)ziJt&1GT^5yGKwW_1jD_cMs z>h%6DiQzO@UGhj^jD4Fx#re_jizsgJPw61ljLsQb+*iI3;ENUP!x{MTq7`(SwuVrO z$OE-;taLe5``e?}j&lL&g6%#A`i%cx1Lp95SbNK$xPrD@bZ~bYJV21(?j9_72*I7; z?(Xi81osevySrQP;O_43%-wwVd#lc^b8cPzk<_qjrgwMm-Q7>GwVu@tEdBG+9dzlK z;vP5@!9RJF9+X@^z5Mi%UzdJsPL^K_s}%5IyCa1MOZ>HA;uzr#VSmF`=nVdgQhECb zMfLXo+f`)ne~AWxkIJ3@b=$YA&{F^VFAynkS+W27W3GR~f0r{@ApWd$%J}|$hDyeN zUlRVFt=|UefZ7uAas1Eigvne!QUB+U|4%nWgp2-9Il_2Gve0ieiiZe62l!)ekavRf zB;I9nS{nY}Y}_`)r4!6FXSDg5FN1UhZX==hk%))4hlkd4qbaHF z3i^u@>0Ck{ZIvBFtT_OY!q3aMWa=P3xga0*JuYjz;*8PD4x^wFy?!ScGb3gaVJe}- zL`MA(a*e8*UcrEgnPHaI zsQ0FH02Bia0!(-$VAgh@^^aKijYsZ>8XY)#4ZO_8;Rs9TE{3y!0EFfH7ZurMNWdEU z)=26*VAg^IMm^Cz_W(-=8J&YR)1q_dwgpFgO3L-*-qWe@s&vU{&-Z+h&DoPm$h3=q z`#!7d$wP>(fw)W)-l&~j*b3XAKFTY%9oqUFMu!{u%F}gNSsrn*>RtcuqSx@~$X~(l zA&pA6bwpujJDp?V!3C2 zB3U<;i+YE~>hGPoKIdYmmph8ZH)oWEs8daYn_19ah*AtCd8}ZC)D0INYb|eoqtbf;g6(->-IZ%;3i-kO&-$zn$;y64s*fLkS1>J z+k5>T68?Nez|^O7#GR*fb_y0S{HTQKVezJZ2cU z!h{`dQDwL0dwsZoH#@5aETnG*e*5+}jBuLn5*^CZ#RTUPVWSuL5-{U*iAjrDDGkLgbi8hA$-^{jv-l)vN)v-hBSGfxy_uju_NA z)hpXNG` zIsypE4Nwd1;ExX2QXF++wSQ#Zzu-4sMq06@|LeyFz1@F(8Mn!EgfBDTmP^4PnOw$n z4|>Z_sb`^p-rO0rteAM~oYiZekaa_b-xo!lQhj)$AuFP*eN6bP;lIy(dIeUwQ*4}$ z9No9R_2&*r=SRI}hvzd{s+`U|;u_x!r-+Q{uCzj0cV;u^KEq=mAT7ER883}m_ii^( zYNbcon-$~GYeiLU#xafvTFi5CvMZqIlJ&5PI5`*fk>2GeTk5zQ&i`^}QG@B=ifAM* z5rcEWn!Tx)x?BA7d|69E`grz9a^09Zx)<7et@Ip>G9vIJpp2)QLj7nm{|}Nc**6R) zs?HUuXr3$G`9SjF9lN@fXhb;pBdD1fnxWVuE^HxiT3&Vb?48Bt;uRhC*L-+asBlp ziXJRa2HbKy2BT9(Ki?+3ih9Q}xp!1h`Bzrffp6d@d zO`^{>?|s2MNLPDf5?i5YtR|0)jm^9t>2Nm(t8iq(Z^m5LE8t7Y)&UUG!(Msefy?B}C`* zy-2dcAD7M%Mf-k}!x_={N0c3L`o|K4q^$AY1KQ9nvN@f<;&+Sv=e0Ony)e|KS+Xn_ zDdkdyP(l-@nSUer3OLT+vtfjVE#f_m<+-B~H4_?&(K0w+vGr}(Q|o_%0_nwKi(<;WbC(F!4%x|<%iMe4hPDQ%AsfW=R_R&dq=*Qr%drFeA_E$?p ze#)MD%vakWn2zazsHlvA?}FWWx+kj@XnO}}?Zpn-5ZrH%`8t>qWkcfQm4E;F4Gkg_ z@eO=HNj9|VRIIg|gTFbP>zO@ivEMRfy?b&v6Ancs4Jq6=e`fW>1!ON5&kqdE5l9p} zYFfT6J_EMV>8xlS#|yE5WF-0V1u($VX?2Gq<*&^*NO<0QO~mgH$7K><+cgT$=5s|| zZAOOFFlrm}jElryKC1VsQ3OAb6nnW0}dkKw)Lhi@lVg zTaTWL!bTe}87)~cYx_=^OZsDZ1RpS2p*~RKMKuq~o_r@t_>RC+(j9i|AWkM91DmoW z258ebMxO~|md+ZJ@QbEaAI_LZ|tetpB!|iHZ8SgcwhT(t2{?6NwE$_V3 z{ep5`uHC-q9RO-%Uqy0B>NlRyD;L%1(~DNnCxkb_(b6_@!6?6}xAXbpy!Eg(D+b3)L6Q~3 z*Ehy~cN+^47WzFkZO@esklC>!xini=d6%pY1)`W^7Ngn9+5jZ^gB;t=R5;?RCAH7o z)LeK|&wC&cypI6%N{dVX;tYeK4K+i3j0Z}xXhLRC(GMEs!0(V4{|iIGIjxz+o_T;{ ze)lOC=2}!d2_5DN<(cLCWzMj%%;;>Q7Vp?3D=^3OmJRAOZWDCQc=)Xy{{li3u1w?> z19VIC(3}E#-qFau+WI8$+COYl6)44BH)2k6CdTSa6R}i8U+sC)3ltWdX@`yalD|^~ z0t4R{Lr_ddGX6DhYeDpTs&kbOs`4uo5bGnfi(v3;l9e-6& zZLMEdkG}t&$lYm{xNnrHDlNhLlO4bH$(u}yM5d=aAY`i{5?z1^@t2a2$^}%Oj7DQ% zk*Yuatr4uS8qx3E!ofQ8&nsZ<@(=N8WqU2p(4B)p7BXM=?cE!NtVbKicVvZ{ZI#5H z(rE6Ra|xZPQFW&|)-UC_6oplO11JIfhdix%ZXo5feb|)r`akbIjNEU*EAC4mxfqP5W*z>yE5OETQKt|IZjBfs# zuyS)V*RPffb*ux6{c}h9Cy(U*u z7t5!&CvK|X^RT0rMFu(-EA#(D^9OSqg2~5kFV?6wETkPrCKA%nKugXD?XOIilb(X9 z!koX;Fsr7<>vQQw_fd9UD9^)p%tIp=V47`?V9gFeaAYTrc$WR{Gp+V(eX(=Gx8kIK2UjiO^BZlLPBn! z&_)dC@eKNhP)GO@16=ZlY`LdQW97FSnbbh`9qc*>)jF<|MG z_BN91yFdH5I@YiWM^72tzjC&Yo#_eCvf@ysr*5IJOtDwY{6*2U=OnlY(99kmQT8)| z?k7)3W-t&0wxEL2akMog>*f^V18Fp14^}(@TT^2-FG3Qg$hF&kBe94B-Jc^G;f2wy z?8z{qvh}eTV87;!5T9JWlz+3>LPxmu@rryjVdD8=60oRi+5H`^#`+rQ*U?AZ%g#2G zz&g>rqzN6N3<{C8JNJwQ^SPCt)=xLze{ggvfdz#}#s;{J5|OuMHY6l0-_n0&XEcB% z`v^pdlXZLQjV=th^e*LM@eN*Q8;{)3eM6pw2Ampj4<5_kT zK}xboE8+oi`mk89vxJH`7RVg85myy!eqtC+f)=#1ZH^dOyJJ!$BIrJye358*Yqacb z#ryda5Sj1mE#VH3(@!$IgX>uP@=J``HgrmkWyZTfRv|%CD5_oqZ*Yn&{5>=@mJCVC}6 z5ax^ep|kFktH?T7sG&NlZZ&axm-sXd9D!2dV}*fp+?X0vS*YV&^!2&EgE()a!s3&& z=ek}7Fhjl1KfP1&^=w+OU*dgLju?{O+0PbPD(MQMHL9$^+)(?yF+VYPprsR|oF^Ul z;Vop4)s}m0nIY&WtnDSJT~=#IR#v=4y0lrw1XcPBFqdjyZAsgFte7+I*|h;R&bEGM z)UU==NNebeE15Gm0Qfoo0i~?Xp&tbEwT3QDx5nSzha_CTRG_CFh}13XibA6ISoAK% z+{BVs0cPU)5`d)N7yQn1G`Z_WW|th3KC4J_Qvg&NL`_5rP5%Ig=tz1cU+sTK8=IS( zlX>d;_uRJrD^S|20^a`d5Ot`$xEk0$QqZL>fBZ935zA*OpWSoMGhK}+CjL%=ll2SP z&g9`Ay-h=ZGm@STSgl&4czEMYAOHl9m9C(CfspFk1IeUFv%akRVB-OHYvF*@Yj`KQ6`2V2H}=ae|`Lb4ME+g++a+}+b}wHz## zmqt`?@4EOsIzeI7ftr#a*Uo8jb{O^#050@dP5@&HcvQ~U++6`JAt5u|Wc~BA2%CJ4tb z51{I5-2KHm6u^}G{Be{RK(up>!&qdWSBKRr>`xvQdTHOUpPvmlT>QfW-0#Tn=zj`s zIgS$PfiG4ttyimYg5a;Ef#9F_e2D_onVc!$!+ubAx2F$KH}GzEvKnosLZBS8yK>A3 z3GlUx$aD4CJ7291r1tihO5ZJfkZ7FkvULzwtDwWN`#amPl>nWrfb6>yNRCf~)e_Nw zQbvE_V zNR|HjPylo2!$FFO9e252$BA|zyB_?3{3rR70n>?XtQ8uo4L+}^8Ei%_xo z-xJ4|W7M(!R{=io%m_3s`3HylcI?43&&A0l*fnnMFlCSq=~4KD8N0)k0y6*tK^u2Q zO;_tTzZ$z)wJJ;z{q8Exnl=C0R;j%(7H_?O2{vtLpm!i1$8L(SX}{rOneCg_pzM4g zCz+&r2PZdfW_0i%|F(rJOd#|nwhT);`i^P;CBQ!&8GvWl5$%(`En+qhrq-KS(J3Q9 zE}7Iaf0@@bnt@%w&W8Rpg~auUBS9nNjh zV|Ng$U3Bw#pUb#P<%5@bl|e4Lzf=6UgF5s|ytMM_BP0BHu&*-rb+z@IMMX+MwGQkb&Q8aHMx4Y#$;I(_Zi99k^3e*)pf-z8ht#+-Zg$ zIAz$dWD2dx4?p`(uYTwtBpzeyVy*>IT8L#Lu39t}0xXsyfS?`P{?jqDqZ%AS^xrzs5<@5%?gs~c*LO=Xv9ps#t1k5^8PqE9W!CM195U~ONN^hK5(T+rLEd@4Fe&*8Fif5^kG1uGgI+=WE9-_ z&ga=WdYJ;CoOAp8`zznf;*g*aOnj;QGb-UP2()sai=Jdu_6=z8x>|qo`LnBf?q9Fd z);=(p6x}EnYF1Sh0ep%PKo5|OI7^iwPgCDOg07wUz+h_|>(|+r3}Gj9m=40&PMomG z(xNrmL@6Lv{!mm@Sy%O;$|?z%K&ERs8^0FA7EPZw4GvFH^3%X4(yIkaTspYqHxZ%X zBEub9+Z=>aLqw1Rpwn6pvh81_?28_30FVNp5!QjUQGm*nWxT9FL_(6zlX8KyKy4MA zDmP-kxD~8FgQaV4IGO7vL~iZ*0l1{=pGLTTkE8uY6LN{Cma!3ooUFv97#OCsU|^j? z{R4AcUIg!8*n{VweQ?;?z?N6;nav8-8yEK~n5iiJ!1VANMv6%2iPq=qIIhr9b8czB zQm!bXBy-O*2Vwl)zMQ*DH5{3LoQhs1PuSQ44BF1HpX4X$E6GVdYgh~tX&e`YKJoz_BJ0}+!Xcc4v8$&!_b5x4{j|^u) z%sw*s(Nx{Ja=%fQ2fgNvqcJ_lov7OfDPoHx$m-nyBy{|2jG3OxasN8X)3jepO-S?O zmmwb)QID^}$LI_Iaa8laNv;6~Ui0!@Ps^ClSHqW`QuYd6QG0F@v;J;pN;gzv^n9uo zU~GKckez=RFu1z8Q`bU-75xgpuW+XC*mdQa=4lU)o8EDr+vpwJ&4*7u^E-OLKbwt7 zPT|`anCwN46LEGGlJ{SU9G1+MOONuSt#7N~m38dvm_kVxsTv&ze<<8PMWRhEHeX*N z$s167Rv+`Zs7@^0m;wRP3~125e^U;St{#!L6%MoUJg@B6^TN->cq>AaZk;^yl@>>| zZgx5?zBp*!>05x%U`GqmKWf0J`MBkGDu~ah6>BwT_pj$w1mH&rCOaGWGIWZ&^Q3I7 zSBaDln;F!~Bmq*?9q%Fy!uWxY5Mbd#+*U#hbw-JeY2~|u!s70CdZeP6*;tqmy|HnA zu$n%96Fwt8A5~sPZU4HROW-GO6z*}xvfvBotwg!~6FwIEbDgLR z&6-ret%k?U#B*njb?u0Me>+mPvVi_cBm^M2gHG4*UEi8j;?#(LC{Kw6;;iw#(<<)^ zHg<&V811WB7=sLYNDtL%;Qx%UBTCH;{Q;Y-S6Br^G(bGB=Gwrm!J}0!32FP_PZrNG zJf|vL(uN9PRjdbvB+_9^Uw}>H-;oh_AND&gyp!s$u9tlbcHAa2delWN7Vx%t&{MJPfE1;P3dnB1FUkaCu zQa5^CCOp3`jGY1o+#B!ac!7F2TlA7;rW+vagU~%tzK#%!Ku}PJUMV(eOSO{M!t5x*Iaz=Qc^I-)fHpEZ%4+wDef?hl{Xg9 z&?=iH^xB7CIHxN}0e}jls$ksk@F!B?=N_CT7}q?>qgeMx)@TUnJBS02Ly&k) zK;oVJl8IeYTl#eSjV2Y`M?Vs6CoA-9W3C}pX$`Zv$Gt=ZEnysH(ci3nKzn6U@MMllg6t$$CHFm|l zjM)|a<6ZvSMH=-(uyOQ<>F5~2_Vee~l|CfyDRrLU3h z+_&~bSGt+XmXF_xT;zFazN0Pw==S?F$3c@$G)h!K|KOFZUkpeT-fR0&mt5P#MtvjY zp}oldFum-dnleP{bVfP^RLI%0zn^S(Op==`ErvI~JJ^_VAslA;BE#d?H@&FMly643 zIKVI4OK|3Ucw@R=H`#0D+1Vnw^b$MYzIr0V82R=k@4*Q_HsYHN&wKW@8Kk#jzoy{~ z#|jN@%vIFCOKKX6HGFX`V7(gpJmT8C!S;HtO@sq{-$`jWwI>?<_6$8?-*bdCZyyx_ zjV2+`JYKYLiGE;=*_txHXhQW}xXh8?# zIP$HY`FP=qfSUPiA|IjTbf?GB(eZCx8-Ne8rIw*ARWs!TKPipttO(903qAgP^eIyt zp0$}DN%LM!YijnWY==Rp0VZBw4{K`@;)@pzwT59_d)7_!!#AAh<{_VlH% zOMClGCQ5VXv)QO|c7yHsuU~noiUr2$_11giE!tfV;s0r2V;FA2oYOT>i zPHkm4Od*3k^FyL+(AKGlIpSLnzLl25s6FK9#078Rb*qEf0ocYDXztmzrHJRQPo3UT z(ax(v7D|1$OyB-lKgF&*Kk{eBGC>^Btd?u3OSISGm~>h*-rCgNH+*0S={;V3Ldk}p zlJN%$`8)z0s39&+>4#BgITvBG+#2)N-oF0+#O5*QhMY4Pa;!4}H{1S&XZLWoORMgv*A^auqaW;bdkptup}7*KgLHQ; zlXE6}rtD1pxbZA>&A8l_%(@t24TP#uK%b2AtL3@+ygdW!^9iiyy|ZC*G9lmYw-k+x6vfl`&B9y%M%nVF4)0QsB`bXavh2Fu@0@(AfNUYHNw5@+~J*NR2 zN<$Z0O#>3XYjt2t z3>d&qE_H9ajX4|1wKa?rGfM`JwgmxsOC)K!#C!j`56PUuV=DJea)!35t#B8gjL3kZ zO640}2r?3>*8f2FJddzdB~k}Nzf&5BNww-=L;CEj;o;w?kY(4-#T62#SW3uKbZWZc0Rpkn#7u8M#;M zl-y&lIw*!t>W7ZDvj|w{2_1N3*F+&;!1_~L-HS2Ggh`Yb6=KE_={yN)wv`Jl$OK>U z|3z&PZr#&zxnhF@)h@&bpM%j91y#j!{~3$IaFlE6Agb0fw>dlmTi4Rj;1qB1*cUg) zb8dyGA4;nG+T*i+w!()Wu z+A9|zK5DCH6FlkVy%3E^E%+yA!xchizGq=QPwCAMqlA5B?_Q`|btV`&my?^0h3{M~ z&O`o%1YLczp(R8&u#JS;pG-z=zi{^m2hbNs0%>`#80-Dj!NI}5x)hvIXOHfKBvirm5--J1ET zu+^rXo8tZX-05pWPoXyz1P~xuFEqor*1N{b{{BDJI{bWkPO8v}5^(Fe7@dR3nL1=O zo`qg+B)m*sp^76H>3R+suH-VH1zh8TJa3K+k8X7VS>(Jy+f91?FQ)@*q-Ie>}j{Hg*$xk8ULD5(h8QaB&X z5*t;)N@JXb)g_ir8}qxpVu1VsUQOrWeANe)kRSQ;0$sM` z+I_@h$L7$jF@0GcG4#a@Nc1GEa#+U9@yzxywI4wvn(nD77=PeAS@L5Y85v=78$;c9 z=8sP2MFXuLXp#adt^Q>X6bE1{2Dn^y7JVsrI~>nwF5jhv`Tp_fRinuoOM>!q)lO7$ zsYGW|On!Y@Qj*9rS_cBid_G6GT(2d7N?K_Xh}j`+hcm^FCaVP@LZXM$w;P^cB&D}@ zN)XFib%xXR^{Rd`Fpi9#Z}!OzGBT|j*ab;rWSq$8V$01e!&!x4tCxjIT zgNhPBP6C4lj2}>0S+)^q3Z!^*e(chaAB?(*g;u&E*ShvaOTt* z!ZT>MvJ6;t8CJK)NAzdd%2Woh1Nf62WS6hUee>6ehRWQzb<}Ei>&;=eWpE9hL zLWowZoSupR<(D)^)0WQUC=vdTJgj?-kg?T}0JHwTvY0#SE%%Hu(f}+od&ezE=0f&y zZKVj1rlm|2vr={7=k`bD$REG-qmNZ@#%;EDxxzy=?o6AL_~i7S)98fw7f{`05)5ha zYJ}7AJW2R0yf6g$(e}2AYZ0km0LOi(mfN&?5J&J`;pcq}tG_R`&BUJ5Y&Bp8JbQo> zt)kb^NhJ#u^$lh&sl9WpW)5BUSIanjwc6N4%tw1>ZJ;#jzd^;42n1~ZbUt2gCv5X{ zeOY(9zATRILGTspi!6VDi!*z!{(v(;AtZ!0`MFA?)xg#;->6}X*LxehJD!RZAnM=A zVYa^WHIro<507xjrL3;L9vTE27Hk0NT0^-ismj|p>=qgZ68yU(^P}#?XD;zdJ{Kr5 z=^*o?f%aEw1k&p6p}l-p!%|Pd`>n###*uAaCOU|84&~FA>vjZ~D!jZ_KlP4R zV2x!6LIZaMPQq}{DhUJFO7o@WuZGlL?rqxNExb|R_7~WHlv2Z~1{B{E4na?MIXwh6 zP#}E_!q~DUH^bTJq8(v)hy~7uhz&caGtcv@_tl9EAmqhl(&ij!Moa$;%nlg>J|rMk z%U*kpg{FTnuMr+EkHFAefG;3}=sHDQp(>4~I9?IYLIsvoM zbtgGOf)VP1-<^GZgn-Rq|3i+PyElZ}Xlpal#%$=9N2B`%`!174qz6ipV~3Yg58A9I zFg1~H1A$KzSBYAV++J*7z039er)P%^_9W&kgsPM$w3Vmf3Xp%iRr0+zg|INzC917a zOW@w#a{0-5xhBjC+)TiZQLobs(yyC4L9v^6~H&sNS0 zB>;(LB}7p4NE=??^-R=8*cHv?)jsFuI38cAoy2FTXdJW|J%~q>2;+V&Q4IwoBeUge zhyeKN#=`@v+X(U}*7~e$2#EJm;A0ihfvn_UWjcv$VWBFEEA�I(&r}?~C;fs`u11 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 R7KMPn*D~*37D*ZS{tubmZOs4x literal 0 HcmV?d00001 From 0e81a784dd9e95a3d4922179b733260e4b009bc0 Mon Sep 17 00:00:00 2001 From: intwocave Date: Thu, 27 Nov 2025 19:15:06 +0900 Subject: [PATCH 123/130] feat: fix import --- mission_10/src/middleware/local.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission_10/src/middleware/local.ts b/mission_10/src/middleware/local.ts index 603ba06d7..09056202c 100644 --- a/mission_10/src/middleware/local.ts +++ b/mission_10/src/middleware/local.ts @@ -1,7 +1,7 @@ import fs from "fs"; import path from "path"; import multer from "multer"; -import { NextFunction, Request, Response } from "express"; +import type { NextFunction, Request, Response } from "express"; const uploadDir = "uploads"; if (!fs.existsSync(uploadDir)) { From 33954e69075ab254072ccc28c71fe349316bbbac Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 28 Nov 2025 09:11:52 +0900 Subject: [PATCH 124/130] feat: update env.d.ts with new environment variables --- mission_10/env.d.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mission_10/env.d.ts b/mission_10/env.d.ts index f4b3b91de..8e1fd99e1 100644 --- a/mission_10/env.d.ts +++ b/mission_10/env.d.ts @@ -2,12 +2,21 @@ declare namespace NodeJS { interface ProcessEnv { NODE_ENV: "development" | "production"; PORT?: string; + DATABASE_URL?: string; + PRODUCTION_DATABASE_URL: string; + + JWT_SECRET: string; + + AWS_ACCESS_KEY_ID: string; + AWS_SECRET_ACCESS_KEY: string; + AWS_S3_BUCKET_NAME: string; + AWS_REGION: string; + /* DB_HOST: string; DB_PORT: string; DB_USERNAME: string; DB_PASSWORD: string; DB_NAME: string; */ - JWT_SECRET: string; } } From 1d33d64f0a9303dd09e7ecd883595646a353efa5 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 28 Nov 2025 09:38:40 +0900 Subject: [PATCH 125/130] feat: add nginx configuration files for mission 10 --- mission_10/infra/ec2/nginx.conf | 84 ++++++++++++++++++++++++++++ mission_10/infra/ec2/nginx_site.conf | 8 +++ 2 files changed, 92 insertions(+) create mode 100644 mission_10/infra/ec2/nginx.conf create mode 100644 mission_10/infra/ec2/nginx_site.conf diff --git a/mission_10/infra/ec2/nginx.conf b/mission_10/infra/ec2/nginx.conf new file mode 100644 index 000000000..360b06823 --- /dev/null +++ b/mission_10/infra/ec2/nginx.conf @@ -0,0 +1,84 @@ +# For more information on configuration, see: +# * Official English Documentation: http://nginx.org/en/docs/ +# * Official Russian Documentation: http://nginx.org/ru/docs/ + +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log notice; +pid /run/nginx.pid; + +# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. +include /usr/share/nginx/modules/*.conf; + +events { + worker_connections 1024; +} + +http { + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + keepalive_timeout 65; + types_hash_max_size 4096; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Load modular configuration files from the /etc/nginx/conf.d directory. + # See http://nginx.org/en/docs/ngx_core_module.html#include + # for more information. + include /etc/nginx/conf.d/*.conf; + +# server { +# listen 80; +# listen [::]:80; +# server_name _; +# root /usr/share/nginx/html; +# +# # Load configuration files for the default server block. +# include /etc/nginx/default.d/*.conf; +# +# error_page 404 /404.html; +# location = /404.html { +# } +# +# error_page 500 502 503 504 /50x.html; +# location = /50x.html { +# } +# } + + include /etc/nginx/sites-enabled/*; + +# Settings for a TLS enabled server. +# +# server { +# listen 443 ssl; +# listen [::]:443 ssl; +# http2 on; +# server_name _; +# root /usr/share/nginx/html; +# +# ssl_certificate "/etc/pki/nginx/server.crt"; +# ssl_certificate_key "/etc/pki/nginx/private/server.key"; +# ssl_session_cache shared:SSL:1m; +# ssl_session_timeout 10m; +# ssl_ciphers PROFILE=SYSTEM; +# ssl_prefer_server_ciphers on; +# +# # Load configuration files for the default server block. +# include /etc/nginx/default.d/*.conf; +# +# error_page 404 /404.html; +# location = /404.html { +# } +# +# error_page 500 502 503 504 /50x.html; +# location = /50x.html { +# } +# } +} \ No newline at end of file diff --git a/mission_10/infra/ec2/nginx_site.conf b/mission_10/infra/ec2/nginx_site.conf new file mode 100644 index 000000000..25e01a962 --- /dev/null +++ b/mission_10/infra/ec2/nginx_site.conf @@ -0,0 +1,8 @@ +# for HTTP +server { + listen 80; + + location / { + proxy_pass http://localhost:3000/; + } +} \ No newline at end of file From 34a67f01bfe1801b99e74df3093e0c73aa3c7da7 Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 28 Nov 2025 18:18:06 +0900 Subject: [PATCH 126/130] feat: copy mission 10 to mission 11 --- mission_11/.env.sample | 15 + mission_11/.gitignore | 11 + mission_11/coverage/clover.xml | 6 + mission_11/coverage/coverage-final.json | 1 + mission_11/coverage/lcov-report/base.css | 224 + .../coverage/lcov-report/block-navigation.js | 87 + mission_11/coverage/lcov-report/favicon.png | Bin 0 -> 445 bytes mission_11/coverage/lcov-report/index.html | 101 + mission_11/coverage/lcov-report/prettify.css | 1 + mission_11/coverage/lcov-report/prettify.js | 2 + .../lcov-report/sort-arrow-sprite.png | Bin 0 -> 138 bytes mission_11/coverage/lcov-report/sorter.js | 210 + mission_11/coverage/lcov.info | 0 mission_11/env.d.ts | 22 + mission_11/infra/ec2/.gitkeep | 0 mission_11/infra/ec2/nginx.conf | 84 + mission_11/infra/ec2/nginx_site.conf | 8 + mission_11/infra/ec2/secure-group-inbound.png | Bin 0 -> 109571 bytes .../infra/ec2/secure-group-outbound.png | Bin 0 -> 99953 bytes mission_11/infra/rds/.gitkeep | 0 .../infra/rds/secure-group-inoutbound.png | Bin 0 -> 46501 bytes mission_11/infra/s3/.gitkeep | 0 mission_11/infra/s3/policy.png | Bin 0 -> 54908 bytes mission_11/jest.config.cjs | 20 + mission_11/package-lock.json | 9152 +++++++++++++++++ mission_11/package.json | 55 + mission_11/prisma/schema.prisma | 95 + mission_11/prisma/seed.ts | 158 + mission_11/src/app.ts | 59 + mission_11/src/container.ts | 1 + .../src/controller/articleController.ts | 253 + mission_11/src/controller/imageController.ts | 21 + mission_11/src/controller/index.ts | 5 + .../src/controller/notificationController.ts | 61 + .../src/controller/productController.ts | 298 + mission_11/src/controller/userController.ts | 159 + mission_11/src/handler/errorHandler.ts | 12 + mission_11/src/lib/prisma.ts | 14 + mission_11/src/lib/socket.ts | 20 + mission_11/src/main.ts | 6 + mission_11/src/middleware/auth.ts | 173 + mission_11/src/middleware/index.ts | 1 + mission_11/src/middleware/local.ts | 36 + mission_11/src/middleware/s3.ts | 28 + mission_11/src/middleware/upload.ts | 6 + mission_11/src/middleware/validator.ts | 31 + .../src/repository/articleRepository.ts | 177 + mission_11/src/repository/index.ts | 4 + .../src/repository/notificationRepository.ts | 68 + .../src/repository/productRepository.ts | 235 + mission_11/src/repository/userRepository.ts | 61 + mission_11/src/router/articleRouter.ts | 73 + mission_11/src/router/imageRouter.ts | 26 + mission_11/src/router/index.ts | 5 + mission_11/src/router/notificationRouter.ts | 35 + mission_11/src/router/productRouter.ts | 79 + mission_11/src/router/userRouter.ts | 44 + mission_11/src/services/articleService.ts | 80 + mission_11/src/services/index.ts | 4 + .../src/services/notificationService.ts | 66 + mission_11/src/services/productService.ts | 103 + mission_11/src/services/userService.ts | 121 + .../src/test/integration/article-auth.test.ts | 169 + .../test/integration/article-noauth.test.ts | 79 + .../src/test/integration/product-auth.test.ts | 169 + .../test/integration/product-noauth.test.ts | 84 + mission_11/src/test/integration/user.test.ts | 43 + mission_11/src/test/setup.ts | 4 + mission_11/src/test/unit/product.test.ts | 46 + mission_11/src/test/util/getAuthToken.ts | 16 + mission_11/src/types/article.ts | 54 + mission_11/src/types/auth.d.ts | 5 + mission_11/src/types/express/index.d.ts | 10 + mission_11/src/types/global.ts | 5 + mission_11/src/types/product.ts | 63 + mission_11/src/types/user.ts | 21 + mission_11/test-client.html | 142 + mission_11/tsconfig.json | 49 + 78 files changed, 13576 insertions(+) create mode 100644 mission_11/.env.sample create mode 100644 mission_11/.gitignore create mode 100644 mission_11/coverage/clover.xml create mode 100644 mission_11/coverage/coverage-final.json create mode 100644 mission_11/coverage/lcov-report/base.css create mode 100644 mission_11/coverage/lcov-report/block-navigation.js create mode 100644 mission_11/coverage/lcov-report/favicon.png create mode 100644 mission_11/coverage/lcov-report/index.html create mode 100644 mission_11/coverage/lcov-report/prettify.css create mode 100644 mission_11/coverage/lcov-report/prettify.js create mode 100644 mission_11/coverage/lcov-report/sort-arrow-sprite.png create mode 100644 mission_11/coverage/lcov-report/sorter.js create mode 100644 mission_11/coverage/lcov.info create mode 100644 mission_11/env.d.ts create mode 100644 mission_11/infra/ec2/.gitkeep create mode 100644 mission_11/infra/ec2/nginx.conf create mode 100644 mission_11/infra/ec2/nginx_site.conf create mode 100644 mission_11/infra/ec2/secure-group-inbound.png create mode 100644 mission_11/infra/ec2/secure-group-outbound.png create mode 100644 mission_11/infra/rds/.gitkeep create mode 100644 mission_11/infra/rds/secure-group-inoutbound.png create mode 100644 mission_11/infra/s3/.gitkeep create mode 100644 mission_11/infra/s3/policy.png create mode 100644 mission_11/jest.config.cjs create mode 100644 mission_11/package-lock.json create mode 100644 mission_11/package.json create mode 100644 mission_11/prisma/schema.prisma create mode 100644 mission_11/prisma/seed.ts create mode 100644 mission_11/src/app.ts create mode 100644 mission_11/src/container.ts create mode 100644 mission_11/src/controller/articleController.ts create mode 100644 mission_11/src/controller/imageController.ts create mode 100644 mission_11/src/controller/index.ts create mode 100644 mission_11/src/controller/notificationController.ts create mode 100644 mission_11/src/controller/productController.ts create mode 100644 mission_11/src/controller/userController.ts create mode 100644 mission_11/src/handler/errorHandler.ts create mode 100644 mission_11/src/lib/prisma.ts create mode 100644 mission_11/src/lib/socket.ts create mode 100644 mission_11/src/main.ts create mode 100644 mission_11/src/middleware/auth.ts create mode 100644 mission_11/src/middleware/index.ts create mode 100644 mission_11/src/middleware/local.ts create mode 100644 mission_11/src/middleware/s3.ts create mode 100644 mission_11/src/middleware/upload.ts create mode 100644 mission_11/src/middleware/validator.ts create mode 100644 mission_11/src/repository/articleRepository.ts create mode 100644 mission_11/src/repository/index.ts create mode 100644 mission_11/src/repository/notificationRepository.ts create mode 100644 mission_11/src/repository/productRepository.ts create mode 100644 mission_11/src/repository/userRepository.ts create mode 100644 mission_11/src/router/articleRouter.ts create mode 100644 mission_11/src/router/imageRouter.ts create mode 100644 mission_11/src/router/index.ts create mode 100644 mission_11/src/router/notificationRouter.ts create mode 100644 mission_11/src/router/productRouter.ts create mode 100644 mission_11/src/router/userRouter.ts create mode 100644 mission_11/src/services/articleService.ts create mode 100644 mission_11/src/services/index.ts create mode 100644 mission_11/src/services/notificationService.ts create mode 100644 mission_11/src/services/productService.ts create mode 100644 mission_11/src/services/userService.ts create mode 100644 mission_11/src/test/integration/article-auth.test.ts create mode 100644 mission_11/src/test/integration/article-noauth.test.ts create mode 100644 mission_11/src/test/integration/product-auth.test.ts create mode 100644 mission_11/src/test/integration/product-noauth.test.ts create mode 100644 mission_11/src/test/integration/user.test.ts create mode 100644 mission_11/src/test/setup.ts create mode 100644 mission_11/src/test/unit/product.test.ts create mode 100644 mission_11/src/test/util/getAuthToken.ts create mode 100644 mission_11/src/types/article.ts create mode 100644 mission_11/src/types/auth.d.ts create mode 100644 mission_11/src/types/express/index.d.ts create mode 100644 mission_11/src/types/global.ts create mode 100644 mission_11/src/types/product.ts create mode 100644 mission_11/src/types/user.ts create mode 100644 mission_11/test-client.html create mode 100644 mission_11/tsconfig.json diff --git a/mission_11/.env.sample b/mission_11/.env.sample new file mode 100644 index 000000000..5ef3f80a1 --- /dev/null +++ b/mission_11/.env.sample @@ -0,0 +1,15 @@ +# Node Env +NODE_ENV="development" + +# JWT +JWT_SECRET="your-super-secret-key" + +# POSTGRESQL +DATABASE_URL="postgresql://user:password@localhost:5432/mydatabase" +PRODUCTION_DATABASE_URL="YOUR_PRODUCTION_DATABASE_URL" + +# AWS S3 +AWS_ACCESS_KEY_ID="your-aws-access-key-id" +AWS_SECRET_ACCESS_KEY="your-aws-secret-access-key" +AWS_S3_BUCKET_NAME="your-s3-bucket-name" +AWS_REGION="your-aws-region" diff --git a/mission_11/.gitignore b/mission_11/.gitignore new file mode 100644 index 000000000..01557d99a --- /dev/null +++ b/mission_11/.gitignore @@ -0,0 +1,11 @@ +node_modules +/dist + +# Keep environment variables out of version control +.env + +/generated/prisma +/prisma/migrations + +todo.list +uploads/ \ No newline at end of file diff --git a/mission_11/coverage/clover.xml b/mission_11/coverage/clover.xml new file mode 100644 index 000000000..6ef1353be --- /dev/null +++ b/mission_11/coverage/clover.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/mission_11/coverage/coverage-final.json b/mission_11/coverage/coverage-final.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/mission_11/coverage/coverage-final.json @@ -0,0 +1 @@ +{} diff --git a/mission_11/coverage/lcov-report/base.css b/mission_11/coverage/lcov-report/base.css new file mode 100644 index 000000000..f418035b4 --- /dev/null +++ b/mission_11/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/mission_11/coverage/lcov-report/block-navigation.js b/mission_11/coverage/lcov-report/block-navigation.js new file mode 100644 index 000000000..530d1ed2b --- /dev/null +++ b/mission_11/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selector that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/mission_11/coverage/lcov-report/favicon.png b/mission_11/coverage/lcov-report/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c1525b811a167671e9de1fa78aab9f5c0b61cef7 GIT binary patch literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> + + + + Code coverage report for All files + + + + + + + + + +

+ + + + + + + + \ No newline at end of file diff --git a/mission_11/coverage/lcov-report/prettify.css b/mission_11/coverage/lcov-report/prettify.css new file mode 100644 index 000000000..b317a7cda --- /dev/null +++ b/mission_11/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/mission_11/coverage/lcov-report/prettify.js b/mission_11/coverage/lcov-report/prettify.js new file mode 100644 index 000000000..b3225238f --- /dev/null +++ b/mission_11/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/mission_11/coverage/lcov-report/sort-arrow-sprite.png b/mission_11/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed68316eb3f65dec9063332d2f69bf3093bbfab GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc literal 0 HcmV?d00001 diff --git a/mission_11/coverage/lcov-report/sorter.js b/mission_11/coverage/lcov-report/sorter.js new file mode 100644 index 000000000..4ed70ae5a --- /dev/null +++ b/mission_11/coverage/lcov-report/sorter.js @@ -0,0 +1,210 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + + // Try to create a RegExp from the searchValue. If it fails (invalid regex), + // it will be treated as a plain text search + let searchRegex; + try { + searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive + } catch (error) { + searchRegex = null; + } + + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + let isMatch = false; + + if (searchRegex) { + // If a valid regex was created, use it for matching + isMatch = searchRegex.test(row.textContent); + } else { + // Otherwise, fall back to the original plain text search + isMatch = row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()); + } + + row.style.display = isMatch ? '' : 'none'; + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/mission_11/coverage/lcov.info b/mission_11/coverage/lcov.info new file mode 100644 index 000000000..e69de29bb diff --git a/mission_11/env.d.ts b/mission_11/env.d.ts new file mode 100644 index 000000000..8e1fd99e1 --- /dev/null +++ b/mission_11/env.d.ts @@ -0,0 +1,22 @@ +declare namespace NodeJS { + interface ProcessEnv { + NODE_ENV: "development" | "production"; + PORT?: string; + + DATABASE_URL?: string; + PRODUCTION_DATABASE_URL: string; + + JWT_SECRET: string; + + AWS_ACCESS_KEY_ID: string; + AWS_SECRET_ACCESS_KEY: string; + AWS_S3_BUCKET_NAME: string; + AWS_REGION: string; + + /* DB_HOST: string; + DB_PORT: string; + DB_USERNAME: string; + DB_PASSWORD: string; + DB_NAME: string; */ + } +} diff --git a/mission_11/infra/ec2/.gitkeep b/mission_11/infra/ec2/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/mission_11/infra/ec2/nginx.conf b/mission_11/infra/ec2/nginx.conf new file mode 100644 index 000000000..360b06823 --- /dev/null +++ b/mission_11/infra/ec2/nginx.conf @@ -0,0 +1,84 @@ +# For more information on configuration, see: +# * Official English Documentation: http://nginx.org/en/docs/ +# * Official Russian Documentation: http://nginx.org/ru/docs/ + +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log notice; +pid /run/nginx.pid; + +# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. +include /usr/share/nginx/modules/*.conf; + +events { + worker_connections 1024; +} + +http { + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + keepalive_timeout 65; + types_hash_max_size 4096; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Load modular configuration files from the /etc/nginx/conf.d directory. + # See http://nginx.org/en/docs/ngx_core_module.html#include + # for more information. + include /etc/nginx/conf.d/*.conf; + +# server { +# listen 80; +# listen [::]:80; +# server_name _; +# root /usr/share/nginx/html; +# +# # Load configuration files for the default server block. +# include /etc/nginx/default.d/*.conf; +# +# error_page 404 /404.html; +# location = /404.html { +# } +# +# error_page 500 502 503 504 /50x.html; +# location = /50x.html { +# } +# } + + include /etc/nginx/sites-enabled/*; + +# Settings for a TLS enabled server. +# +# server { +# listen 443 ssl; +# listen [::]:443 ssl; +# http2 on; +# server_name _; +# root /usr/share/nginx/html; +# +# ssl_certificate "/etc/pki/nginx/server.crt"; +# ssl_certificate_key "/etc/pki/nginx/private/server.key"; +# ssl_session_cache shared:SSL:1m; +# ssl_session_timeout 10m; +# ssl_ciphers PROFILE=SYSTEM; +# ssl_prefer_server_ciphers on; +# +# # Load configuration files for the default server block. +# include /etc/nginx/default.d/*.conf; +# +# error_page 404 /404.html; +# location = /404.html { +# } +# +# error_page 500 502 503 504 /50x.html; +# location = /50x.html { +# } +# } +} \ No newline at end of file diff --git a/mission_11/infra/ec2/nginx_site.conf b/mission_11/infra/ec2/nginx_site.conf new file mode 100644 index 000000000..25e01a962 --- /dev/null +++ b/mission_11/infra/ec2/nginx_site.conf @@ -0,0 +1,8 @@ +# for HTTP +server { + listen 80; + + location / { + proxy_pass http://localhost:3000/; + } +} \ No newline at end of file diff --git a/mission_11/infra/ec2/secure-group-inbound.png b/mission_11/infra/ec2/secure-group-inbound.png new file mode 100644 index 0000000000000000000000000000000000000000..324a33fa97136324c4e404842d9b0e207defb660 GIT binary patch literal 109571 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�I(&r}?~C;fs`u11 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 R7KMPn*D~*37D*ZS{tubmZOs4x literal 0 HcmV?d00001 diff --git a/mission_11/infra/s3/.gitkeep b/mission_11/infra/s3/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/mission_11/infra/s3/policy.png b/mission_11/infra/s3/policy.png new file mode 100644 index 0000000000000000000000000000000000000000..04af13ffd181e89cc8bacb896ad722e0c78f7638 GIT binary patch literal 54908 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/src/**/*.test.ts"], + setupFilesAfterEnv: ["/src/test/setup.ts"], +}; diff --git a/mission_11/package-lock.json b/mission_11/package-lock.json new file mode 100644 index 000000000..7e01d3ce3 --- /dev/null +++ b/mission_11/package-lock.json @@ -0,0 +1,9152 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sprint_mission_3", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@aws-sdk/client-s3": "^3.940.0", + "@jest/globals": "^30.2.0", + "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "dotenv": "^17.2.3", + "express": "^5.1.0", + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "multer-s3": "^3.0.1", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "socket.io": "^4.8.1", + "tsx": "^4.20.6" + }, + "devDependencies": { + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.9", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.3", + "@types/express-jwt": "^6.0.4", + "@types/jest": "^30.0.0", + "@types/multer": "^2.0.0", + "@types/multer-s3": "^3.0.3", + "@types/node": "^24.3.1", + "@types/socket.io": "^3.0.1", + "@types/supertest": "^6.0.3", + "jest": "^30.2.0", + "prisma": "^6.13.0", + "supertest": "^7.1.4", + "ts-jest": "^29.4.5", + "typescript": "^5.9.2" + } + }, + "node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/crc32c": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", + "integrity": "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha1-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz", + "integrity": "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.940.0.tgz", + "integrity": "sha512-Wi4qnBT6shRRMXuuTgjMFTU5mu2KFWisgcigEMPptjPGUtJvBVi4PTGgS64qsLoUk/obqDAyOBOfEtRZ2ddC2w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha1-browser": "5.2.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/credential-provider-node": "3.940.0", + "@aws-sdk/middleware-bucket-endpoint": "3.936.0", + "@aws-sdk/middleware-expect-continue": "3.936.0", + "@aws-sdk/middleware-flexible-checksums": "3.940.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-location-constraint": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-sdk-s3": "3.940.0", + "@aws-sdk/middleware-ssec": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/signature-v4-multi-region": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/eventstream-serde-browser": "^4.2.5", + "@smithy/eventstream-serde-config-resolver": "^4.3.5", + "@smithy/eventstream-serde-node": "^4.2.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-blob-browser": "^4.2.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/hash-stream-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/md5-js": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "@smithy/util-waiter": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.940.0.tgz", + "integrity": "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.940.0.tgz", + "integrity": "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@aws-sdk/xml-builder": "3.930.0", + "@smithy/core": "^3.18.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.940.0.tgz", + "integrity": "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.940.0.tgz", + "integrity": "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-stream": "^4.5.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.940.0.tgz", + "integrity": "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/credential-provider-env": "3.940.0", + "@aws-sdk/credential-provider-http": "3.940.0", + "@aws-sdk/credential-provider-login": "3.940.0", + "@aws-sdk/credential-provider-process": "3.940.0", + "@aws-sdk/credential-provider-sso": "3.940.0", + "@aws-sdk/credential-provider-web-identity": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.940.0.tgz", + "integrity": "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.940.0.tgz", + "integrity": "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.940.0", + "@aws-sdk/credential-provider-http": "3.940.0", + "@aws-sdk/credential-provider-ini": "3.940.0", + "@aws-sdk/credential-provider-process": "3.940.0", + "@aws-sdk/credential-provider-sso": "3.940.0", + "@aws-sdk/credential-provider-web-identity": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.940.0.tgz", + "integrity": "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.940.0.tgz", + "integrity": "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.940.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/token-providers": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.940.0.tgz", + "integrity": "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/lib-storage": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.940.0.tgz", + "integrity": "sha512-4pHgz9tuFJNSy/qoTbW5FqXPjoR4B18jB656UsE+TP5GWd7EPx7m4F0EUwIsD3OF5+KPiiyICi8zkxOs7erfQw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/smithy-client": "^4.9.8", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.940.0" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.936.0.tgz", + "integrity": "sha512-XLSVVfAorUxZh6dzF+HTOp4R1B5EQcdpGcPliWr0KUj2jukgjZEcqbBmjyMF/p9bmyQsONX80iURF1HLAlW0qg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-config-provider": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.936.0.tgz", + "integrity": "sha512-Eb4ELAC23bEQLJmUMYnPWcjD3FZIsmz2svDiXEcxRkQU9r7NRID7pM7C5NPH94wOfiCk0b2Y8rVyFXW0lGQwbA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.940.0.tgz", + "integrity": "sha512-WdsxDAVj5qaa5ApAP+JbpCOMHFGSmzjs2Y2OBSbWPeR9Ew7t/Okj+kUub94QJPsgzhvU1/cqNejhsw5VxeFKSQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@aws-crypto/crc32c": "5.2.0", + "@aws-crypto/util": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.936.0.tgz", + "integrity": "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.936.0.tgz", + "integrity": "sha512-SCMPenDtQMd9o5da9JzkHz838w3327iqXk3cbNnXWqnNRx6unyW8FL0DZ84gIY12kAyVHz5WEqlWuekc15ehfw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.936.0.tgz", + "integrity": "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.936.0.tgz", + "integrity": "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@aws/lambda-invoke-store": "^0.2.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.940.0.tgz", + "integrity": "sha512-JYkLjgS1wLoKHJ40G63+afM1ehmsPsjcmrHirKh8+kSCx4ip7+nL1e/twV4Zicxr8RJi9Y0Ahq5mDvneilDDKQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/core": "^3.18.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.936.0.tgz", + "integrity": "sha512-/GLC9lZdVp05ozRik5KsuODR/N7j+W+2TbfdFL3iS+7un+gnP6hC8RDOZd6WhpZp7drXQ9guKiTAxkZQwzS8DA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.940.0.tgz", + "integrity": "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@smithy/core": "^3.18.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.940.0.tgz", + "integrity": "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.936.0.tgz", + "integrity": "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.940.0.tgz", + "integrity": "sha512-ugHZEoktD/bG6mdgmhzLDjMP2VrYRAUPRPF1DpCyiZexkH7DCU7XrSJyXMvkcf0DHV+URk0q2sLf/oqn1D2uYw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.940.0.tgz", + "integrity": "sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.936.0.tgz", + "integrity": "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.893.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.893.0.tgz", + "integrity": "sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.936.0.tgz", + "integrity": "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-endpoints": "^3.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.893.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.893.0.tgz", + "integrity": "sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.936.0.tgz", + "integrity": "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.940.0.tgz", + "integrity": "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.930.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.930.0.tgz", + "integrity": "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "fast-xml-parser": "5.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.1.tgz", + "integrity": "sha512-sIyFcoPZkTtNu9xFeEoynMef3bPJIAbOfUh+ueYcfhVl6xm2VRtMcMclSxmZCMnHHd4hlYKJeq/aggmBEWynww==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emnapi/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", + "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/core": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", + "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.2.0", + "jest-config": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-resolve-dependencies": "30.2.0", + "jest-runner": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "jest-watcher": "30.2.0", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", + "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "license": "MIT", + "dependencies": { + "expect": "30.2.0", + "jest-snapshot": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", + "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@sinonjs/fake-timers": "^13.0.0", + "@types/node": "*", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", + "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/types": "30.2.0", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", + "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", + "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", + "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/types": "30.2.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", + "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", + "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@prisma/client": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.19.0.tgz", + "integrity": "sha512-QXFT+N/bva/QI2qoXmjBzL7D6aliPffIwP+81AdTGq0FXDoLxLkWivGMawG8iM5B9BKfxLIXxfWWAF6wbuJU6g==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.19.0.tgz", + "integrity": "sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.18.4", + "empathic": "2.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.19.0.tgz", + "integrity": "sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.19.0.tgz", + "integrity": "sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/fetch-engine": "6.19.0", + "@prisma/get-platform": "6.19.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773.tgz", + "integrity": "sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.19.0.tgz", + "integrity": "sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/get-platform": "6.19.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.19.0.tgz", + "integrity": "sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.5.tgz", + "integrity": "sha512-j7HwVkBw68YW8UmFRcjZOmssE77Rvk0GWAIN1oFBhsaovQmZWYCIcGa9/pwRB0ExI8Sk9MWNALTjftjHZea7VA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.0.tgz", + "integrity": "sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.2.1.tgz", + "integrity": "sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-base64": "^4.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.3.tgz", + "integrity": "sha512-ezHLe1tKLUxDJo2LHtDuEDyWXolw8WGOR92qb4bQdWq/zKenO5BvctZGrVJBK08zjezSk7bmbKFOXIVyChvDLw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.18.5", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.18.5.tgz", + "integrity": "sha512-6gnIz3h+PEPQGDj8MnRSjDvKBah042jEoPgjFGJ4iJLBE78L4lY/n98x14XyPF4u3lN179Ub/ZKFY5za9GeLQw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.2.6", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.5.tgz", + "integrity": "sha512-BZwotjoZWn9+36nimwm/OLIcVe+KYRwzMjfhd4QT7QxPm9WY0HiOV8t/Wlh+HVUif0SBVV7ksq8//hPaBC/okQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.5.tgz", + "integrity": "sha512-Ogt4Zi9hEbIP17oQMd68qYOHUzmH47UkK7q7Gl55iIm9oKt27MUGrC5JfpMroeHjdkOliOA4Qt3NQ1xMq/nrlA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.9.0", + "@smithy/util-hex-encoding": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.5.tgz", + "integrity": "sha512-HohfmCQZjppVnKX2PnXlf47CW3j92Ki6T/vkAT2DhBR47e89pen3s4fIa7otGTtrVxmj7q+IhH0RnC5kpR8wtw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.5.tgz", + "integrity": "sha512-ibjQjM7wEXtECiT6my1xfiMH9IcEczMOS6xiCQXoUIYSj5b1CpBbJ3VYbdwDy8Vcg5JHN7eFpOCGk8nyZAltNQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.5.tgz", + "integrity": "sha512-+elOuaYx6F2H6x1/5BQP5ugv12nfJl66GhxON8+dWVUEDJ9jah/A0tayVdkLRP0AeSac0inYkDz5qBFKfVp2Gg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.5.tgz", + "integrity": "sha512-G9WSqbST45bmIFaeNuP/EnC19Rhp54CcVdX9PDL1zyEB514WsDVXhlyihKlGXnRycmHNmVv88Bvvt4EYxWef/Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-codec": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.6.tgz", + "integrity": "sha512-3+RG3EA6BBJ/ofZUeTFJA7mHfSYrZtQIrDP9dI8Lf7X6Jbos2jptuLrAAteDiFVrmbEmLSuRG/bUKzfAXk7dhg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.5", + "@smithy/querystring-builder": "^4.2.5", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-blob-browser": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.6.tgz", + "integrity": "sha512-8P//tA8DVPk+3XURk2rwcKgYwFvwGwmJH/wJqQiSKwXZtf/LiZK+hbUZmPj/9KzM+OVSwe4o85KTp5x9DUZTjw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/chunked-blob-reader": "^5.2.0", + "@smithy/chunked-blob-reader-native": "^4.2.1", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.5.tgz", + "integrity": "sha512-DpYX914YOfA3UDT9CN1BM787PcHfWRBB43fFGCYrZFUH0Jv+5t8yYl+Pd5PW4+QzoGEDvn5d5QIO4j2HyYZQSA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-stream-node": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.5.tgz", + "integrity": "sha512-6+do24VnEyvWcGdHXomlpd0m8bfZePpUKBy7m311n+JuRwug8J4dCanJdTymx//8mi0nlkflZBvJe+dEO/O12Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.5.tgz", + "integrity": "sha512-2L2erASEro1WC5nV+plwIMxrTXpvpfzl4e+Nre6vBVRR2HKeGGcvpJyyL3/PpiSg+cJG2KpTmZmq934Olb6e5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.0.tgz", + "integrity": "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/md5-js": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.5.tgz", + "integrity": "sha512-Bt6jpSTMWfjCtC0s79gZ/WZ1w90grfmopVOWqkI2ovhjpD5Q2XRXuecIPB9689L2+cCySMbaXDhBPU56FKNDNg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.5.tgz", + "integrity": "sha512-Y/RabVa5vbl5FuHYV2vUCwvh/dqzrEY/K2yWPSqvhFUwIY0atLqO4TienjBXakoy4zrKAMCZwg+YEqmH7jaN7A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "4.3.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.3.12.tgz", + "integrity": "sha512-9pAX/H+VQPzNbouhDhkW723igBMLgrI8OtX+++M7iKJgg/zY/Ig3i1e6seCcx22FWhE6Q/S61BRdi2wXBORT+A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.18.5", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-middleware": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.12.tgz", + "integrity": "sha512-S4kWNKFowYd0lID7/DBqWHOQxmxlsf0jBaos9chQZUWTVOjSW1Ogyh8/ib5tM+agFDJ/TCxuCTvrnlc+9cIBcQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/service-error-classification": "^4.2.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.6.tgz", + "integrity": "sha512-VkLoE/z7e2g8pirwisLz8XJWedUSY8my/qrp81VmAdyrhi94T+riBfwP+AOEEFR9rFTSonC/5D2eWNmFabHyGQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.5.tgz", + "integrity": "sha512-bYrutc+neOyWxtZdbB2USbQttZN0mXaOyYLIsaTbJhFsfpXyGWUxJpEuO1rJ8IIJm2qH4+xJT0mxUSsEDTYwdQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.5.tgz", + "integrity": "sha512-UTurh1C4qkVCtqggI36DGbLB2Kv8UlcFdMXDcWMbqVY2uRg0XmT9Pb4Vj6oSQ34eizO1fvR0RnFV4Axw4IrrAg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.5.tgz", + "integrity": "sha512-CMnzM9R2WqlqXQGtIlsHMEZfXKJVTIrqCNoSd/QpAyp+Dw0a1Vps13l6ma1fH8g7zSPNsA59B/kWgeylFuA/lw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/querystring-builder": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.5.tgz", + "integrity": "sha512-8iLN1XSE1rl4MuxvQ+5OSk/Zb5El7NJZ1td6Tn+8dQQHIjp59Lwl6bd0+nzw6SKm2wSSriH2v/I9LPzUic7EOg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.5.tgz", + "integrity": "sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.5.tgz", + "integrity": "sha512-y98otMI1saoajeik2kLfGyRp11e5U/iJYH/wLCh3aTV/XutbGT9nziKGkgCaMD1ghK7p6htHMm6b6scl9JRUWg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "@smithy/util-uri-escape": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.5.tgz", + "integrity": "sha512-031WCTdPYgiQRYNPXznHXof2YM0GwL6SeaSyTH/P72M1Vz73TvCNH2Nq8Iu2IEPq9QP2yx0/nrw5YmSeAi/AjQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.5.tgz", + "integrity": "sha512-8fEvK+WPE3wUAcDvqDQG1Vk3ANLR8Px979te96m84CbKAjBVf25rPYSzb4xU4hlTyho7VhOGnh5i62D/JVF0JQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.0.tgz", + "integrity": "sha512-5WmZ5+kJgJDjwXXIzr1vDTG+RhF9wzSODQBfkrQ2VVkYALKGvZX1lgVSxEkgicSAFnFhPj5rudJV0zoinqS0bA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.5.tgz", + "integrity": "sha512-xSUfMu1FT7ccfSXkoLl/QRQBi2rOvi3tiBZU2Tdy3I6cgvZ6SEi9QNey+lqps/sJRnogIS+lq+B1gxxbra2a/w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-uri-escape": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "4.9.8", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.9.8.tgz", + "integrity": "sha512-8xgq3LgKDEFoIrLWBho/oYKyWByw9/corz7vuh1upv7ZBm0ZMjGYBhbn6v643WoIqA9UTcx5A5htEp/YatUwMA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.18.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "@smithy/util-stream": "^4.5.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.9.0.tgz", + "integrity": "sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.5.tgz", + "integrity": "sha512-VaxMGsilqFnK1CeBX+LXnSuaMx4sTL/6znSZh2829txWieazdVxr54HmiyTsIbpOTLcf5nYpq9lpzmwRdxj6rQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.0.tgz", + "integrity": "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.0.tgz", + "integrity": "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.1.tgz", + "integrity": "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.0.tgz", + "integrity": "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.0.tgz", + "integrity": "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.11.tgz", + "integrity": "sha512-yHv+r6wSQXEXTPVCIQTNmXVWs7ekBTpMVErjqZoWkYN75HIFN5y9+/+sYOejfAuvxWGvgzgxbTHa/oz61YTbKw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.14.tgz", + "integrity": "sha512-ljZN3iRvaJUgulfvobIuG97q1iUuCMrvXAlkZ4msY+ZuVHQHDIqn7FKZCEj+bx8omz6kF5yQXms/xhzjIO5XiA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/config-resolver": "^4.4.3", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.5.tgz", + "integrity": "sha512-3O63AAWu2cSNQZp+ayl9I3NapW1p1rR5mlVHcF6hAB1dPZUQFfRPYtplWX/3xrzWthPGj5FqB12taJJCfH6s8A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.0.tgz", + "integrity": "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.5.tgz", + "integrity": "sha512-6Y3+rvBF7+PZOc40ybeZMcGln6xJGVeY60E7jy9Mv5iKpMJpHgRE6dKy9ScsVxvfAYuEX4Q9a65DQX90KaQ3bA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.5.tgz", + "integrity": "sha512-GBj3+EZBbN4NAqJ/7pAhsXdfzdlznOh8PydUijy6FpNIMnHPSMO2/rP4HKu+UFeikJxShERk528oy7GT79YiJg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/service-error-classification": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.6.tgz", + "integrity": "sha512-qWw/UM59TiaFrPevefOZ8CNBKbYEP6wBAIlLqxn3VAIo9rgnTNc4ASbVrqDmhuwI87usnjhdQrxodzAGFFzbRQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.0.tgz", + "integrity": "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.0.tgz", + "integrity": "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.5.tgz", + "integrity": "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/uuid": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.0.tgz", + "integrity": "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "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", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie-parser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.10.tgz", + "integrity": "sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.5.tgz", + "integrity": "sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-jwt": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-6.0.4.tgz", + "integrity": "sha512-I53KRQ9D0eTA6hVCN9S73iOeprKS3JNWK+Cp2mDPB6uOIkTVpkgSkX394kHQzb5cd0U02I0adRmsMxHk+zX8tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/express-unless": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", + "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express-unless": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.3.tgz", + "integrity": "sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/methods": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", + "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/multer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", + "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/multer-s3": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/multer-s3/-/multer-s3-3.0.3.tgz", + "integrity": "sha512-VgWygI9UwyS7loLithUUi0qAMIDWdNrERS2Sb06UuPYiLzKuIFn2NgL7satyl4v8sh/LLoU7DiPanvbQaRg9Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@aws-sdk/client-s3": "^3.0.0", + "@types/multer": "*", + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/socket.io": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-3.0.1.tgz", + "integrity": "sha512-XSma2FhVD78ymvoxYV4xGXrIH/0EKQ93rR+YR0Y+Kw1xbPzLDCip/UWSejZ08FpxYeYNci/PZPQS9anrvJRqMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "socket.io": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "license": "MIT" + }, + "node_modules/@types/superagent": { + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/supertest": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.3.tgz", + "integrity": "sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", + "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "30.2.0", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", + "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", + "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.28", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.28.tgz", + "integrity": "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/bowser": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.0.tgz", + "integrity": "sha512-yHAbSRuT6LTeKi6k2aS40csueHqgAsFEgmrOsfRyFpJnFv5O2hl9FYmWEUZ97gZ/dG17U4IQQcTx4YAFYPuWRQ==", + "license": "MIT" + }, + "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/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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/c12/node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001755", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001755.tgz", + "integrity": "sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/cjs-module-lexer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz", + "integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz", + "integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.254", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.254.tgz", + "integrity": "sha512-DcUsWpVhv9svsKRxnSCZ86SjD+sp32SGidNB37KpqXJncp1mfUgKbHvBomE89WJDbfVKw1mdv5+ikrvd43r+Bg==", + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "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/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-jwt": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.5.1.tgz", + "integrity": "sha512-Dv6QjDLpR2jmdb8M6XQXiCcpEom7mK8TOqnr0/TngDKsG2DHVkO8+XnVxkJVN7BuS1I3OrGw6N8j5DaaGgkDRQ==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "^9", + "express-unless": "^2.1.3", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express-unless": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz", + "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==", + "license": "MIT" + }, + "node_modules/express/node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fast-check/node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "devOptional": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "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", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-xml-parser": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz", + "integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^2.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "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", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/formidable": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "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/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "license": "MIT" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "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==", + "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/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "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/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", + "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.2.0", + "@jest/types": "30.2.0", + "import-local": "^3.2.0", + "jest-cli": "30.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", + "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.1.1", + "jest-util": "30.2.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-circus": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", + "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "p-limit": "^3.1.0", + "pretty-format": "30.2.0", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-cli": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", + "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", + "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.2.0", + "@jest/types": "30.2.0", + "babel-jest": "30.2.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-circus": "30.2.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-runner": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "micromatch": "^4.0.8", + "parse-json": "^5.2.0", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-each": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", + "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "jest-util": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", + "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", + "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "micromatch": "^4.0.8", + "walker": "^1.0.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" + } + }, + "node_modules/jest-leak-detector": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", + "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", + "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", + "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", + "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/environment": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-leak-detector": "30.2.0", + "jest-message-util": "30.2.0", + "jest-resolve": "30.2.0", + "jest-runtime": "30.2.0", + "jest-util": "30.2.0", + "jest-watcher": "30.2.0", + "jest-worker": "30.2.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", + "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/globals": "30.2.0", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", + "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "pretty-format": "30.2.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", + "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", + "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.2.0", + "string-length": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", + "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.2.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "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==", + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "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/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/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", + "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "mkdirp": "^0.5.6", + "object-assign": "^4.1.1", + "type-is": "^1.6.18", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/multer-s3": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/multer-s3/-/multer-s3-3.0.1.tgz", + "integrity": "sha512-BFwSO80a5EW4GJRBdUuSHblz2jhVSAze33ZbnGpcfEicoT0iRolx4kWR+AJV07THFRCQ78g+kelKFdjkCCaXeQ==", + "license": "MIT", + "dependencies": { + "@aws-sdk/lib-storage": "^3.46.0", + "file-type": "^3.3.0", + "html-comment-regex": "^1.1.2", + "run-parallel": "^1.1.6" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.0.0" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "license": "MIT" + }, + "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/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/nypm": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", + "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "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/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "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/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prisma": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.19.0.tgz", + "integrity": "sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.19.0", + "@prisma/engines": "6.19.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", + "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.7.0", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "license": "MIT", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", + "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/superagent": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz", + "integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.1", + "cookiejar": "^2.1.4", + "debug": "^4.3.7", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.4", + "formidable": "^3.5.4", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supertest": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.4.tgz", + "integrity": "sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^10.2.3" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "license": "BSD-3-Clause" + }, + "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" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-jest": { + "version": "29.4.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.5.tgz", + "integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/mission_11/package.json b/mission_11/package.json new file mode 100644 index 000000000..4fb9505eb --- /dev/null +++ b/mission_11/package.json @@ -0,0 +1,55 @@ +{ + "name": "sprint_mission_3", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "NODE_OPTIONS='--experimental-vm-modules' jest --verbose", + "build": "tsc", + "start": "NODE_ENV=production node dist/main.js", + "dev": "tsx watch src/main.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@aws-sdk/client-s3": "^3.940.0", + "@jest/globals": "^30.2.0", + "@prisma/client": "^6.13.0", + "bcrypt": "^6.0.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "dotenv": "^17.2.3", + "express": "^5.1.0", + "express-jwt": "^8.5.1", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "multer-s3": "^3.0.1", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "socket.io": "^4.8.1", + "tsx": "^4.20.6" + }, + "devDependencies": { + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.9", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.3", + "@types/express-jwt": "^6.0.4", + "@types/jest": "^30.0.0", + "@types/multer": "^2.0.0", + "@types/multer-s3": "^3.0.3", + "@types/node": "^24.3.1", + "@types/socket.io": "^3.0.1", + "@types/supertest": "^6.0.3", + "jest": "^30.2.0", + "prisma": "^6.13.0", + "supertest": "^7.1.4", + "ts-jest": "^29.4.5", + "typescript": "^5.9.2" + }, + "prisma": { + "seed": "tsx prisma/seed.ts" + }, + "type": "module" +} diff --git a/mission_11/prisma/schema.prisma b/mission_11/prisma/schema.prisma new file mode 100644 index 000000000..657f4f3c6 --- /dev/null +++ b/mission_11/prisma/schema.prisma @@ -0,0 +1,95 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" + // output = "../generated/prisma" +} + +datasource db { + provider = "postgresql" + url = env("PRODUCTION_DATABASE_URL") +} + +model Product { + id Int @id @default(autoincrement()) + name String + description String + price Int + tags String[] + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] + likedBy LikedProduct[] + notifications Notification[] +} + +model Article { + id Int @id @default(autoincrement()) + title String + content String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + comments Comment[] + notifications Notification[] +} + +model Comment { + id Int @id @default(autoincrement()) + name String + content String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int? + Article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) + articleId Int? +} + +model User { + id Int @id @default(autoincrement()) + email String @unique + nickname String + image String? + password String + refreshToken String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + Article Article[] + Product Product[] + Comment Comment[] + likedProducts LikedProduct[] + notifications Notification[] +} + +model LikedProduct { + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + product Product @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int + createdAt DateTime @default(now()) + + @@id([userId, productId]) +} + +model Notification { + id Int @id @default(autoincrement()) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId Int + message String + read Boolean @default(false) + createdAt DateTime @default(now()) + article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) + articleId Int? + product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int? +} diff --git a/mission_11/prisma/seed.ts b/mission_11/prisma/seed.ts new file mode 100644 index 000000000..bd79ab898 --- /dev/null +++ b/mission_11/prisma/seed.ts @@ -0,0 +1,158 @@ +import { PrismaClient } from '@prisma/client'; +import bcrypt from 'bcrypt'; + +// initialize Prisma Client +const prisma = new PrismaClient(); + +async function main() { + // create two dummy users + const password = await bcrypt.hash('password123', 10); + const user1 = await prisma.user.create({ + data: { + email: 'user1@example.com', + nickname: 'Alice', + password, + image: 'https://i.pravatar.cc/150?u=user1@example.com', + refreshToken: 'some-refresh-token', + }, + }); + + const user2 = await prisma.user.create({ + data: { + email: 'user2@example.com', + nickname: 'Bob', + password, + image: 'https://i.pravatar.cc/150?u=user2@example.com', + }, + }); + + // create two dummy articles + const article1 = await prisma.article.create({ + data: { + title: 'Prisma is the best ORM', + content: + 'Prisma makes database access easy with an intuitive data model and type-safety.', + userId: user1.id, + }, + }); + + const article2 = await prisma.article.create({ + data: { + title: 'Getting started with Next.js', + content: + 'Next.js is a React framework for building full-stack web applications.', + userId: user2.id, + }, + }); + + // create two dummy products + const product1 = await prisma.product.create({ + data: { + name: 'Laptop', + description: 'A very powerful laptop for all your needs.', + price: 1200, + tags: ['electronics', 'computer'], + userId: user1.id, + }, + }); + + const product2 = await prisma.product.create({ + data: { + name: 'Coffee Mug', + description: 'A mug to hold your favorite beverage.', + price: 15, + tags: ['kitchen', 'home'], + userId: user2.id, + }, + }); + + // create comments + const comment1 = await prisma.comment.create({ + data: { + name: 'Commenter1', + content: 'Great article!', + userId: user2.id, + articleId: article1.id, + }, + }); + + const comment2 = await prisma.comment.create({ + data: { + name: 'Commenter2', + content: 'I love this laptop!', + userId: user1.id, + productId: product1.id, + }, + }); + + const comment3 = await prisma.comment.create({ + data: { + name: 'Commenter3', + content: 'This is a general comment.', + userId: user1.id, + }, + }); + + const comment4 = await prisma.comment.create({ + data: { + name: 'Commenter4', + content: 'This comment is for both an article and a product.', + userId: user2.id, + articleId: article2.id, + productId: product2.id, + }, + }); + + + // create a liked product + const likedProduct = await prisma.likedProduct.create({ + data: { + userId: user1.id, + productId: product2.id, + }, + }); + + // create notifications + const notification1 = await prisma.notification.create({ + data: { + userId: user1.id, + message: 'Your article has a new comment!', + articleId: article1.id, + }, + }); + + const notification2 = await prisma.notification.create({ + data: { + userId: user2.id, + message: 'Your product has a new comment!', + productId: product1.id, + read: true, + }, + }); + + console.log({ + user1, + user2, + article1, + article2, + product1, + product2, + comment1, + comment2, + comment3, + comment4, + likedProduct, + notification1, + notification2, + }); +} + +main() + .catch((e) => { + console.error(e); + process.exit(1); + }) + .finally(async () => { + // close Prisma Client at the end + await prisma.$disconnect(); + }); \ No newline at end of file diff --git a/mission_11/src/app.ts b/mission_11/src/app.ts new file mode 100644 index 000000000..a5fd2e69d --- /dev/null +++ b/mission_11/src/app.ts @@ -0,0 +1,59 @@ +import path from "path"; +import http from "http"; + +import express from "express"; +import type { Request, Response, NextFunction } from "express"; +import cors from "cors"; +import cookieParser from "cookie-parser"; +import productRouter from "./router/productRouter.js"; +import articleRouter from "./router/articleRouter.js"; +import imageRouter from "./router/imageRouter.js"; +import notificationRouter from "./router/notificationRouter.js"; +import userRouter from "./router/userRouter.js"; +import { initializeSocket } from "./lib/socket.js"; + +import errorHandler from "./handler/errorHandler.js"; + +const app = express(); +export const httpServer = http.createServer(app); + +// Socket.IO 초기화 +const io = initializeSocket(httpServer); + +io.on("connection", (socket) => { + console.log("A user connected:", socket.id); + + socket.on("join", (userId) => { + console.log(`User ${userId} joined room`); + socket.join(userId); + }); + + socket.on("disconnect", () => { + console.log("User disconnected:", socket.id); + }); +}); + +app.use(express.json()); +app.use( + cors({ + methods: ["GET", "POST", "PUT", "PATCH", "DELETE"], + }) +); +app.use(cookieParser()); +app.use("/uploads", express.static("uploads")); + +function logRequest(req: Request, _: Response, next: NextFunction) { + console.log(`[${req.method}] ${req.originalUrl}`); + next(); +} + +// middleware for logging all http request +app.use(logRequest); + +app.use("/products", productRouter); +app.use("/articles", articleRouter); +app.use("/images", imageRouter); +app.use(notificationRouter); +app.use(userRouter); + +app.use(errorHandler); diff --git a/mission_11/src/container.ts b/mission_11/src/container.ts new file mode 100644 index 000000000..ba0183f59 --- /dev/null +++ b/mission_11/src/container.ts @@ -0,0 +1 @@ +import prisma from './lib/prisma.js'; \ No newline at end of file diff --git a/mission_11/src/controller/articleController.ts b/mission_11/src/controller/articleController.ts new file mode 100644 index 000000000..2f603387d --- /dev/null +++ b/mission_11/src/controller/articleController.ts @@ -0,0 +1,253 @@ +import * as articleService from "../services/articleService.js"; +import type { RequestHandler } from "express"; + +const createPost: RequestHandler = async function (req, res, next) { + const { title, content } = req.body; + + const userId = req.user ? req.user.userId : null; + if (userId === null) { + const err = new Error("Access token is missing or invalid"); + err.statusCode = 401; + return next(err); + } + + if (!title || !content) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + const article = await articleService.createPost({ userId, title, content }); + res.status(201).json(article); + } catch (err) { + next(err); + } +}; + +const getPosts: RequestHandler = async function (req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search } = req.query; + + try { + const articles = await articleService.getPosts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search: String(search), + }); + + if (articles) res.status(200).json(articles); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with given parameters`; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const getPost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) return res.status(400).json({ message: "Invalid parameter 'id'" }); + + try { + const article = await articleService.getPost({ id: Number(id) }); + + if (article) res.status(200).json(article); + else { + const err = new Error(`Cannot find article with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchPost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + // Columns in model Article + const articleCols = ["title", "content"]; + + // ? + const filteredBody = Object.entries(req.body) + .filter(([key]) => articleCols.includes(key)) + .reduce>((obj, [key, value]) => { + obj[key] = value; + return obj; + }, {}); + + try { + const article = await articleService.patchPost({ + id: Number(id), + ...filteredBody, + }); + + if (article) res.status(200).json(article); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const deletePost: RequestHandler = async function (req, res, next) { + const { id } = req.params; + if (!id) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + try { + const deleted = await articleService.deletePost({ id: Number(id) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find article with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const postComment: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Access token is missing or invalid"); + err.statusCode = 401; + return next(err); + } + + if (!name || !content || !pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + return next(err); + } + + try { + const comment = await articleService.postComment({ + userId, + name, + content, + pid: Number(pid), + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +}; + +const getComments: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + const comments = await articleService.getComments({ + pid: Number(pid), + cursor: Number(cursor), + limit: Number(limit), + }); + + if (comments) + res.status(200).json({ + comments, + nextCursor: + comments.length === Number(limit) ? comments.at(-1)?.id : null, // llm + }); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comments with id ${pid}`; + return next(err); + } +}; + +const patchComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id' and 'cid'"; + return next(err); + } + + const { name, content } = req.body; + if (!name || !content) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid SQL Parameters"; + return next(err); + } + + const comment = await articleService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find any comment with ID ${pid}`; + return next(err); + } +}; + +const deleteComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await articleService.deleteComment({ cid: Number(cid) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find any comment with ID ${cid}`); + err.statusCode = 404; + return next(err); + } +}; + +export { + createPost, + getPosts, + getPost, + patchPost, + deletePost, + postComment, + getComments, + patchComment, + deleteComment, +}; diff --git a/mission_11/src/controller/imageController.ts b/mission_11/src/controller/imageController.ts new file mode 100644 index 000000000..7d97fc261 --- /dev/null +++ b/mission_11/src/controller/imageController.ts @@ -0,0 +1,21 @@ +import type { Request, Response } from 'express'; + +class ImageController { + uploadImage = async (req: Request, res: Response) => { + if (!req.file) { + return res.status(400).json({ message: '파일이 없습니다.' }); + } + + const file = req.file as any; + + return res.status(201).json({ + message: '이미지 업로드 성공', + file: { + url: file.location, + name: file.key, + }, + }); + }; +} + +export const imageController = new ImageController(); \ No newline at end of file diff --git a/mission_11/src/controller/index.ts b/mission_11/src/controller/index.ts new file mode 100644 index 000000000..9d4bcaaeb --- /dev/null +++ b/mission_11/src/controller/index.ts @@ -0,0 +1,5 @@ +export * from './articleController.js'; +export * from './productController.js'; +export * from './userController.js'; +export * from './notificationController.js'; +export * from './imageController.js'; \ No newline at end of file diff --git a/mission_11/src/controller/notificationController.ts b/mission_11/src/controller/notificationController.ts new file mode 100644 index 000000000..ae5a2b667 --- /dev/null +++ b/mission_11/src/controller/notificationController.ts @@ -0,0 +1,61 @@ +import type { Request, Response, NextFunction } from 'express'; +import notificationService from '../services/notificationService.js'; + +async function getNotifications( + req: Request, + res: Response, + next: NextFunction +) { + try { + const userId = req.user.userId; + const notifications = await notificationService.getUserNotifications(userId); + res.status(200).json(notifications); + } catch (error) { + next(error); + } +} + +async function getUnreadCount( + req: Request, + res: Response, + next: NextFunction +) { + try { + const userId = req.user.userId; + const count = await notificationService.getUnreadNotificationCount(userId); + res.status(200).json({ count }); + } catch (error) { + next(error); + } +} + +async function markAsRead(req: Request, res: Response, next: NextFunction) { + try { + const userId = req.user.userId; + const notificationId = parseInt(req.params.id, 10); + const notification = await notificationService.markNotificationAsRead( + notificationId, + userId + ); + res.status(200).json(notification); + } catch (error) { + next(error); + } +} + +async function markAllAsRead(req: Request, res: Response, next: NextFunction) { + try { + const userId = req.user.userId; + await notificationService.markAllNotificationsAsRead(userId); + res.status(204).send(); + } catch (error) { + next(error); + } +} + +export default { + getNotifications, + getUnreadCount, + markAsRead, + markAllAsRead, +}; diff --git a/mission_11/src/controller/productController.ts b/mission_11/src/controller/productController.ts new file mode 100644 index 000000000..c8bb444a7 --- /dev/null +++ b/mission_11/src/controller/productController.ts @@ -0,0 +1,298 @@ +import * as productService from "../services/productService.js"; +import type { RequestHandler } from "express"; + +const createProduct: RequestHandler = async function createProduct( + req, + res, + next +) { + // destructuring field data from request body + const { name, description, price, tags } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!name || !description || !price || !tags) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Product table + const product = await productService.createProduct({ + userId, + name, + description, + price, + tags, + }); + + res.status(201).json(product); + } catch (err) { + next(err); + } +}; + +const getProducts: RequestHandler = async function (req, res, next) { + const { offset = 0, limit = 10, sort = "recent", search = "" } = req.query; + + try { + const products = await productService.getProducts({ + offset: Number(offset), + limit: Number(limit), + sort: sort === "old" ? "asc" : "desc", + search: String(search), + }); + + if (products) res.status(200).json(products); + else { + const err = new Error("Cannot find products"); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const getProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const product = await productService.getProduct({ id }); + + if (product) res.status(200).json(product); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error(); + err.statusCode = 400; + err.message = "Invalid parameter 'id'"; + next(err); + } + + // Attributes in model Product + const productCols = ["name", "description", "price", "tags"]; + + // Possible improvement? + const filteredBody = Object.entries(req.body) + .filter(([key]) => productCols.includes(key)) + .reduce>((obj, [key, value]) => { + obj[key] = value; + return obj; + }, {}); + + try { + const product = await productService.patchProduct({ id, ...filteredBody }); + + if (product) res.status(200).json(product); + else { + const err = new Error(); + err.statusCode = 404; + err.message = `Cannot find product with ID ${id}`; + next(err); + } + } catch (err) { + next(err); + } +}; + +const deleteProduct: RequestHandler = async function (req, res, next) { + const id = Number(req.params.id); + if (isNaN(id) || id < 0) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const deleted = await productService.deleteProduct({ id }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${id}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const postComment: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + const { name, content } = req.body; + const userId = req.user ? req.user.userId : null; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + // validation + if (!name || !content || !pid) { + const err = new Error("Required data is not sufficient"); + err.statusCode = 400; + return next(err); + } + + try { + // insert into Comment table + const comment = await productService.postComment({ + userId, + pid: Number(pid), + name, + content, + }); + + res.status(201).json(comment); + } catch (err) { + next(err); + } +}; + +const getComments: RequestHandler = async function (req, res, next) { + const { id: pid } = req.params; + if (!pid) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + const { cursor, limit = 10 } = req.query; + + try { + const comments = await productService.getComments({ + pid: Number(pid), + cursor: cursor ? Number(cursor) : null, + limit: Number(limit), + }); + + // Cursor pagination + const nextCursor = + comments.length > 0 ? comments[comments.length - 1] : null; + + if (comments) + res.status(200).json({ + comments, + nextCursor, + }); + else { + const err = new Error(`Cannot find any comments`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const patchComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + const { name, content } = req.body; + + if (!pid || !cid || !name || !content) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productService.patchComment({ + cid: Number(cid), + name, + content, + }); + + if (comment) res.status(200).json(comment); + else { + const err = new Error(`Cannot find any comment with ID ${cid}`); + err.statusCode = 404; + return next(err); + } + } catch (err) { + next(err); + } +}; + +const deleteComment: RequestHandler = async function (req, res, next) { + const { id: pid, cid } = req.params; + if (!pid || !cid) { + const err = new Error("Invalid parameter 'id' and 'cid'"); + err.statusCode = 400; + return next(err); + } + + const deleted = await productService.deleteComment({ cid: Number(cid) }); + + if (deleted) res.status(200).json(deleted); + else { + const err = new Error(`Cannot find product with ID ${pid}`); + err.statusCode = 404; + return next(err); + } +}; + +const toggleLike: RequestHandler = async function (req, res, next) { + if (!req.user) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!req.params.id) { + const err = new Error("Invalid parameter 'id'"); + err.statusCode = 400; + return next(err); + } + + try { + const userId = req.user.userId; + const productId = parseInt(req.params.id, 10); + + if (isNaN(productId)) { + const err = new Error("Invalid product ID"); + err.statusCode = 400; + return next(err); + } + + const result = await productService.toggleLike(userId, productId); + res.status(200).json(result); + } catch (error) { + next(error); + } +}; + +export { + createProduct, + getProducts, + getProduct, + patchProduct, + deleteProduct, + postComment, + getComments, + patchComment, + deleteComment, + toggleLike, +}; diff --git a/mission_11/src/controller/userController.ts b/mission_11/src/controller/userController.ts new file mode 100644 index 000000000..00b5f5407 --- /dev/null +++ b/mission_11/src/controller/userController.ts @@ -0,0 +1,159 @@ +import * as userService from "../services/userService.js"; +import type { RequestHandler } from "express"; + +// for Creating user +const createUser: RequestHandler = async function (req, res, next) { + const { email, nickname, password } = req.body; + + if (!email || !nickname || !password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const userId = await userService.createUser({ email, nickname, password }); + + return res.status(200).json({ userId }); + } catch (err) { + next(err); + } +}; + +// for Login +const getAccessToken: RequestHandler = async function (req, res, next) { + const { email, password } = req.body; + + if (!email || !password) { + const err = new Error("Email or password is wrong"); + err.statusCode = 404; + return next(err); + } + + try { + const user = await userService.getUser(req.body); + const accessToken = userService.createToken(user); + const refreshToken = userService.createToken(user, "refresh"); + await userService.updateUserInfo(user.id, { refreshToken }); + res.cookie("refreshToken", refreshToken, { + httpOnly: true, + sameSite: "none", + secure: true, + }); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +}; + +const getMyInfo: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + + if (!userId) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + try { + const user = await userService.getUserById(userId); + + return res.status(200).json(user); + } catch (err) { + next(err); + } +}; + +const updateMyInfo: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + const { email, nickname } = req.body; + + if ((!email && !nickname) || userId === null) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const updatedUser = await userService.updateUserInfo(userId, req.body); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +}; + +const updateMyPassword: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + const { password } = req.body; + + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + if (!password) { + const err = new Error("Required parameter is missing"); + err.statusCode = 400; + return next(err); + } + + try { + const updatedUser = await userService.updateUserPassword(userId, password); + + return res.status(200).json(updatedUser); + } catch (err) { + next(err); + } +}; + +const getMyProducts: RequestHandler = async function (req, res, next) { + const userId = req.user ? req.user.userId : null; + if (userId === null) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + return next(err); + } + + try { + const products = await userService.getMyProducts(userId); + + return res.status(200).json(products); + } catch (err) { + next(err); + } +}; + +const getRefreshToken: RequestHandler = async function (req, res, next) { + const userId = req.auth ? req.auth.userId : null; + const refreshToken = req.cookies.refreshToken; + + if (!refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + next(err); + } + + try { + const accessToken = await userService.refreshToken( + Number(userId), + refreshToken + ); + + return res.status(200).json({ accessToken }); + } catch (err) { + next(err); + } +}; + +export { + createUser, + getAccessToken, + getMyInfo, + updateMyInfo, + updateMyPassword, + getMyProducts, + getRefreshToken, +}; diff --git a/mission_11/src/handler/errorHandler.ts b/mission_11/src/handler/errorHandler.ts new file mode 100644 index 000000000..ed4c35489 --- /dev/null +++ b/mission_11/src/handler/errorHandler.ts @@ -0,0 +1,12 @@ +import type { ErrorRequestHandler } from "express"; + +const errorHandler: ErrorRequestHandler = function (err, req, res, next) { + console.error(`[ERROR] ${err.stack || err.message}`); + + const statusCode = err.statusCode || 500; + const message = err.message || "Internal server error!"; + + res.status(statusCode).json({ message }); +} + +export default errorHandler; \ No newline at end of file diff --git a/mission_11/src/lib/prisma.ts b/mission_11/src/lib/prisma.ts new file mode 100644 index 000000000..b71f1485f --- /dev/null +++ b/mission_11/src/lib/prisma.ts @@ -0,0 +1,14 @@ +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient({ + datasources: { + db: { + url: + process.env.NODE_ENV === 'production' + ? process.env.PRODUCTION_DATABASE_URL + : process.env.DATABASE_URL, + }, + }, +}); + +export default prisma; \ No newline at end of file diff --git a/mission_11/src/lib/socket.ts b/mission_11/src/lib/socket.ts new file mode 100644 index 000000000..6b7195b05 --- /dev/null +++ b/mission_11/src/lib/socket.ts @@ -0,0 +1,20 @@ +import { Server } from 'socket.io'; + +let io: Server; + +export const initializeSocket = (server: any) => { + io = new Server(server, { + cors: { + origin: '*', // In a real application, restrict this to your frontend's URL + methods: ['GET', 'POST'], + }, + }); + return io; +}; + +export const getIO = () => { + if (!io) { + throw new Error('Socket.io not initialized!'); + } + return io; +}; diff --git a/mission_11/src/main.ts b/mission_11/src/main.ts new file mode 100644 index 000000000..ded3928d4 --- /dev/null +++ b/mission_11/src/main.ts @@ -0,0 +1,6 @@ +import "dotenv/config"; +import { httpServer } from "./app.js"; + +const PORT = Number(process.env.PORT) || 3000; + +httpServer.listen(PORT, () => console.log(`Server started on port ${PORT}..`)); diff --git a/mission_11/src/middleware/auth.ts b/mission_11/src/middleware/auth.ts new file mode 100644 index 000000000..0d040e8c6 --- /dev/null +++ b/mission_11/src/middleware/auth.ts @@ -0,0 +1,173 @@ +import type { RequestHandler } from "express"; +import { expressjwt } from "express-jwt"; +import * as articleRepository from "../repository/articleRepository.js"; +import * as productRepository from "../repository/productRepository.js"; + +// 토큰 검증 +const verifyAccessToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + requestProperty: "user", +}); + +// refresh 토큰 검증 +const verifyRefreshToken = expressjwt({ + secret: process.env.JWT_SECRET, + algorithms: ["HS256"], + getToken: (req) => req.cookies.refreshToken, +}); + +// 게시글 유저 검증 +const verifyArticleAuth: RequestHandler = async (req, res, next) => { + // Get article id + const { id } = req.params; + + // Get article author's id + try { + const article = await articleRepository.getPost({ id: Number(id) }); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + return next(err); + } + + // Call next if valid user + if (req.user && req.user.userId === article.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 유저 검증 +const verifyProductAuth: RequestHandler = async (req, res, next) => { + // Get product id + const { id } = req.params; + + // Get product uploaders's id + try { + const product = await productRepository.getProduct({ id: Number(id) }); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + return next(err); + } + + // Call next if valid user + if (req.user && req.user.userId === product.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 게시글 존재 여부 확인 +const checkArticleExist: RequestHandler = async (req, res, next) => { + const { id } = req.params; + + try { + const article = await articleRepository.getPost({ id: Number(id) }); + if (!article) { + const err = new Error(`Article ${id} not found`); + err.statusCode = 404; + return next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 상품 존재 여부 확인 +const checkProductExist: RequestHandler = async (req, res, next) => { + const { id } = req.params; + + try { + const product = await productRepository.getProduct({ id: Number(id) }); + if (!product) { + const err = new Error(`Product ${id} not found`); + err.statusCode = 404; + return next(err); + } else next(); + } catch (err) { + next(err); + } +}; + +// 게시글 댓글 유저 검증 +const verifyArticleCommentAuth: RequestHandler = async (req, res, next) => { + const { cid } = req.params; + + if (!cid) { + const err = new Error("Comment id is required"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await articleRepository.getComment({ cid: parseInt(cid) }); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + return next(err); + } + + if (req.user && req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +// 상품 댓글 유저 검증 +const verifyProductCommentAuth: RequestHandler = async (req, res, next) => { + const { cid } = req.params; + + if (!cid) { + const err = new Error("Comment id is required"); + err.statusCode = 400; + return next(err); + } + + try { + const comment = await productRepository.getComment({ cid: parseInt(cid) }); + + if (!comment) { + const err = new Error(`Comment ${cid} not found`); + err.statusCode = 404; + return next(err); + } + + if (req.user && req.user.userId === comment.userId) next(); + else { + const err = new Error("Unauthorized"); + err.statusCode = 403; + return next(err); + } + } catch (err) { + next(err); + } +}; + +export default { + verifyAccessToken, + verifyRefreshToken, + verifyArticleAuth, + verifyProductAuth, + checkArticleExist, + checkProductExist, + verifyArticleCommentAuth, + verifyProductCommentAuth, +}; diff --git a/mission_11/src/middleware/index.ts b/mission_11/src/middleware/index.ts new file mode 100644 index 000000000..02584180c --- /dev/null +++ b/mission_11/src/middleware/index.ts @@ -0,0 +1 @@ +export * from './validator.js'; \ No newline at end of file diff --git a/mission_11/src/middleware/local.ts b/mission_11/src/middleware/local.ts new file mode 100644 index 000000000..09056202c --- /dev/null +++ b/mission_11/src/middleware/local.ts @@ -0,0 +1,36 @@ +import fs from "fs"; +import path from "path"; +import multer from "multer"; +import type { NextFunction, Request, Response } from "express"; + +const uploadDir = "uploads"; +if (!fs.existsSync(uploadDir)) { + fs.mkdirSync(uploadDir); +} + +const storage = multer.diskStorage({ + destination: function (req, file, cb) { + cb(null, uploadDir); + }, + filename: function (req, file, cb) { + cb(null, `${Date.now()}_${file.originalname}`); + }, +}); + +const upload = multer({ storage }); + +export const localUpload = { + single: (fieldName: string) => (req: Request, res: Response, next: NextFunction) => { + upload.single(fieldName)(req, res, (err) => { + if (err) { + return next(err); + } + if (req.file) { + const file = req.file as Express.Multer.File; + (file as any).location = `/uploads/${file.filename}`; + (file as any).key = file.filename; + } + next(); + }); + }, +}; diff --git a/mission_11/src/middleware/s3.ts b/mission_11/src/middleware/s3.ts new file mode 100644 index 000000000..0949940bc --- /dev/null +++ b/mission_11/src/middleware/s3.ts @@ -0,0 +1,28 @@ +import { S3Client } from '@aws-sdk/client-s3'; +import multer from 'multer'; +import multerS3 from 'multer-s3'; +import path from 'path'; + +const s3 = new S3Client({ + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID as string, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY as string, + }, + region: process.env.AWS_REGION as string, +}); + +export const s3upload = multer({ + storage: multerS3({ + s3: s3, + bucket: process.env.AWS_S3_BUCKET_NAME as string, + // acl: 'public-read', + contentType: multerS3.AUTO_CONTENT_TYPE, + metadata: function (req, file, cb) { + cb(null, { fieldName: file.fieldname }); + }, + key: function (req, file, cb) { + cb(null, `contents/${Date.now()}_${path.basename(file.originalname)}`); + }, + }), + limits: { fileSize: 5 * 1024 * 1024 }, +}); \ No newline at end of file diff --git a/mission_11/src/middleware/upload.ts b/mission_11/src/middleware/upload.ts new file mode 100644 index 000000000..e0465827a --- /dev/null +++ b/mission_11/src/middleware/upload.ts @@ -0,0 +1,6 @@ +import { localUpload } from "./local.js"; +import { s3upload } from "./s3.js"; + +const upload = process.env.NODE_ENV === "production" ? s3upload : localUpload; + +export default upload; diff --git a/mission_11/src/middleware/validator.ts b/mission_11/src/middleware/validator.ts new file mode 100644 index 000000000..48cf69245 --- /dev/null +++ b/mission_11/src/middleware/validator.ts @@ -0,0 +1,31 @@ +import type { RequestHandler } from "express"; + +// Verify required parameters are okay +const validateProduct: RequestHandler = async function (req, res, next) { + const { name, description, price, tags } = req.body; + + // validation logic (possible improvements with Zod library in the future) + if (!name || !description || !price || !tags) + return res.status(400).json({ message: "Missing required fields" }); + + if (isNaN(price)) + return res.status(400).json({ message: "Price must be a number" }); + + if (!Array.isArray(tags) || !tags.every((tag) => typeof tag === "string")) + return res.status(400).json({ message: "Tags must be an array of string" }); + + next(); +}; + +// Verify required parameters are okay +const validateArticle: RequestHandler = async function (req, res, next) { + const { title, content } = req.body; + + // validation + if (!title || !content) + return res.status(400).json({ message: "Invalid SQL Parameters" }); + + next(); +}; + +export { validateProduct, validateArticle }; diff --git a/mission_11/src/repository/articleRepository.ts b/mission_11/src/repository/articleRepository.ts new file mode 100644 index 000000000..a3a79f670 --- /dev/null +++ b/mission_11/src/repository/articleRepository.ts @@ -0,0 +1,177 @@ +import prisma from "../lib/prisma.js"; +import type { + CreatePostDTO, + GetPostsDTO, + GetPostDTO, + PatchPostDTO, + DeletePostDTO, + PostCommentDTO, + GetCommentsDTO, + GetCommentDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/article.js"; + +export async function createPost(data: CreatePostDTO) { + return await prisma.article.create({ + data, + }); +} + +export async function getPosts(data: GetPostsDTO) { + // search에 값이 있을 때만 where로 문자열 검색 + const where = data.search + ? { + OR: [ + { + title: { + contains: data.search, + mode: "insensitive" as const, + }, + }, + { + content: { + contains: data.search, + mode: "insensitive" as const, + }, + }, + ], + } + : {}; + + const result = await prisma.article.findMany({ + select: { + id: true, + title: true, + content: true, + createdAt: true, + }, + orderBy: { + createdAt: data.sort, + }, + where, + skip: data.offset * data.limit, + take: data.limit, + }); + + return result; +} + +export async function getPost(data: GetPostDTO) { + const result = await prisma.article.findUnique({ + where: { + id: data.id, + }, + }); + + return result; +} + +export async function patchPost(data: PatchPostDTO) { + const { id, ...filteredBody } = data; + + const result = await prisma.article.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deletePost(data: DeletePostDTO) { + const { id } = data; + + const result = await prisma.article.delete({ + where: { + id, + }, + }); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const { pid: articleId, name, content, userId } = data; + + const result = await prisma.comment.create({ + data: { + name, + content, + articleId, + userId, + }, + }); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const { pid, cursor, limit } = data; + + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + articleId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(data: GetCommentDTO) { + const { cid: id } = data; + + const result = await prisma.comment.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const { cid, name, content } = data; + + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const { cid } = data; + + const result = prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} diff --git a/mission_11/src/repository/index.ts b/mission_11/src/repository/index.ts new file mode 100644 index 000000000..cab62f42d --- /dev/null +++ b/mission_11/src/repository/index.ts @@ -0,0 +1,4 @@ +export * from './articleRepository.js'; +export * from './productRepository.js'; +export * from './userRepository.js'; +export * from './notificationRepository.js'; \ No newline at end of file diff --git a/mission_11/src/repository/notificationRepository.ts b/mission_11/src/repository/notificationRepository.ts new file mode 100644 index 000000000..88829f4fe --- /dev/null +++ b/mission_11/src/repository/notificationRepository.ts @@ -0,0 +1,68 @@ +import prisma from '../lib/prisma.js'; + +async function create( + userId: number, + message: string, + articleId?: number, + productId?: number +) { + return prisma.notification.create({ + data: { + userId, + message, + articleId: articleId ?? null, + productId: productId ?? null, + }, + }); +} + +async function findManyByUserId(userId: number) { + return prisma.notification.findMany({ + where: { userId }, + orderBy: { createdAt: 'desc' }, + }); +} + +async function getUnreadCount(userId: number) { + return prisma.notification.count({ + where: { + userId, + read: false, + }, + }); +} + +async function markAsRead(notificationId: number, userId: number) { + const notification = await prisma.notification.findUnique({ + where: { id: notificationId }, + }); + + if (!notification || notification.userId !== userId) { + throw new Error('인증되지 않음 접근 혹은 알림 ID가 존재하지 않음'); + } + + return prisma.notification.update({ + where: { id: notificationId }, + data: { read: true }, + }); +} + +async function markAllAsRead(userId: number) { + return prisma.notification.updateMany({ + where: { + userId, + read: false, + }, + data: { + read: true, + }, + }); +} + +export default { + create, + findManyByUserId, + getUnreadCount, + markAsRead, + markAllAsRead, +}; diff --git a/mission_11/src/repository/productRepository.ts b/mission_11/src/repository/productRepository.ts new file mode 100644 index 000000000..1a8ea9922 --- /dev/null +++ b/mission_11/src/repository/productRepository.ts @@ -0,0 +1,235 @@ +import prisma from "../lib/prisma.js"; +import type { + CreateProductDTO, + GetProductsDTO, + GetProductDTO, + PatchProductDTO, + DeleteProductDTO, + PostCommentDTO, + GetCommentsDTO, + GetCommentDTO, + PatchCommentDTO, + DeleteCommentDTO, + GetProductsByUserDTO, +} from "../types/product.js"; + +export async function createProduct(data: CreateProductDTO) { + const { userId, name, description, price, tags } = data; + + return await prisma.product.create({ + data: { + name, + description, + price, + tags, + userId, + }, + }); +} + +export async function getProducts(data: GetProductsDTO) { + const { offset, limit, sort, search } = data; + + const result = await prisma.product.findMany({ + select: { + id: true, + name: true, + price: true, + createdAt: true, + }, + orderBy: { + createdAt: sort, + }, + where: { + OR: [ + { + name: { + contains: search, + mode: "insensitive", + }, + }, + { + description: { + contains: search, + mode: "insensitive", + }, + }, + ], + }, + skip: offset * limit, + take: limit, + }); + + return result; +} + +export async function getProduct(data: GetProductDTO) { + const { id } = data; + const result = await prisma.product.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchProduct(data: PatchProductDTO) { + const { id, ...filteredBody } = data; + + const result = await prisma.product.update({ + where: { + id: Number(id), + }, + data: { + ...filteredBody, + }, + }); + + return result; +} + +export async function deleteProduct(data: DeleteProductDTO) { + const { id } = data; + + const result = await prisma.product.delete({ + where: { + id, + }, + }); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const { pid, userId, name, content } = data; + + const result = await prisma.comment.create({ + data: { + userId, + name, + content, + productId: pid, + }, + }); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const { pid, cursor, limit } = data; + + const result = await prisma.comment.findMany({ + select: { + id: true, + content: true, + createdAt: true, + }, + where: { + productId: Number(pid), + }, + orderBy: { + id: "asc", + }, + take: Number(limit), + ...(cursor + ? { + skip: 1, + cursor: { id: Number(cursor) }, + } + : {}), + }); + + return result; +} + +export async function getComment(data: GetCommentDTO) { + const { cid: id } = data; + + const result = await prisma.comment.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const { cid, name, content } = data; + + const result = await prisma.comment.update({ + where: { + id: Number(cid), + }, + data: { + name, + content, + }, + }); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const { cid } = data; + + const result = await prisma.comment.delete({ + where: { + id: Number(cid), + }, + }); + + return result; +} + +export async function getProductsByUser(data: GetProductsByUserDTO) { + const { userId: id } = data; + + const products = await prisma.user.findUnique({ + where: { id }, + select: { + Product: true, + }, + }); + + return products; +} + +export async function findLike(userId: number, productId: number) { + return prisma.likedProduct.findUnique({ + where: { + userId_productId: { + userId, + productId, + }, + }, + }); +} + +export async function likeProduct(userId: number, productId: number) { + return prisma.likedProduct.create({ + data: { + userId, + productId, + }, + }); +} + +export async function unlikeProduct(userId: number, productId: number) { + return prisma.likedProduct.delete({ + where: { + userId_productId: { + userId, + productId, + }, + }, + }); +} + +export async function getLikedUsersByProductId(productId: number) { + return prisma.likedProduct.findMany({ + where: { productId }, + select: { userId: true }, + }); +} diff --git a/mission_11/src/repository/userRepository.ts b/mission_11/src/repository/userRepository.ts new file mode 100644 index 000000000..3ec40d685 --- /dev/null +++ b/mission_11/src/repository/userRepository.ts @@ -0,0 +1,61 @@ +import prisma from "../lib/prisma.js"; +import bcrypt from "bcrypt"; +import type { CreateUserDTO, UserInfoDTO, GetUserDTO } from "../types/user.js"; + +export async function createUser(user: CreateUserDTO) { + const hashedPassword = await hashPassword(user.password); + + const createdUser = await prisma.user.create({ + data: { + ...user, + password: hashedPassword, // This line overwrites user.password + }, + }); + + return createdUser; +} + +export async function findByEmail(email: string) { + const result = await prisma.user.findFirst({ + where: { + email, + }, + }); + + return result; +} + +export async function findById(id: number) { + const result = await prisma.user.findUnique({ + where: { + id, + }, + }); + + return result; +} + +export async function hashPassword(password: string) { + const salt = await bcrypt.genSalt(10); + const hash = await bcrypt.hash(password, salt); + + return hash; +} + +export function filterSensitiveUserData(user: UserInfoDTO) { + const { password, refreshToken, ...rest } = user; + return rest; +} + +export async function updateUser(id: number, toUpdate: any) { + if (toUpdate.password) { + toUpdate.password = await hashPassword(toUpdate.password); + } + + const updatedUser = await prisma.user.update({ + where: { id }, + data: toUpdate, + }); + + return updatedUser; +} diff --git a/mission_11/src/router/articleRouter.ts b/mission_11/src/router/articleRouter.ts new file mode 100644 index 000000000..07b603722 --- /dev/null +++ b/mission_11/src/router/articleRouter.ts @@ -0,0 +1,73 @@ +import express from "express"; +import { validateArticle } from "../middleware/index.js"; +import auth from "../middleware/auth.js"; +import * as articleController from "../controller/articleController.js"; + +const router = express.Router(); + +router + .route("/") + + // Create a post + .post( + auth.verifyAccessToken, + validateArticle, + articleController.createPost + ) + + // Retrieve all articles + .get(articleController.getPosts); + +router + .route("/:id") + + // Get informations of a specific article + .get(articleController.getPost) + + // Modify a article property + .patch( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.patchPost + ) + + // Delete a particular article + .delete( + auth.verifyAccessToken, + auth.verifyArticleAuth, + articleController.deletePost + ); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkArticleExist, + articleController.postComment + ) + + // Inquery all comments + .get(auth.checkArticleExist, articleController.getComments); + +router + .route("/:id/comments/:cid") + + // Modify comment + .patch( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.patchComment + ) + + // Delete comment + .delete( + auth.verifyAccessToken, + auth.checkArticleExist, + auth.verifyArticleCommentAuth, + articleController.deleteComment + ); + +export default router; diff --git a/mission_11/src/router/imageRouter.ts b/mission_11/src/router/imageRouter.ts new file mode 100644 index 000000000..ee4b4e093 --- /dev/null +++ b/mission_11/src/router/imageRouter.ts @@ -0,0 +1,26 @@ +import express from 'express'; +import { imageController } from '../controller/imageController.js'; +import upload from '../middleware/upload.js'; +// import multer from "multer"; + +const router = express.Router(); + +// const upload = multer({ dest: 'uploads/' }); + +/* // 이미지 리사이징 기능 구현 예정 +router.post('/', upload.single('image'), async (req, res) => { + // console.log(req.file); + if (!req.file) { + return res.status(400).json({ message: 'No file uploaded' }); + } + + res.status(201).json({ message: 'Upload OK', filePath: req.file.path }); +}); */ + +router.post( + '/', + upload.single('image'), + imageController.uploadImage +); + +export default router; \ No newline at end of file diff --git a/mission_11/src/router/index.ts b/mission_11/src/router/index.ts new file mode 100644 index 000000000..2ef8681ab --- /dev/null +++ b/mission_11/src/router/index.ts @@ -0,0 +1,5 @@ +export * from './articleRouter.js'; +export * from './productRouter.js'; +export * from './imageRouter.js'; +export * from './userRouter.js'; +export * from './notificationRouter.js'; \ No newline at end of file diff --git a/mission_11/src/router/notificationRouter.ts b/mission_11/src/router/notificationRouter.ts new file mode 100644 index 000000000..9266195ad --- /dev/null +++ b/mission_11/src/router/notificationRouter.ts @@ -0,0 +1,35 @@ +import { Router } from 'express'; +import notificationController from '../controller/notificationController.js'; +import auth from '../middleware/auth.js'; + +const router = Router(); + +// 모든 알림을 받아옴 +router.get( + '/notifications', + auth.verifyAccessToken, + notificationController.getNotifications +); + +// 알림 수를 받아옴 +router.get( + '/notifications/unread-count', + auth.verifyAccessToken, + notificationController.getUnreadCount +); + +// 알림을 읽음으로 표시 +router.patch( + '/notifications/:id/read', + auth.verifyAccessToken, + notificationController.markAsRead +); + +// 모든 알림을 읽음으로 표시 +router.patch( + '/notifications/read-all', + auth.verifyAccessToken, + notificationController.markAllAsRead +); + +export default router; diff --git a/mission_11/src/router/productRouter.ts b/mission_11/src/router/productRouter.ts new file mode 100644 index 000000000..9383b6fa7 --- /dev/null +++ b/mission_11/src/router/productRouter.ts @@ -0,0 +1,79 @@ +import express from "express"; +import type { Router } from "express"; +import { validateProduct } from "../middleware/validator.js"; +import auth from "../middleware/auth.js"; +import * as productController from "../controller/productController.js"; + +const router = express.Router(); + +router + .route("/") + + // Upload a new product + .post( + auth.verifyAccessToken, + validateProduct, + productController.createProduct + ) + + // Retrieve all products + .get(productController.getProducts); + +router + .route("/:id") + + // Get informations of a specific product + .get(productController.getProduct) + + // Modify a product property + .patch( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.patchProduct + ) + + // Delete a particular product + .delete( + auth.verifyAccessToken, + auth.verifyProductAuth, + productController.deleteProduct + ); + +// Like or unlike a product +router.post( + "/:id/like", + auth.verifyAccessToken, + productController.toggleLike +); + +router + .route("/:id/comments") + + // Add a comment + .post( + auth.verifyAccessToken, + auth.checkProductExist, + productController.postComment + ) + + // Inquery all comments + .get(auth.checkProductExist, productController.getComments); + +router + .route("/:id/comments/:cid") + + .patch( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.patchComment + ) + + .delete( + auth.verifyAccessToken, + auth.checkProductExist, + auth.verifyProductCommentAuth, + productController.deleteComment + ); + +export default router; diff --git a/mission_11/src/router/userRouter.ts b/mission_11/src/router/userRouter.ts new file mode 100644 index 000000000..9ab871231 --- /dev/null +++ b/mission_11/src/router/userRouter.ts @@ -0,0 +1,44 @@ +import express from "express"; +import * as userController from "../controller/userController.js"; +import auth from "../middleware/auth.js"; + +const userRouter = express.Router(); + +userRouter + .route("/users") + + // Create user + .post(userController.createUser) + + // Get my(user) info + .get(auth.verifyAccessToken, userController.getMyInfo); + +// Update user info (nickname, email) +userRouter.patch( + "/users/info", + auth.verifyAccessToken, + userController.updateMyInfo +); + +// Update user password +userRouter.patch( + "/users/password", + auth.verifyAccessToken, + userController.updateMyPassword +); + +// Get product lists uploaded by user +userRouter.get( + "/users/products", + auth.verifyAccessToken, + userController.getMyProducts +); + +userRouter.post("/login", userController.getAccessToken); +userRouter.post( + "/login/refresh", + auth.verifyRefreshToken, + userController.getRefreshToken +); + +export default userRouter; diff --git a/mission_11/src/services/articleService.ts b/mission_11/src/services/articleService.ts new file mode 100644 index 000000000..caaca1aac --- /dev/null +++ b/mission_11/src/services/articleService.ts @@ -0,0 +1,80 @@ +import * as articleRepository from "../repository/articleRepository.js"; +import notificationService from "./notificationService.js"; +import type { + CreatePostDTO, + GetPostsDTO, + GetPostDTO, + PatchPostDTO, + DeletePostDTO, + PostCommentDTO, + GetCommentsDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/article.js"; + +export async function createPost(data: CreatePostDTO) { + const result = await articleRepository.createPost(data); + + return result; +} + +export async function getPosts(data: GetPostsDTO) { + const result = await articleRepository.getPosts(data); + + return result; +} + +export async function getPost(id: GetPostDTO) { + const result = await articleRepository.getPost(id); + + return result; +} + +export async function patchPost(data: PatchPostDTO) { + const result = await articleRepository.patchPost(data); + + return result; +} + +export async function deletePost(id: DeletePostDTO) { + const result = await articleRepository.deletePost(id); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const newComment = await articleRepository.postComment(data); + + const article = await articleRepository.getPost({ id: data.pid }); + if (!article) { + return newComment; + } + + if (article.userId !== data.userId) { + const message = `내가 판매 신청한 매물에 새로운 댓글이 달렸습니다.`; + await notificationService.createNotification( + article.userId, + message, + article.id + ); + } + + return newComment; +} + +export async function getComments(data: GetCommentsDTO) { + const result = await articleRepository.getComments(data); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const result = await articleRepository.patchComment(data); + + return result; +} +export async function deleteComment(data: DeleteCommentDTO) { + const result = await articleRepository.deleteComment(data); + + return result; +} diff --git a/mission_11/src/services/index.ts b/mission_11/src/services/index.ts new file mode 100644 index 000000000..69a5a5e9d --- /dev/null +++ b/mission_11/src/services/index.ts @@ -0,0 +1,4 @@ +export * from './articleService.js'; +export * from './productService.js'; +export * from './userService.js'; +export * from './notificationService.js'; \ No newline at end of file diff --git a/mission_11/src/services/notificationService.ts b/mission_11/src/services/notificationService.ts new file mode 100644 index 000000000..51d3cad92 --- /dev/null +++ b/mission_11/src/services/notificationService.ts @@ -0,0 +1,66 @@ +import notificationRepository from '../repository/notificationRepository.js'; +import { getIO } from '../lib/socket.js'; + +async function createNotification( + userId: number, + message: string, + articleId?: number, + productId?: number +) { + const newNotification = await notificationRepository.create( + userId, + message, + articleId, + productId + ); + + // 특정 유저ID에게 실시간 알림 전송 + const io = getIO(); + io.to(String(userId)).emit('new_notification', newNotification); + + // Also emit an unread count update + const unreadCount = await notificationRepository.getUnreadCount(userId); + io.to(String(userId)).emit('unread_count', unreadCount); + + return newNotification; +} + +async function getUserNotifications(userId: number) { + return notificationRepository.findManyByUserId(userId); +} + +async function getUnreadNotificationCount(userId: number) { + return notificationRepository.getUnreadCount(userId); +} + +async function markNotificationAsRead(notificationId: number, userId: number) { + const updatedNotification = await notificationRepository.markAsRead( + notificationId, + userId + ); + + // Emit an unread count update + const io = getIO(); + const unreadCount = await notificationRepository.getUnreadCount(userId); + io.to(String(userId)).emit('unread_count', unreadCount); + + return updatedNotification; +} + +async function markAllNotificationsAsRead(userId: number) { + const result = await notificationRepository.markAllAsRead(userId); + + // Emit an unread count update + const io = getIO(); + io.to(String(userId)).emit('unread_count', 0); + + return result; +} + +export default { + createNotification, + getUserNotifications, + getUnreadNotificationCount, + markNotificationAsRead, + markAllNotificationsAsRead, +}; diff --git a/mission_11/src/services/productService.ts b/mission_11/src/services/productService.ts new file mode 100644 index 000000000..0444fdb75 --- /dev/null +++ b/mission_11/src/services/productService.ts @@ -0,0 +1,103 @@ +import * as productRepository from "../repository/productRepository.js"; +import notificationService from "./notificationService.js"; +import type { + CreateProductDTO, + GetProductsDTO, + GetProductDTO, + PatchProductDTO, + DeleteProductDTO, + PostCommentDTO, + GetCommentsDTO, + PatchCommentDTO, + DeleteCommentDTO, +} from "../types/product.js"; + +export async function createProduct(data: CreateProductDTO) { + const result = await productRepository.createProduct(data); + + return result; +} + +export async function getProducts(data: GetProductsDTO) { + const result = await productRepository.getProducts(data); + + return result; +} + +export async function getProduct(data: GetProductDTO) { + const result = await productRepository.getProduct(data); + + return result; +} + +export async function patchProduct(data: PatchProductDTO) { + const { id, price: newPrice } = data; + + const originalProduct = await productRepository.getProduct({ id: Number(id) }); + if (!originalProduct) { + throw new Error("상품이 존재하지 않습니다."); + } + const oldPrice = originalProduct.price; + + const updatedProduct = await productRepository.patchProduct(data); + + if (newPrice !== undefined && newPrice !== oldPrice) { + const likedUsers = await productRepository.getLikedUsersByProductId( + Number(id) + ); + + for (const liked of likedUsers) { + const message = `'${originalProduct.name}' 상품의 가격이 ${oldPrice}원에서 ${newPrice}원으로 변경되었습니다.`; + await notificationService.createNotification( + liked.userId, + message, + undefined, + Number(id) + ); + } + } + + return updatedProduct; +} + +export async function deleteProduct(data: DeleteProductDTO) { + const result = await productRepository.deleteProduct(data); + + return result; +} + +export async function postComment(data: PostCommentDTO) { + const result = await productRepository.postComment(data); + + return result; +} + +export async function getComments(data: GetCommentsDTO) { + const result = await productRepository.getComments(data); + + return result; +} + +export async function patchComment(data: PatchCommentDTO) { + const result = await productRepository.patchComment(data); + + return result; +} + +export async function deleteComment(data: DeleteCommentDTO) { + const result = await productRepository.deleteComment(data); + + return result; +} + +export async function toggleLike(userId: number, productId: number) { + const existingLike = await productRepository.findLike(userId, productId); + + if (existingLike) { + await productRepository.unlikeProduct(userId, productId); + return { message: '관심 목록에서 삭제했습니다.' }; + } else { + await productRepository.likeProduct(userId, productId); + return { message: '관심 목록에 추가했습니다.' }; + } +} diff --git a/mission_11/src/services/userService.ts b/mission_11/src/services/userService.ts new file mode 100644 index 000000000..2060ef614 --- /dev/null +++ b/mission_11/src/services/userService.ts @@ -0,0 +1,121 @@ +import * as userRepository from "../repository/userRepository.js"; +import * as productRepository from "../repository/productRepository.js"; +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; +import type { CreateUserDTO, GetUserDTO, UserInfoDTO } from "../types/user.js"; + +export async function createUser(user: CreateUserDTO) { + // 이미 가입된 이메일인지 검증 + const existedUser = await userRepository.findByEmail(user.email); + + if (existedUser) { + const err = new Error("User already exists"); + err.statusCode = 422; + throw err; + } + + const createdUser = await userRepository.createUser(user); + const createdUserId = await userRepository.filterSensitiveUserData( + createdUser + ).id; + + return createdUserId; +} + +export async function getUser({ email, password }: GetUserDTO) { + const user: UserInfoDTO | null = await userRepository.findByEmail(email); + + // If user is invalid + if (!user || !user.password) { + const err = new Error("Unauthorized"); + err.statusCode = 401; + throw err; + } + + // Verifying password + await verifyPassword(password, user.password); + + // Return without password + return userRepository.filterSensitiveUserData(user); +} + +export async function getUserById(userId: number) { + const user = await userRepository.findById(userId); + + if (!user) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return userRepository.filterSensitiveUserData(user); +} + +async function verifyPassword(inputPassword: string, password: string) { + const isVerified = await bcrypt.compare(inputPassword, password); + + if (!isVerified) { + const err = new Error("Password is wrong"); + err.statusCode = 401; + throw err; + } +} + +export function createToken(user: UserInfoDTO, token: string | null = null) { + const payload = { userId: user.id }; + const options: jwt.SignOptions = { + expiresIn: token === "refresh" ? "2W" : "1H", + }; + + if (!process.env.JWT_SECRET) { + throw new Error("JWT_SECRET is not defined"); + } + + return jwt.sign(payload, process.env.JWT_SECRET, options); +} + +export async function refreshToken(userId: number, refreshToken: string) { + const user = await userRepository.findById(userId); + + if (!user || user.refreshToken !== refreshToken) { + const err = new Error("Unauthorized"); + err.statusCode = 404; + throw err; + } + + const accessToken = createToken(user); + return accessToken; +} + +export async function updateUserInfo(userId: number, toUpdate: any) { + // 수정할 내용이 없다면 에러 처리 + if (Object.keys(toUpdate).length === 0) { + const err = new Error("No data to update"); + err.statusCode = 400; + throw err; + } + + const updatedUser = await userRepository.updateUser(userId, toUpdate); + + return userRepository.filterSensitiveUserData(updatedUser); +} + +export async function updateUserPassword(userId: number, newPassword: string) { + const hashedPassword = await userRepository.hashPassword(newPassword); + const user = await userRepository.updateUser(userId, { + password: hashedPassword, + }); + + return userRepository.filterSensitiveUserData(user); +} + +export async function getMyProducts(userId: number) { + const products = await productRepository.getProductsByUser({ userId }); + if (!products) { + const err = new Error("User not found"); + err.statusCode = 404; + throw err; + } + + return products.Product; +} diff --git a/mission_11/src/test/integration/article-auth.test.ts b/mission_11/src/test/integration/article-auth.test.ts new file mode 100644 index 000000000..81c8ac2d0 --- /dev/null +++ b/mission_11/src/test/integration/article-auth.test.ts @@ -0,0 +1,169 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; +import { getAuthToken } from "../util/getAuthToken.js"; + +const prisma = new PrismaClient(); + +let authToken: string; +let userId: number; +let articleId: number; +let commentId: number; + +const mockUser = { + email: "article-auth-user@test.com", + nickname: "test-auth", + password: "password123", +}; + +const mockArticle = { + title: "Auth Test Article", + content: "This is the content of the auth test article.", +}; + +const mockComment = { + name: "test-author", + content: "Example auth comment", +}; + +beforeAll(async () => { + // Ensure user does not exist + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + await request(app).post("/users").send(mockUser); + authToken = await getAuthToken(mockUser.email, mockUser.password); + const user = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + userId = user!.id; + + const articleResponse = await request(app) + .post("/articles") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockArticle, userId }); + articleId = articleResponse.body.id; + + const commentResponse = await request(app) + .post(`/articles/${articleId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockComment, userId }); + commentId = commentResponse.body.id; +}); + +afterAll(async () => { + await prisma.user.delete({ where: { id: userId } }); + authToken = ""; +}); + +describe("Article Integration Test (Auth)", () => { + describe("POST /articles", () => { + it("should create another article and return its properties", async () => { + const anotherMockArticle = { + title: "Another New Article", + content: "This is another article.", + }; + + const response = await request(app) + .post("/articles") + .set("Authorization", `Bearer ${authToken}`) + .send(anotherMockArticle) + .expect(201); + expect(response.body).toEqual( + expect.objectContaining({ id: expect.any(Number) }) + ); + await prisma.article.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /articles/:id", () => { + it("should update a specific article by ID", async () => { + const updatedData = { + title: "Modified Title", + }; + + const response = await request(app) + .patch(`/articles/${articleId}`) + .set("Authorization", `Bearer ${authToken}`) + .send(updatedData) + .expect(200); + + expect(response.body).toEqual( + expect.objectContaining({ id: articleId, title: updatedData.title }) + ); + }); + }); + + describe("DELETE /articles/:id", () => { + it("should delete a specific article by ID", async () => { + const tempArticleRes = await request(app) + .post("/articles") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockArticle, title: "To Be Deleted" }); + const tempArticleId = tempArticleRes.body.id; + + const response = await request(app) + .delete(`/articles/${tempArticleId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempArticleId); + }); + }); + + describe("POST /articles/:id/comments", () => { + it("should post another comment to a specific article", async () => { + const anotherMockComment = { + name: "another-author", + content: "Another example comment", + }; + + const response = await request(app) + .post(`/articles/${articleId}/comments`) + .send(anotherMockComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(201); + + expect(response.body).toHaveProperty("id"); + await prisma.comment.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /articles/:id/comments/:cid", () => { + it("should update a specific comment by ID", async () => { + const updatedComment = { + name: "updated-author", + content: "Updated comment content", + }; + + const response = await request(app) + .patch(`/articles/${articleId}/comments/${commentId}`) + .send(updatedComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("content", updatedComment.content); + }); + }); + + describe("DELETE /articles/:id/comments/:cid", () => { + it("should delete a specific comment by ID", async () => { + const tempCommentRes = await request(app) + .post(`/articles/${articleId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ name: "temp-user", content: "to be deleted" }); + const tempCommentId = tempCommentRes.body.id; + + const response = await request(app) + .delete(`/articles/${articleId}/comments/${tempCommentId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempCommentId); + }); + }); +}); diff --git a/mission_11/src/test/integration/article-noauth.test.ts b/mission_11/src/test/integration/article-noauth.test.ts new file mode 100644 index 000000000..bccb9fb11 --- /dev/null +++ b/mission_11/src/test/integration/article-noauth.test.ts @@ -0,0 +1,79 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); +let articleId: number; +let userId: number; + +const mockUser = { + email: "article-noauth-user@test.com", + nickname: "test-noauth", + password: "password123", +}; + +beforeAll(async () => { + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + // Create user + const userResponse = await request(app).post("/users").send(mockUser); + userId = userResponse.body.userId; + + // Create article + const article = await prisma.article.create({ + data: { + title: "Test Article", + content: "Test Content", + userId: userId, + }, + }); + articleId = article.id; +}); + +afterAll(async () => { + // Clean up + await prisma.user.delete({ where: { id: userId } }); +}); + +describe("Article Integration Test (No Auth)", () => { + describe("GET /articles", () => { + it("should return a list of articles", async () => { + const response = await request(app).get("/articles").expect(200); + expect(Array.isArray(response.body)).toBe(true); + }); + }); + + describe("GET /articles/:id", () => { + it("should return a specific article by ID", async () => { + const response = await request(app) + .get(`/articles/${articleId}`) + .expect(200); + + expect(response.body).toEqual(expect.objectContaining({ id: articleId })); + }); + + it("should return 404 for non-existing article", async () => { + const nonExistingId = 9999; + await request(app).get(`/articles/${nonExistingId}`).expect(404); + }); + }); + + describe("GET /articles/:id/comments", () => { + it("should return comments for a specific article", async () => { + const response = await request(app) + .get(`/articles/${articleId}/comments`) + .expect(200); + expect(Array.isArray(response.body.comments)).toBe(true); + }); + + it("should return 404 for comments of non-existing article", async () => { + const nonExistingId = 9999; + await request(app).get(`/articles/${nonExistingId}/comments`).expect(404); + }); + }); +}); diff --git a/mission_11/src/test/integration/product-auth.test.ts b/mission_11/src/test/integration/product-auth.test.ts new file mode 100644 index 000000000..ed556c171 --- /dev/null +++ b/mission_11/src/test/integration/product-auth.test.ts @@ -0,0 +1,169 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; +import { getAuthToken } from "../util/getAuthToken.js"; + +const prisma = new PrismaClient(); + +let authToken: string; +let userId: number; +let productId: number; +let commentId: number; + +const mockUser = { + email: "product-auth-user@test.com", + nickname: "test-product-auth", + password: "password123", +}; + +const mockProduct = { + name: "Auth Test Product", + description: "This is an auth test product.", + price: 50000, + tags: [], +}; + +const mockComment = { + name: "product-comment-author", + content: "Example product auth comment", +}; + +beforeAll(async () => { + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + await request(app).post("/users").send(mockUser); + authToken = await getAuthToken(mockUser.email, mockUser.password); + const user = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + userId = user!.id; + + const productResponse = await request(app) + .post("/products") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockProduct, userId }); + productId = productResponse.body.id; + + const commentResponse = await request(app) + .post(`/products/${productId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockComment, userId }); + commentId = commentResponse.body.id; +}); + +afterAll(async () => { + await prisma.user.delete({ where: { id: userId } }); + authToken = ""; +}); + +describe("Product Integration Test (Auth)", () => { + describe("POST /products", () => { + it("should upload another product and return its properties", async () => { + const anotherMockProduct = { + name: "Another Auth Product", + description: "Another one.", + price: 100, + tags: ["new"], + }; + + const response = await request(app) + .post("/products") + .set("Authorization", `Bearer ${authToken}`) + .send(anotherMockProduct) + .expect(201); + expect(response.body).toEqual( + expect.objectContaining({ id: expect.any(Number) }) + ); + await prisma.product.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /products/:id", () => { + it("should update a specific product by ID", async () => { + const updatedData = { + price: 9999, + }; + + const response = await request(app) + .patch(`/products/${productId}`) + .send(updatedData) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("price", updatedData.price); + }); + }); + + describe("DELETE /products/:id", () => { + it("should delete a specific product by ID", async () => { + const tempProductRes = await request(app) + .post("/products") + .set("Authorization", `Bearer ${authToken}`) + .send({ ...mockProduct, name: "To Be Deleted" }); + const tempProductId = tempProductRes.body.id; + + const response = await request(app) + .delete(`/products/${tempProductId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempProductId); + }); + }); + + describe("POST /products/:id/comments", () => { + it("should post another comment to a specific product", async () => { + const anotherMockComment = { + name: "another-product-commenter", + content: "Another product comment", + }; + + const response = await request(app) + .post(`/products/${productId}/comments`) + .send(anotherMockComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(201); + + expect(response.body).toHaveProperty("id"); + await prisma.comment.delete({ where: { id: response.body.id } }); + }); + }); + + describe("PATCH /products/:id/comments/:cid", () => { + it("should update a specific comment by ID", async () => { + const updatedComment = { + name: "updated-product-commenter", + content: "Updated product comment", + }; + const response = await request(app) + .patch(`/products/${productId}/comments/${commentId}`) + .send(updatedComment) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("content", updatedComment.content); + }); + }); + + describe("DELETE /products/:id/comments/:cid", () => { + it("should delete a specific comment by ID", async () => { + const tempCommentRes = await request(app) + .post(`/products/${productId}/comments`) + .set("Authorization", `Bearer ${authToken}`) + .send({ name: "temp-user", content: "to be deleted" }); + const tempCommentId = tempCommentRes.body.id; + + const response = await request(app) + .delete(`/products/${productId}/comments/${tempCommentId}`) + .set("Authorization", `Bearer ${authToken}`) + .expect(200); + + expect(response.body).toHaveProperty("id", tempCommentId); + }); + }); +}); diff --git a/mission_11/src/test/integration/product-noauth.test.ts b/mission_11/src/test/integration/product-noauth.test.ts new file mode 100644 index 000000000..51ac29c4d --- /dev/null +++ b/mission_11/src/test/integration/product-noauth.test.ts @@ -0,0 +1,84 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { PrismaClient } from "@prisma/client"; + +const mockUser = { + email: "test@example.com", + nickname: "test", + password: "password123", +}; + +let productId: number; +let userId: number; + +const prisma = new PrismaClient(); + +beforeAll(async () => { + // Delete user if it exists to ensure a clean slate + const existingUser = await prisma.user.findUnique({ + where: { email: mockUser.email }, + }); + if (existingUser) { + await prisma.user.delete({ where: { id: existingUser.id } }); + } + + const response = await request(app).post("/users").send(mockUser); + userId = response.body.userId; + + const res = await prisma.product.create({ + data: { + name: "Test Product", + description: "Test Product Desc", + price: 10010, + userId: userId, + }, + }); + + productId = res.id; +}); + +afterAll(async () => { + await prisma.user.deleteMany({ + where: { + email: mockUser.email, + }, + }); +}); + +describe("Product Integration Test (No Auth)", () => { + describe("GET /products", () => { + it("should return a list of products", async () => { + const response = await request(app).get("/products").expect(200); + expect(Array.isArray(response.body)).toBe(true); + }); + }); + + describe("GET /products/:id", () => { + it("should return a specific product by ID", async () => { + const response = await request(app) + .get(`/products/${productId}`) + .expect(200); + + expect(response.body).toHaveProperty("id"); + }); + + it("should return 404 for non-existing product", async () => { + const nonExistingId = 9999; + await request(app).get(`/products/${nonExistingId}`).expect(404); + }); + }); + + describe("GET /products/:id/comments", () => { + it("should return comments for a specific product", async () => { + const response = await request(app) + .get(`/products/${productId}/comments`) + .expect(200); + expect(Array.isArray(response.body.comments)).toBe(true); + }); + + it("should return 404 for comments of non-existing product", async () => { + const nonExistingId = 9999; + await request(app).get(`/products/${nonExistingId}/comments`).expect(404); + }); + }); +}); diff --git a/mission_11/src/test/integration/user.test.ts b/mission_11/src/test/integration/user.test.ts new file mode 100644 index 000000000..483657353 --- /dev/null +++ b/mission_11/src/test/integration/user.test.ts @@ -0,0 +1,43 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; +import { getAuthToken } from "../util/getAuthToken.js"; +import { PrismaClient } from "@prisma/client"; + +const mockUser = { + email: "testtest@example.com", + nickname: "test", + password: "password123", +}; + +const prisma = new PrismaClient(); + +afterAll(async () => { + await prisma.user.deleteMany({ + where: { + email: mockUser.email, + }, + }); +}); + +describe("User Integration Test", () => { + describe("POST /users", () => { + it("should return a id of user newly created", async () => { + const response = await request(app) + .post("/users") + .send(mockUser) + .expect(200); + expect(response.body).toHaveProperty("userId"); + }); + + it("should return 400 status code", async () => { + const response = await request(app).post("/users").send({}).expect(400); + }); + }); + + describe("POST /login", () => { + it("should return a string of accessToken", async () => { + const accessToken = await getAuthToken(mockUser.email, mockUser.password); + expect(typeof accessToken).toBe("string"); + }); + }); +}); diff --git a/mission_11/src/test/setup.ts b/mission_11/src/test/setup.ts new file mode 100644 index 000000000..a80cd98d9 --- /dev/null +++ b/mission_11/src/test/setup.ts @@ -0,0 +1,4 @@ +import { jest } from '@jest/globals'; + +jest.spyOn(console, "error").mockImplementation(() => {}); +jest.spyOn(console, "log").mockImplementation(() => {}); \ No newline at end of file diff --git a/mission_11/src/test/unit/product.test.ts b/mission_11/src/test/unit/product.test.ts new file mode 100644 index 000000000..55dff3aed --- /dev/null +++ b/mission_11/src/test/unit/product.test.ts @@ -0,0 +1,46 @@ +import { jest } from "@jest/globals"; + +const mockCreateProductFunction = jest.fn(); + +jest.unstable_mockModule("../../repository/productRepository.js", () => ({ + createProduct: mockCreateProductFunction, +})); + +const { createProduct: createProductService } = await import( + "../../services/productService.js" +); + +describe("Product Service Unit Test", () => { + describe("createProduct", () => { + const mockCreateProductRepo = mockCreateProductFunction; + + afterEach(() => { + mockCreateProductRepo.mockClear(); + }); + + it("should call repository and return the created product", async () => { + const mockProductData = { + userId: 1, + name: "Test Product", + description: "This is a test product.", + price: 10000, + tags: ["test"], + }; + + const mockCreatedProduct = { + id: 123, + ...mockProductData, + createdAt: new Date(), + updatedAt: new Date(), + }; + + mockCreateProductRepo.mockResolvedValue(mockCreatedProduct); + + const result = await createProductService(mockProductData); + + expect(mockCreateProductRepo).toHaveBeenCalledTimes(1); + expect(mockCreateProductRepo).toHaveBeenCalledWith(mockProductData); + expect(result).toEqual(mockCreatedProduct); + }); + }); +}); \ No newline at end of file diff --git a/mission_11/src/test/util/getAuthToken.ts b/mission_11/src/test/util/getAuthToken.ts new file mode 100644 index 000000000..ac05de4e2 --- /dev/null +++ b/mission_11/src/test/util/getAuthToken.ts @@ -0,0 +1,16 @@ +import request from "supertest"; +import { httpServer as app } from "../../app.js"; + +export const getAuthToken = async (email: string, password: string) => { + const userData = { + /* email: "user1@example.com", + password: "password123", */ + email, + password, + }; + + const response = await request(app).post("/login").send(userData).expect(200); + + const { accessToken } = response.body; + return accessToken; +}; diff --git a/mission_11/src/types/article.ts b/mission_11/src/types/article.ts new file mode 100644 index 000000000..1398c1c95 --- /dev/null +++ b/mission_11/src/types/article.ts @@ -0,0 +1,54 @@ +export interface CreatePostDTO { + title: string; + content: string; + userId: number; +} + +export interface GetPostsDTO { + cursor?: number; + limit: number; + sort: "asc" | "desc"; + offset: number; + search?: string; +} + +export interface GetPostDTO { + id: number; +} + +export interface PatchPostDTO { + id: number; + title?: string; + content?: string; +} + +export interface DeletePostDTO { + id: number; +} + +export interface PostCommentDTO { + pid: number; + name: string; + content: string; + userId: number; +} + +export interface GetCommentsDTO { + pid: number; + cursor: number; + limit: number; +} + +export interface GetCommentDTO { + cid: number; +} + +export interface PatchCommentDTO { + cid: number; + name: string; + content: string; +} + +export interface DeleteCommentDTO { + cid: number; +} diff --git a/mission_11/src/types/auth.d.ts b/mission_11/src/types/auth.d.ts new file mode 100644 index 000000000..7353fbba8 --- /dev/null +++ b/mission_11/src/types/auth.d.ts @@ -0,0 +1,5 @@ +export interface JwtPayload { + userId: number; + iat?: number; + exp?: number; +} diff --git a/mission_11/src/types/express/index.d.ts b/mission_11/src/types/express/index.d.ts new file mode 100644 index 000000000..25cbc8d62 --- /dev/null +++ b/mission_11/src/types/express/index.d.ts @@ -0,0 +1,10 @@ +import "express"; +import type { JwtPayload } from "../auth.d.js"; + +declare module "express-serve-static-core" { + interface Request { + // user?: import("../types/auth").JwtPayload; + user?: JwtPayload; + auth?: JwtPayload; + } +} diff --git a/mission_11/src/types/global.ts b/mission_11/src/types/global.ts new file mode 100644 index 000000000..452228e41 --- /dev/null +++ b/mission_11/src/types/global.ts @@ -0,0 +1,5 @@ +declare global { + interface Error { + statusCode?: number; + } +} \ No newline at end of file diff --git a/mission_11/src/types/product.ts b/mission_11/src/types/product.ts new file mode 100644 index 000000000..52d1aa2f2 --- /dev/null +++ b/mission_11/src/types/product.ts @@ -0,0 +1,63 @@ +export interface CreateProductDTO { + userId: number; + name: string; + description: string; + price: number; + tags: string[]; +} + +export interface GetProductsDTO { + offset: number; + limit: number; + sort: "asc" | "desc"; + search: string; +} + +export interface GetProductDTO { + id: number; +} + +export interface PatchProductDTO { + id: number; + name?: string; + description?: string; + price?: number; + tags?: string[]; +} + +export interface DeleteProductDTO { + id: number; +} + +export interface PostCommentDTO { + pid: number; + userId: number; + content: string; + name: string; +} + +export interface GetCommentsDTO { + pid: number; + cursor: number | null; + limit: number; +} + +export interface GetCommentDTO { + cid: number; +} + +export interface PatchCommentDTO { + cid: number; + name: string; + content: string; +} + +export interface DeleteCommentDTO { + cid: number; +} + +export interface GetProductsByUserDTO { + userId: number; + offset?: number; + limit?: number; +} diff --git a/mission_11/src/types/user.ts b/mission_11/src/types/user.ts new file mode 100644 index 000000000..adf66d149 --- /dev/null +++ b/mission_11/src/types/user.ts @@ -0,0 +1,21 @@ +export interface CreateUserDTO { + email: string; + nickname: string; + password: string; +} + +export interface GetUserDTO { + email: string; + password: string; +} + +export interface UserInfoDTO { + password?: string; + email: string; + nickname: string; + image: string | null; + refreshToken?: string | null; + createdAt: Date; + updatedAt: Date; + id: number; +} diff --git a/mission_11/test-client.html b/mission_11/test-client.html new file mode 100644 index 000000000..a7bc85c49 --- /dev/null +++ b/mission_11/test-client.html @@ -0,0 +1,142 @@ + + + + + + Socket.IO Test Client + + + +

+ +
+

서버 로그

+
+

서버 로그가 여기에 표시됩니다...

+
+
+ + + + + \ No newline at end of file diff --git a/mission_11/tsconfig.json b/mission_11/tsconfig.json new file mode 100644 index 000000000..cd741fa49 --- /dev/null +++ b/mission_11/tsconfig.json @@ -0,0 +1,49 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "moduleResolution": "nodenext", + "target": "es2022", + // "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, + + "esModuleInterop": true + }, + "include": ["src", "env.d.ts"], + "exclude": ["**/*.test.ts"] +} From 55c12a9c9cf86d3b863e5d0f5e3345d5c074ad7b Mon Sep 17 00:00:00 2001 From: intwocave Date: Tue, 2 Dec 2025 13:47:56 +0900 Subject: [PATCH 127/130] feat: add github actions --- .github/workflows/github-actions-demo.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/github-actions-demo.yml diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml new file mode 100644 index 000000000..b00f8e942 --- /dev/null +++ b/.github/workflows/github-actions-demo.yml @@ -0,0 +1,18 @@ +name: GitHub Actions Demo +run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 +on: [push] +jobs: + Explore-GitHub-Actions: + runs-on: ubuntu-latest + steps: + - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." + - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" + - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + - name: Check out repository code + uses: actions/checkout@v5 + - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." + - run: echo "🖥️ The workflow is now ready to test your code on the runner." + - name: List files in the repository + run: | + ls ${{ github.workspace }} + - run: echo "🍏 This job's status is ${{ job.status }}." From 51cf85379bec36804703cbccc797df65d56aa34b Mon Sep 17 00:00:00 2001 From: intwocave Date: Fri, 16 Jan 2026 17:42:31 +0900 Subject: [PATCH 128/130] feat: ci/cd --- .github/workflows/github-actions-demo.yml | 18 -------- .github/workflows/github-actions.yml | 53 +++++++++++++++++++++++ mission_11/Dockerfile | 32 ++++++++++++++ mission_11/docker-compose.yaml | 33 ++++++++++++++ 4 files changed, 118 insertions(+), 18 deletions(-) delete mode 100644 .github/workflows/github-actions-demo.yml create mode 100644 .github/workflows/github-actions.yml create mode 100644 mission_11/Dockerfile create mode 100644 mission_11/docker-compose.yaml diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml deleted file mode 100644 index b00f8e942..000000000 --- a/.github/workflows/github-actions-demo.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: GitHub Actions Demo -run-name: ${{ github.actor }} is testing out GitHub Actions 🚀 -on: [push] -jobs: - Explore-GitHub-Actions: - runs-on: ubuntu-latest - steps: - - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." - - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" - - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." - - name: Check out repository code - uses: actions/checkout@v5 - - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." - - run: echo "🖥️ The workflow is now ready to test your code on the runner." - - name: List files in the repository - run: | - ls ${{ github.workspace }} - - run: echo "🍏 This job's status is ${{ job.status }}." diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml new file mode 100644 index 000000000..c77a1865a --- /dev/null +++ b/.github/workflows/github-actions.yml @@ -0,0 +1,53 @@ +name: CI/CD Pipeline for Mission 11 + +on: + pull_request: + branches: + - '**' + push: + branches: + - main + +jobs: + test: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + + defaults: + run: + working-directory: ./mission_11 + + steps: + - name: Check out repository code + uses: actions/checkout@v5 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test + + deploy: + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: test + runs-on: ubuntu-latest + + steps: + - name: Check out repository code + uses: actions/checkout@v5 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ap-northeast-2 + + - name: Deploy to AWS + run: | + echo "Deploying to AWS..." diff --git a/mission_11/Dockerfile b/mission_11/Dockerfile new file mode 100644 index 000000000..aad375462 --- /dev/null +++ b/mission_11/Dockerfile @@ -0,0 +1,32 @@ +FROM node:20-slim AS builder +WORKDIR /usr/src/app + +COPY package.json package-lock.json ./ +COPY . . + +RUN npm install + +RUN npx prisma generate + +RUN npm run build + +# ---------------------------------------- + +FROM node:20-slim +WORKDIR /usr/src/app + +ENV NODE_ENV=production + +COPY package.json package-lock.json ./ + +RUN npm install --omit=dev + +COPY --from=builder /usr/src/app/dist ./dist +COPY --from=builder /usr/src/app/prisma ./prisma +COPY --from=builder /usr/src/app/node_modules/.prisma ./node_modules/.prisma + +EXPOSE 3000 + +VOLUME /usr/src/app/uploads + +CMD ["node", "dist/main.js"] diff --git a/mission_11/docker-compose.yaml b/mission_11/docker-compose.yaml new file mode 100644 index 000000000..75010fb38 --- /dev/null +++ b/mission_11/docker-compose.yaml @@ -0,0 +1,33 @@ +services: + backend: + build: . + restart: unless-stopped + ports: + - "3000:3000" + volumes: + - ./uploads:/usr/src/app/uploads + env_file: + - ./.env + environment: + - NODE_ENV=production + - DATABASE_URL=${DATABASE_URL} + - JWT_SECRET=your-super-secret-key-for-docker + - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} + - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} + - AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME} + - AWS_REGION=${AWS_REGION} + depends_on: + - db + + db: + image: postgres:15 + restart: always + environment: + - POSTGRES_USER=${POSTGRES_USER} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - POSTGRES_DB=${POSTGRES_DB} + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: From 49bb5d019ccd7e8b007ff56e2c4052fab15fcc11 Mon Sep 17 00:00:00 2001 From: intwocave Date: Wed, 21 Jan 2026 10:47:40 +0900 Subject: [PATCH 129/130] feat: ok sort --- mission_12/algorithm/sorts.js | 141 ++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 mission_12/algorithm/sorts.js diff --git a/mission_12/algorithm/sorts.js b/mission_12/algorithm/sorts.js new file mode 100644 index 000000000..dae5d8f23 --- /dev/null +++ b/mission_12/algorithm/sorts.js @@ -0,0 +1,141 @@ +/* + 선택 정렬 (Selection sort) + 숫자형 배열을 파라미터로 받고, 해당 배열을 수정하도록 구현합니다. + + 삽입 정렬 (Insertion sort) + 숫자형 배열을 파라미터로 받고, 해당 배열을 수정하도록 구현합니다. + + 병합 정렬 (Merge sort) + 숫자형 배열을 파라미터로 받고, 정렬된 새로운 배열을 리턴하도록 구현합니다. + + 퀵 정렬 (Quick sort) + 숫자형 배열을 파라미터로 받고, 해당 배열을 수정하도록 구현합니다. +*/ + +// 선택 정렬 (Selection sort) +function selectionSort(arr) { + for (let i = 0; i < arr.length; i++) { + let minIdx = i; + for (let j = i; j < arr.length; j++) { + if (arr[minIdx] > arr[j]) minIdx = j; + } + + const tmp = arr[i]; + arr[i] = arr[minIdx]; + arr[minIdx] = tmp; + } +} + +// 삽입 정렬 (Insertion sort) +function insertionSort(arr) { + for (let i = 1; i < arr.length; i++) { + const current = arr[i]; + let j = i - 1; + + while (j >= 0 && arr[j] > current) { + arr[j + 1] = arr[j]; + j--; + } + arr[j + 1] = current; + } +} + +// 병합 정렬 (Merge sort) +function mergeSort(arr) { + function _mergeSort(arr, left, right) { + if (left == right) { + const newArr = []; + newArr.push(arr[left]); + + return newArr; + } + + const mid = Math.ceil((left + right) / 2 - 1); + + const l = _mergeSort(arr, left, mid); + const r = _mergeSort(arr, mid + 1, right); + + const mergedArr = []; + let i = 0, + j = 0; + + while (i < l.length || j < r.length) { + if (l[i] <= r[j]) { + if (i >= l.length) { + mergedArr.push(r[j]); + j++; + continue; + } + mergedArr.push(l[i]); + i++; + } else { + if (j >= r.length) { + mergedArr.push(l[i]); + i++; + continue; + } + mergedArr.push(r[j]); + j++; + } + } + + return mergedArr; + } + + return _mergeSort(arr, 0, arr.length - 1); +} + +// 퀵 정렬 (Quick sort) +function quickSort(arr, left, right) { + if (left >= right) return; + + const pivot = arr[left]; + let low = left + 1, + high = right; + + while (low <= high) { + if (arr[low] <= pivot) { + low++; + continue; + } + + if (pivot < arr[high]) { + high--; + continue; + } + + const tmp = arr[low]; + arr[low] = arr[high]; + arr[high] = tmp; + } + + arr[left] = arr[high]; + arr[high] = pivot; + + quickSort(arr, left, high - 1); + quickSort(arr, high + 1, right); +} + +let nums = [4, 5, 3, 1, 2]; + +console.log("--- Original array of numbers ---"); +console.log(nums); + +console.log("--- Selection Sort ---"); +nums = [4, 5, 3, 1, 2]; +selectionSort(nums); +console.log(nums); + +console.log("--- Insertion Sort ---"); +nums = [4, 5, 3, 1, 2]; +insertionSort(nums); +console.log(nums); + +console.log("--- Merge Sort ---"); +nums = [4, 5, 3, 1, 2]; +console.log(mergeSort(nums)); + +console.log("--- Quick Sort ---"); +nums = [4, 5, 3, 1, 2]; +quickSort(nums, 0, nums.length - 1); +console.log(nums); From 31fb5a4f222781441b23fe49b21f425a91886ff1 Mon Sep 17 00:00:00 2001 From: intwocave Date: Sun, 25 Jan 2026 15:34:47 +0900 Subject: [PATCH 130/130] feat: ok sort --- mission_13/algorithm/BinarySearchTree.js | 110 +++++++++++++++++++++++ mission_13/algorithm/DoublyLinkedList.js | 84 +++++++++++++++++ mission_13/algorithm/LinkedList.js | 65 ++++++++++++++ mission_13/algorithm/Queue.js | 25 ++++++ mission_13/algorithm/Stack.js | 27 ++++++ mission_13/algorithm/sorts.js | 54 +++++++++++ 6 files changed, 365 insertions(+) create mode 100644 mission_13/algorithm/BinarySearchTree.js create mode 100644 mission_13/algorithm/DoublyLinkedList.js create mode 100644 mission_13/algorithm/LinkedList.js create mode 100644 mission_13/algorithm/Queue.js create mode 100644 mission_13/algorithm/Stack.js create mode 100644 mission_13/algorithm/sorts.js diff --git a/mission_13/algorithm/BinarySearchTree.js b/mission_13/algorithm/BinarySearchTree.js new file mode 100644 index 000000000..c5330849d --- /dev/null +++ b/mission_13/algorithm/BinarySearchTree.js @@ -0,0 +1,110 @@ +class BinarySearchTree { + constructor() { + this.root = null; + } + + insert(value) { + // 트리에 값 추가 + const node = new Node(value); + + if (this.root == null) { + this.root = node; + } else { + let current = this.root; + while (true) { + if (value === current.value) return false; + if (value < current.value) { + if (current.left == null) { + current.left = node; + return true; + } + current = current.left; + } else { + if (current.right == null) { + current.right = node; + return true; + } + current = current.right; + } + } + } + } + + find(value) { + // 주어진 값을 찾고 해당 노드를 리턴 + if (this.root == null) return undefined; + + let current = this.root; + + while(current) { + if (value == current.value) return current; + if (value < current.value) { + current = current.left; + } else { + current = current.right; + } + } + + return undefined; + } + + remove(value) { + // 트리에서 해당 값을 삭제 + this.root = this._removeNode(this.root, value); + } + + _removeNode(node, value) { + if (node === null) { + return null; + } + + if (value < node.value) { + node.left = this._removeNode(node.left, value); + return node; + } else if (value > node.value) { + node.right = this._removeNode(node.right, value); + return node; + } else { + // 삭제할 노드를 찾은 경우 + + // 1. 자식이 없는 경우 (리프 노드) + if (node.left === null && node.right === null) { + node = null; + return node; + } + + // 2. 자식이 하나인 경우 + if (node.left === null) { + node = node.right; + return node; + } else if (node.right === null) { + node = node.left; + return node; + } + + // 3. 자식이 둘인 경우 + // 오른쪽 서브트리에서 가장 작은 값을 찾음 (In-order successor) + const aux = this._findMinNode(node.right); + node.value = aux.value; + // 오른쪽 서브트리에서 최소값을 가진 노드를 삭제 + node.right = this._removeNode(node.right, aux.value); + return node; + } + } + + _findMinNode(node) { + if (node.left === null) { + return node; + } else { + return this._findMinNode(node.left); + } + } +} + +class Node { + constructor(value) { + this.value = value; + this.left = null; + this.right = null; + } +} diff --git a/mission_13/algorithm/DoublyLinkedList.js b/mission_13/algorithm/DoublyLinkedList.js new file mode 100644 index 000000000..76c762663 --- /dev/null +++ b/mission_13/algorithm/DoublyLinkedList.js @@ -0,0 +1,84 @@ +class DoublyLinkedList { + constructor() { + this.head = null; + this.tail = null; + this.size = 0; + } + + addToHead(value) { + // 리스트의 앞쪽에 노드 추가 + const node = new Node(value); + + if (this.size == 0) { + this.head = this.tail = node; + } else { + node.next = this.head; + this.head.prev = node; + this.head = node; + } + + this.size++; + } + + addToTail(value) { + // 리스트의 뒤쪽에 노드 추가 + const node = new Node(value); + + if (this.size == 0) { + this.tail = this.head = node; + } else { + node.prev = this.tail; + this.tail.next = node; + this.tail = node; + } + + this.size++; + } + + insertAfter(targetValue, newValue) { + // 특정 값을 가진 노드 뒤에 새 노드 추가 + const node = new Node(newValue); + + for (let n = this.head; n !== null; n = n.next) { + if (n.value == targetValue) { + node.next = n.next; + n.next = node; + node.prev = n; + this.size++; + break; + } + } + } + + findNode(value) { + // 값을 가진 노드를 찾아 반환합니다. + if (this.size == 0) return null; + + for (let n = this.head; n !== null; n = n.next) + if (n.value == value) return n; + + return null; + } + + removeNode(value) { + // 특정 값을 가진 노드 삭제 + for (let n = this.head; n !== null; n = n.next) { + if (n.value == value) { + // const [prevNode, nextNode] = [n.prev, n.next]; + const { prev: prevNode, next: nextNode } = n; + prevNode.next = nextNode; + nextNode.prev = prevNode; + this.size--; + break; + } + } + } +} + +class Node { + constructor(value) { + this.value = value; + this.prev = null; + this.next = null; + } +} diff --git a/mission_13/algorithm/LinkedList.js b/mission_13/algorithm/LinkedList.js new file mode 100644 index 000000000..084dd6435 --- /dev/null +++ b/mission_13/algorithm/LinkedList.js @@ -0,0 +1,65 @@ +class LinkedList { + constructor() { + this.head = null; + this.size = 0; + } + + addNode(value) { + // 리스트의 끝에 새 노드를 추가 + const node = new Node(value); + + if (this.size == 0) { + this.head = node; + this.size++; + } else { + let n = this.head; + for (; n.next !== null; n = n.next); + n.next = node; + this.size++; + } + } + + findNode(value) { + // 주어진 값을 가지는 노드를 찾아 리턴 + if (this.size == 0) return null; + + for (let n = this.head; n !== null; n = n.next) { + if (n.value == value) return n; + } + + return null; + } + + insertAfter(targetValue, newValue) { + // 특정 값을 가진 노드 뒤에 새 노드 추가 + const node = new Node(newValue); + + for (let n = this.head; n !== null; n = n.next) { + if (n.value == targetValue) { + node.next = n.next; + n.next = node; + this.size++; + break; + } + } + } + + removeAfter(targetValue) { + // 특정 값을 가진 노드 뒤의 노드를 삭제 + for (let n = this.head; n !== null; n = n.next) { + if (n.value == targetValue) { + const next = n.next; + n.next = next.next; + this.size--; + break; + } + } + } +} + +class Node { + constructor(value) { + this.value = value; + this.next = null; + } +} diff --git a/mission_13/algorithm/Queue.js b/mission_13/algorithm/Queue.js new file mode 100644 index 000000000..787cf1d18 --- /dev/null +++ b/mission_13/algorithm/Queue.js @@ -0,0 +1,25 @@ +class Queue { + constructor() { + this.items = []; + } + + enqueue(value) { + // 큐의 맨 뒤에 값을 추가 + this.items.push(value); + } + + dequeue() { + // 큐의 앞에서 값을 제거하고 그 값을 리턴 + return this.items.shift(); + } + + peek() { + // 큐의 앞에 있는 값을 제거하지 않고 리턴 + return this.items[0]; + } + + isEmpty() { + // 큐가 비어 있는지 불린형으로 리턴 + return this.items.length === 0; + } +} \ No newline at end of file diff --git a/mission_13/algorithm/Stack.js b/mission_13/algorithm/Stack.js new file mode 100644 index 000000000..979ace3bd --- /dev/null +++ b/mission_13/algorithm/Stack.js @@ -0,0 +1,27 @@ +class Stack { + constructor() { + this.items = []; + } + + push(value) { + // 스택의 맨 위에 값을 추가 + this.items.push(value); + } + + pop() { + // 스택의 맨 위 값을 제거하고 그 값을 리턴 + return this.items.pop(); + } + + peek() { + // 큐의 앞에 있는 값을 제거하지 않고 리턴 + if (this.items.length === 0) return null; + + return this.items[this.items.length - 1]; + } + + isEmpty() { + // 큐가 비어 있는지 불린형으로 리턴 + return this.items.length === 0; + } +} \ No newline at end of file diff --git a/mission_13/algorithm/sorts.js b/mission_13/algorithm/sorts.js new file mode 100644 index 000000000..de9988227 --- /dev/null +++ b/mission_13/algorithm/sorts.js @@ -0,0 +1,54 @@ +/* +힙 정렬 (Heap sort) + 숫자형 배열을 파라미터로 받고, 해당 배열을 수정하도록 구현합니다. +*/ + +function heapify(arr, n, i) { + let largest = i; + const left = i * 2 + 1; + const right = i * 2 + 2; + + if (left < n && arr[left] > arr[largest]) { + largest = left; + } + + if (right < n && arr[right] > arr[largest]) { + largest = right; + } + + if (largest !== i) { + [arr[largest], arr[i]] = [arr[i], arr[largest]]; + heapify(arr, n, largest); + } +} + +function heapSort(arr) { + // build a max-heap + for (let i = Math.floor(arr.length / 2) - 1; i >= 0; i--) { + heapify(arr, arr.length, i); + } + + // do sort + for (let i = arr.length - 1; i > 0; i--) { + // swap root node and last node + [arr[0], arr[i]] = [arr[i], arr[0]]; + + heapify(arr, i, 0); + } +} + +let nums = [4, 5, 3, 6, 1, 2]; +/* + 4 + / \ + 5 3 + / \ / + 6 1 2 + */ + +console.log("--- Original array of numbers ---"); +console.log(nums); + +console.log("--- Heap Sort ---"); +heapSort(nums); +console.log(nums); \ No newline at end of file