From 19f47ba6b83a16f106b8cc0ac83b181b4000d2e1 Mon Sep 17 00:00:00 2001 From: Hunter Date: Fri, 26 Apr 2024 04:03:02 +1200 Subject: [PATCH] add config for prettier; fix file formatting for both backend and frontend --- .prettierrc | 6 + backend/.prettierignore | 3 - backend/.prettierrc | 1 - backend/README.md | 26 +- backend/package-lock.json | 3686 ++--- backend/package.json | 60 +- backend/src/controllers/news.controller.ts | 184 +- .../src/controllers/research.controller.ts | 192 +- backend/src/errors/HTTPErrors.ts | 42 +- backend/src/index.ts | 36 +- backend/src/repositories/IRepository.ts | 73 +- .../repositories/memory/MemoryRepository.ts | 437 +- .../src/repositories/memory/data/news.json | 550 +- .../repositories/memory/data/researches.json | 528 +- .../src/repositories/memory/data/users.json | 56 +- .../src/repositories/memory/sorters/Sorter.ts | 7 +- .../memory/sorters/article.sorter.ts | 2 +- .../memory/sorters/user.sorter.ts | 2 +- .../src/repositories/mongo/MongoRepository.ts | 434 +- backend/src/repositories/repository.ts | 66 +- backend/src/routes/news.router.ts | 26 +- backend/src/routes/research.router.ts | 29 +- backend/src/util/const.ts | 16 +- backend/src/util/functions.ts | 12 +- backend/src/util/types/input.types.ts | 131 +- backend/src/util/types/util.types.ts | 16 +- backend/tsconfig.json | 200 +- backend/vercel.json | 26 +- frontend/.eslintrc.json | 2 +- frontend/.prettierignore | 18 + frontend/README.md | 11 +- frontend/app/(cms)/layout.tsx | 4 +- frontend/app/(cms)/news/[id]/edit/layout.tsx | 14 +- frontend/app/(cms)/news/[id]/edit/page.tsx | 10 +- .../app/(cms)/news/publish/example/page.tsx | 19 +- frontend/app/(cms)/news/publish/layout.tsx | 14 +- frontend/app/(cms)/news/publish/page.tsx | 12 +- .../app/(cms)/research/[id]/edit/layout.tsx | 14 +- .../app/(cms)/research/[id]/edit/page.tsx | 14 +- .../app/(cms)/research/publish/layout.tsx | 14 +- frontend/app/(cms)/research/publish/page.tsx | 6 +- frontend/app/(content)/about/page.tsx | 2 +- frontend/app/(content)/layout.tsx | 10 +- frontend/app/(content)/news/[id]/page.tsx | 12 +- frontend/app/(content)/news/page.tsx | 29 +- frontend/app/(content)/research/[id]/page.tsx | 12 +- frontend/app/(content)/research/page.tsx | 27 +- frontend/app/(homepage)/layout.tsx | 10 +- frontend/app/(homepage)/page.tsx | 16 +- frontend/app/components/ArticleCard.tsx | 24 +- frontend/app/components/ArticleForm.tsx | 56 +- frontend/app/components/ArticleFromCMS.tsx | 14 +- frontend/app/components/ButtonLink.tsx | 16 +- frontend/app/components/ContentEditor.tsx | 150 +- frontend/app/components/Footer.tsx | 23 +- frontend/app/components/Nav.tsx | 10 +- frontend/app/consts.ts | 4 +- frontend/app/globals.css | 23 +- frontend/app/layout.tsx | 34 +- frontend/app/util.ts | 10 +- frontend/next.config.mjs | 4 +- frontend/package-lock.json | 12378 ++++++++-------- frontend/package.json | 75 +- frontend/postcss.config.js | 10 +- frontend/tailwind.config.ts | 65 +- frontend/tsconfig.json | 48 +- 66 files changed, 10044 insertions(+), 10017 deletions(-) create mode 100644 .prettierrc delete mode 100644 backend/.prettierrc create mode 100644 frontend/.prettierignore diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..a21e8630 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +trailingComma: "es5" +tabWidth: 4 +semi: false +singleQuote: false +printWidth: 120 +bracketSameLine: true diff --git a/backend/.prettierignore b/backend/.prettierignore index 960cfc39..0ea0c2d8 100644 --- a/backend/.prettierignore +++ b/backend/.prettierignore @@ -13,7 +13,4 @@ .DS_Store *.pem -# typescript -*.tsbuildinfo -next-env.d.ts .vercel diff --git a/backend/.prettierrc b/backend/.prettierrc deleted file mode 100644 index 0967ef42..00000000 --- a/backend/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/backend/README.md b/backend/README.md index 79b9927d..26ec65cc 100644 --- a/backend/README.md +++ b/backend/README.md @@ -5,12 +5,14 @@ ![AWS](https://img.shields.io/badge/AWS-%23FF9900.svg?style=for-the-badge&logo=amazon-aws&logoColor=white) ![MongoDB](https://img.shields.io/badge/MongoDB-%234ea94b.svg?style=for-the-badge&logo=mongodb&logoColor=white) -Our backend app will be implemented using Express.js, with the NoSQL database being hosted on MongoDB, and authentication / +Our backend app will be implemented using Express.js, with the NoSQL database being hosted on MongoDB, and +authentication / CDN services being delegated to Amazon Web Services (AWS). # Starting the Local Server Change directory to the backend (only if you are currently in the root directory): + ```bash cd backend ``` @@ -18,6 +20,7 @@ cd backend ## Install Dependencies Install dependencies using `npm`: + ```bash npm i ``` @@ -32,7 +35,6 @@ The default port is configured to `3000`. The environment is `LOCAL` by default, Ping the Express API through [http://localhost:3000](http://localhost:3000). You should see the following response: - ```json { "message": "ok" @@ -42,17 +44,25 @@ Ping the Express API through [http://localhost:3000](http://localhost:3000). You # Deployment Rules -- Any changes pushed to github on **any** branch will be deployed to Vercel Development Preview. This is not public. -- Any changes pushed on the `dev` branch will be deployed to the **development** environment ([https://dev-api.aapc-nz.org](https://dev-api.aapc-nz.org)). -- Any changes pushed on the `main` branch will be deployed to the **production** environment ([https://api.aapc-nz.org](https://api.aapc-nz.org)). +- Any changes pushed to github on **any** branch will be deployed to Vercel Development Preview. This is not public. +- Any changes pushed on the `dev` branch will be deployed to the **development** + environment ([https://dev-api.aapc-nz.org](https://dev-api.aapc-nz.org)). +- Any changes pushed on the `main` branch will be deployed to the **production** + environment ([https://api.aapc-nz.org](https://api.aapc-nz.org)). # Environments ### `LOCAL` -When running the backend locally, the `ENV` will be `LOCAL` and use the `MemoryRepository` with data from the local JSON files. + +When running the backend locally, the `ENV` will be `LOCAL` and use the `MemoryRepository` with data from the local JSON +files. ### `DEV` -On [https://dev-api.aapc-nz.org](https://dev-api.aapc-nz.org) (the **development** environment), the `ENV` will be `DEV` and use the `MongoRepository` with data from the **Development** MongoDB Atlas cluster. + +On [https://dev-api.aapc-nz.org](https://dev-api.aapc-nz.org) (the **development** environment), the `ENV` will be `DEV` +and use the `MongoRepository` with data from the **Development** MongoDB Atlas cluster. ### `PROD` -On [https://api.aapc-nz.org](https://api.aapc-nz.org) (the **production** environment), the `ENV` will be `PROD` and use the `MongoRepository` with data from the **Production** MongoDB Atlas cluster. + +On [https://api.aapc-nz.org](https://api.aapc-nz.org) (the **production** environment), the `ENV` will be `PROD` and use +the `MongoRepository` with data from the **Production** MongoDB Atlas cluster. diff --git a/backend/package-lock.json b/backend/package-lock.json index eb1f6bd9..27a39b1e 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,1847 +1,1847 @@ { - "name": "aapc-backend", - "version": "0.1.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "aapc-backend", - "version": "0.1.1", - "dependencies": { - "@aapc/types": "^0.2.3", - "cors": "^2.8.5", - "dotenv": "^16.4.5", - "express": "^4.19.2", - "express-async-handler": "^1.2.0", - "mongodb": "^6.5.0" - }, - "devDependencies": { - "@types/express": "^4.17.21", - "@types/node": "^20.12.2", - "nodemon": "^3.1.0", - "prettier": "3.2.5", - "tsx": "^4.7.1", - "typescript": "^5.4.3" - } - }, - "node_modules/@aapc/types": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@aapc/types/-/types-0.2.3.tgz", - "integrity": "sha512-r4yjrN1/wOyusAYyhwK2+4RxX61FmNNPpiwd2ggwpiCBYf7vd4x0CZW8say9/uMvR2PQS1tjxNrpB9o2VgLITA==" - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", - "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", - "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", - "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", - "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", - "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", - "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", - "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", - "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", - "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", - "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", - "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", - "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", - "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", - "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", - "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", - "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", - "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", - "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", - "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", - "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", - "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", - "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", - "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@mongodb-js/saslprep": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.5.tgz", - "integrity": "sha512-XLNOMH66KhJzUJNwT/qlMnS4WsNDWD5ASdyaSH3EtK+F4r/CFGa3jT4GNi4mfOitGvWXtdLgQJkQjxSVrio+jA==", - "dependencies": { - "sparse-bitfield": "^3.0.3" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "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, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.43", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", - "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "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 - }, - "node_modules/@types/node": { - "version": "20.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.2.tgz", - "integrity": "sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/qs": { - "version": "6.9.14", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", - "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", - "dev": true - }, - "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 - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", - "dev": true, - "dependencies": { - "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" - } - }, - "node_modules/@types/webidl-conversions": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" - }, - "node_modules/@types/whatwg-url": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.4.tgz", - "integrity": "sha512-lXCmTWSHJvf0TRSO58nm978b8HJ/EdsSsEKLd3ODHFjo+3VGAyyTp4v50nWvwtzBxSMQrVOK7tcuN0zGPLICMw==", - "dependencies": { - "@types/webidl-conversions": "*" - } - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/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==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/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, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bson": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.5.0.tgz", - "integrity": "sha512-DXf1BTAS8vKyR90BO4x5v3rKVarmkdkzwOrnYDFdjAY694ILNDkmA3uRh1xXJEl+C1DAh8XCvAQ+Gh3kzubtpg==", - "engines": { - "node": ">=16.20.1" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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, - "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/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "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==", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "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/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "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==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", - "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.12", - "@esbuild/android-arm": "0.19.12", - "@esbuild/android-arm64": "0.19.12", - "@esbuild/android-x64": "0.19.12", - "@esbuild/darwin-arm64": "0.19.12", - "@esbuild/darwin-x64": "0.19.12", - "@esbuild/freebsd-arm64": "0.19.12", - "@esbuild/freebsd-x64": "0.19.12", - "@esbuild/linux-arm": "0.19.12", - "@esbuild/linux-arm64": "0.19.12", - "@esbuild/linux-ia32": "0.19.12", - "@esbuild/linux-loong64": "0.19.12", - "@esbuild/linux-mips64el": "0.19.12", - "@esbuild/linux-ppc64": "0.19.12", - "@esbuild/linux-riscv64": "0.19.12", - "@esbuild/linux-s390x": "0.19.12", - "@esbuild/linux-x64": "0.19.12", - "@esbuild/netbsd-x64": "0.19.12", - "@esbuild/openbsd-x64": "0.19.12", - "@esbuild/sunos-x64": "0.19.12", - "@esbuild/win32-arm64": "0.19.12", - "@esbuild/win32-ia32": "0.19.12", - "@esbuild/win32-x64": "0.19.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==" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express-async-handler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/express-async-handler/-/express-async-handler-1.2.0.tgz", - "integrity": "sha512-rCSVtPXRmQSW8rmik/AIb2P0op6l7r1fMW538yyvTMltCO4xQEWMmobfrIxN2V1/mVrgxB8Az3reYF6yUZw37w==" - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", - "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", - "dev": true, - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "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 - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "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==", - "engines": { - "node": ">= 0.6" - } - }, - "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==", - "dependencies": { - "mime-db": "1.52.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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mongodb": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.5.0.tgz", - "integrity": "sha512-Fozq68InT+JKABGLqctgtb8P56pRrJFkbhW0ux+x1mdHeyinor8oNzJqwLjV/t5X5nJGfTlluxfyMnOXNggIUA==", - "dependencies": { - "@mongodb-js/saslprep": "^1.1.5", - "bson": "^6.4.0", - "mongodb-connection-string-url": "^3.0.0" - }, - "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.2.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/mongodb-connection-string-url": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.0.tgz", - "integrity": "sha512-t1Vf+m1I5hC2M5RJx/7AtxgABy1cZmIPQRMXw+gEIPn/cZNF3Oiy+l0UIypUwVB5trcWHq3crg2g3uAR9aAwsQ==", - "dependencies": { - "@types/whatwg-url": "^11.0.2", - "whatwg-url": "^13.0.0" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/nodemon": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", - "integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==", - "dev": true, - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^4", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/nodemon/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/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" + "name": "aapc-backend", + "version": "0.1.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "aapc-backend", + "version": "0.1.1", + "dependencies": { + "@aapc/types": "^0.2.3", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "express": "^4.19.2", + "express-async-handler": "^1.2.0", + "mongodb": "^6.5.0" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "@types/node": "^20.12.2", + "nodemon": "^3.1.0", + "prettier": "3.2.5", + "tsx": "^4.7.1", + "typescript": "^5.4.3" + } + }, + "node_modules/@aapc/types": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@aapc/types/-/types-0.2.3.tgz", + "integrity": "sha512-r4yjrN1/wOyusAYyhwK2+4RxX61FmNNPpiwd2ggwpiCBYf7vd4x0CZW8say9/uMvR2PQS1tjxNrpB9o2VgLITA==" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.5.tgz", + "integrity": "sha512-XLNOMH66KhJzUJNwT/qlMnS4WsNDWD5ASdyaSH3EtK+F4r/CFGa3jT4GNi4mfOitGvWXtdLgQJkQjxSVrio+jA==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "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, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.43", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", + "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "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 + }, + "node_modules/@types/node": { + "version": "20.12.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.2.tgz", + "integrity": "sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/qs": { + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", + "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", + "dev": true + }, + "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 + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.4.tgz", + "integrity": "sha512-lXCmTWSHJvf0TRSO58nm978b8HJ/EdsSsEKLd3ODHFjo+3VGAyyTp4v50nWvwtzBxSMQrVOK7tcuN0zGPLICMw==", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/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==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bson": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.5.0.tgz", + "integrity": "sha512-DXf1BTAS8vKyR90BO4x5v3rKVarmkdkzwOrnYDFdjAY694ILNDkmA3uRh1xXJEl+C1DAh8XCvAQ+Gh3kzubtpg==", + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "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/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "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==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "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/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "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==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.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==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-async-handler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/express-async-handler/-/express-async-handler-1.2.0.tgz", + "integrity": "sha512-rCSVtPXRmQSW8rmik/AIb2P0op6l7r1fMW538yyvTMltCO4xQEWMmobfrIxN2V1/mVrgxB8Az3reYF6yUZw37w==" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "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 + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "dependencies": { + "mime-db": "1.52.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, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mongodb": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.5.0.tgz", + "integrity": "sha512-Fozq68InT+JKABGLqctgtb8P56pRrJFkbhW0ux+x1mdHeyinor8oNzJqwLjV/t5X5nJGfTlluxfyMnOXNggIUA==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.4.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.0.tgz", + "integrity": "sha512-t1Vf+m1I5hC2M5RJx/7AtxgABy1cZmIPQRMXw+gEIPn/cZNF3Oiy+l0UIypUwVB5trcWHq3crg2g3uAR9aAwsQ==", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nodemon": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", + "integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/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==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.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, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/tsx": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.1.tgz", + "integrity": "sha512-8d6VuibXHtlN5E3zFkgY8u4DX7Y3Z27zvvPKVmLon/D4AjuKzarkUBTLDBgj9iTQ0hg5xM7c/mYiRVM+HETf0g==", + "dev": true, + "dependencies": { + "esbuild": "~0.19.10", + "get-tsconfig": "^4.7.2" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "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==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "engines": { + "node": ">= 0.4.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==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/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==" - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.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, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "dependencies": { - "memory-pager": "^1.0.2" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dependencies": { - "punycode": "^2.3.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/tsx": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.1.tgz", - "integrity": "sha512-8d6VuibXHtlN5E3zFkgY8u4DX7Y3Z27zvvPKVmLon/D4AjuKzarkUBTLDBgj9iTQ0hg5xM7c/mYiRVM+HETf0g==", - "dev": true, - "dependencies": { - "esbuild": "~0.19.10", - "get-tsconfig": "^4.7.2" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "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==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", - "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, - "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==", - "engines": { - "node": ">= 0.4.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==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", - "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", - "dependencies": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true } - } } diff --git a/backend/package.json b/backend/package.json index bba588d8..af14ba3e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,31 +1,31 @@ { - "name": "aapc-backend", - "version": "0.1.1", - "private": true, - "description": "The backend of the AAPC website.", - "scripts": { - "dev": "nodemon -x tsx ./src/index.ts", - "build": "tsc --build", - "start": "node ./dist/index.js", - "deploy:development": "npm run build && vercel build && vercel deploy --prebuilt", - "deploy:production": "npm run build && vercel build --prod && vercel --prod deploy --prebuilt", - "prettier": "prettier ./**/*.{js,ts} --check", - "prettier:fix": "prettier ./**/*.{js,ts} --write" - }, - "dependencies": { - "@aapc/types": "^0.2.3", - "cors": "^2.8.5", - "dotenv": "^16.4.5", - "express": "^4.19.2", - "express-async-handler": "^1.2.0", - "mongodb": "^6.5.0" - }, - "devDependencies": { - "@types/express": "^4.17.21", - "@types/node": "^20.12.2", - "nodemon": "^3.1.0", - "prettier": "3.2.5", - "tsx": "^4.7.1", - "typescript": "^5.4.3" - } -} \ No newline at end of file + "name": "aapc-backend", + "version": "0.1.1", + "private": true, + "description": "The backend of the AAPC website.", + "scripts": { + "dev": "nodemon -x tsx ./src/index.ts", + "build": "tsc --build", + "start": "node ./dist/index.js", + "deploy:development": "npm run build && vercel build && vercel deploy --prebuilt", + "deploy:production": "npm run build && vercel build --prod && vercel --prod deploy --prebuilt", + "prettier": "npx prettier . --check", + "prettier:fix": "npx prettier . --write" + }, + "dependencies": { + "@aapc/types": "^0.2.3", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "express": "^4.19.2", + "express-async-handler": "^1.2.0", + "mongodb": "^6.5.0" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "@types/node": "^20.12.2", + "nodemon": "^3.1.0", + "prettier": "3.2.5", + "tsx": "^4.7.1", + "typescript": "^5.4.3" + } +} diff --git a/backend/src/controllers/news.controller.ts b/backend/src/controllers/news.controller.ts index c0ea4b0f..06a64474 100644 --- a/backend/src/controllers/news.controller.ts +++ b/backend/src/controllers/news.controller.ts @@ -1,110 +1,104 @@ -import { RequestHandler } from "express"; -import { DB } from "../repositories/repository"; -import { BadRequestError, NotFoundError } from "../errors/HTTPErrors"; -import { Article, ArticleType, Paginator } from "@aapc/types"; -import { DEFAULT_PER_PAGE, DUMMY_USER } from "../util/const"; -import { ArrayResult } from "../util/types/util.types"; -import { ArticleIn } from "../util/types/input.types"; +import { RequestHandler } from "express" +import { DB } from "../repositories/repository" +import { BadRequestError, NotFoundError } from "../errors/HTTPErrors" +import { Article, ArticleType, Paginator } from "@aapc/types" +import { DEFAULT_PER_PAGE, DUMMY_USER } from "../util/const" +import { ArrayResult } from "../util/types/util.types" +import { ArticleIn } from "../util/types/input.types" export default class NewsController { - static getNews: RequestHandler = async (req, res, next) => { - const url = new URL( - `${req.protocol}://${req.get("host")}${req.originalUrl}`, - ); + static getNews: RequestHandler = async (req, res, next) => { + const url = new URL(`${req.protocol}://${req.get("host")}${req.originalUrl}`) - // Get query parameter p from URL - const page: number = Number(req.query.p ?? 1); + // Get query parameter p from URL + const page: number = Number(req.query.p ?? 1) - // Get query parameter pp from URL - const perPage = Number(req.query.pp ?? DEFAULT_PER_PAGE); + // Get query parameter pp from URL + const perPage = Number(req.query.pp ?? DEFAULT_PER_PAGE) - const startFrom = (page - 1) * perPage; - const searchTitle = String(req.query.title ?? ""); - let r: ArrayResult
; - if (searchTitle === "") { - r = await DB.getAllNews({ startFrom: startFrom, maxResults: perPage }); - } else { - r = await DB.searchNewsByTitle(searchTitle, { - startFrom: startFrom, - maxResults: perPage, - }); + const startFrom = (page - 1) * perPage + const searchTitle = String(req.query.title ?? "") + let r: ArrayResult
+ if (searchTitle === "") { + r = await DB.getAllNews({ + startFrom: startFrom, + maxResults: perPage, + }) + } else { + r = await DB.searchNewsByTitle(searchTitle, { + startFrom: startFrom, + maxResults: perPage, + }) + } + const paginator = new Paginator(Article, { + resultsPerPage: perPage, + currentPage: page, + totalResults: r.totalResults, + data: r.results, + }) + if (page < paginator.lastPage) { + url.searchParams.set("p", String(page + 1)) + paginator.nextPageLocation = url.href + } + if (page > 1) { + url.searchParams.set("p", String(page - 1)) + paginator.prevPageLocation = url.href + } + res.json(paginator) + next() } - const paginator = new Paginator(Article, { - resultsPerPage: perPage, - currentPage: page, - totalResults: r.totalResults, - data: r.results, - }); - if (page < paginator.lastPage) { - url.searchParams.set("p", String(page + 1)); - paginator.nextPageLocation = url.href; - } - if (page > 1) { - url.searchParams.set("p", String(page - 1)); - paginator.prevPageLocation = url.href; - } - res.json(paginator); - next(); - }; - static getNewsById: RequestHandler = async (req, res, next) => { - if (!("id" in req.params)) throw new BadRequestError(); - const id: string = String(req.params.id); + static getNewsById: RequestHandler = async (req, res, next) => { + if (!("id" in req.params)) throw new BadRequestError() + const id: string = String(req.params.id) - const a = await DB.getNewsById(id); - if (a === null) - throw new NotFoundError( - `News article with id ${req.params.id} does not exist.`, - ); - res.json(a); - next(); - }; + const a = await DB.getNewsById(id) + if (a === null) throw new NotFoundError(`News article with id ${req.params.id} does not exist.`) + res.json(a) + next() + } - static createNews: RequestHandler = async (req, res, next) => { - // TODO: use auth headers to auto fill user - try { - const n = new ArticleIn(req.body).toArticle(ArticleType.news, DUMMY_USER); - await DB.createNews(n); - res.status(201).send(); - } catch (e: any) { - throw new BadRequestError(e.message); + static createNews: RequestHandler = async (req, res, next) => { + // TODO: use auth headers to auto fill user + try { + const n = new ArticleIn(req.body).toArticle(ArticleType.news, DUMMY_USER) + await DB.createNews(n) + res.status(201).send() + } catch (e: any) { + throw new BadRequestError(e.message) + } + next() } - next(); - }; - static editNews: RequestHandler = async (req, res, next) => { - if (!("id" in req.params)) throw new BadRequestError(); - const id: string = String(req.params.id); - const currentArticle = await DB.getNewsById(id); - if (currentArticle === null) - throw new NotFoundError(`News article with id ${id} does not exist.`); - try { - const n = new ArticleIn(req.body).toArticle( - currentArticle.articleType, - currentArticle.publisher, - ); - currentArticle.lastEditedAt = new Date().toISOString(); - currentArticle.title = n.title; - currentArticle.content = n.content; - currentArticle.subtitle = n.subtitle; - currentArticle.media = n.media; - await DB.editNews(id, currentArticle); - res.status(204).send(); - } catch (e: any) { - throw new BadRequestError(e.message); + static editNews: RequestHandler = async (req, res, next) => { + if (!("id" in req.params)) throw new BadRequestError() + const id: string = String(req.params.id) + const currentArticle = await DB.getNewsById(id) + if (currentArticle === null) throw new NotFoundError(`News article with id ${id} does not exist.`) + try { + const n = new ArticleIn(req.body).toArticle(currentArticle.articleType, currentArticle.publisher) + currentArticle.lastEditedAt = new Date().toISOString() + currentArticle.title = n.title + currentArticle.content = n.content + currentArticle.subtitle = n.subtitle + currentArticle.media = n.media + await DB.editNews(id, currentArticle) + res.status(204).send() + } catch (e: any) { + throw new BadRequestError(e.message) + } + next() } - next(); - }; - static deleteNews: RequestHandler = async (req, res, next) => { - if (!("id" in req.params)) throw new BadRequestError(); - const id: string = String(req.params.id); - try { - await DB.deleteNews(id); - } catch (e) { - throw new NotFoundError(`News article with id ${id} does not exist.`); + static deleteNews: RequestHandler = async (req, res, next) => { + if (!("id" in req.params)) throw new BadRequestError() + const id: string = String(req.params.id) + try { + await DB.deleteNews(id) + } catch (e) { + throw new NotFoundError(`News article with id ${id} does not exist.`) + } + res.status(204).send() + next() } - res.status(204).send(); - next(); - }; } diff --git a/backend/src/controllers/research.controller.ts b/backend/src/controllers/research.controller.ts index d1ebfaf7..31abd504 100644 --- a/backend/src/controllers/research.controller.ts +++ b/backend/src/controllers/research.controller.ts @@ -1,118 +1,104 @@ -import { RequestHandler } from "express"; -import { DB } from "../repositories/repository"; -import { BadRequestError, NotFoundError } from "../errors/HTTPErrors"; -import { DEFAULT_PER_PAGE, DUMMY_USER } from "../util/const"; -import { ArrayResult } from "../util/types/util.types"; -import { Article, ArticleType, Paginator } from "@aapc/types"; -import { ArticleIn } from "../util/types/input.types"; +import { RequestHandler } from "express" +import { DB } from "../repositories/repository" +import { BadRequestError, NotFoundError } from "../errors/HTTPErrors" +import { DEFAULT_PER_PAGE, DUMMY_USER } from "../util/const" +import { ArrayResult } from "../util/types/util.types" +import { Article, ArticleType, Paginator } from "@aapc/types" +import { ArticleIn } from "../util/types/input.types" export default class ResearchController { - static getResearch: RequestHandler = async (req, res, next) => { - const url = new URL( - `${req.protocol}://${req.get("host")}${req.originalUrl}`, - ); + static getResearch: RequestHandler = async (req, res, next) => { + const url = new URL(`${req.protocol}://${req.get("host")}${req.originalUrl}`) - // Get query parameter p from URL - const page: number = Number(req.query.p ?? 1); + // Get query parameter p from URL + const page: number = Number(req.query.p ?? 1) - // Get query parameter pp from URL - const perPage = Number(req.query.pp ?? DEFAULT_PER_PAGE); + // Get query parameter pp from URL + const perPage = Number(req.query.pp ?? DEFAULT_PER_PAGE) - const startFrom = (page - 1) * perPage; - const searchTitle = String(req.query.title ?? ""); - let r: ArrayResult
; - if (searchTitle === "") { - r = await DB.getAllResearch({ - startFrom: startFrom, - maxResults: perPage, - }); - } else { - r = await DB.searchResearchByTitle(searchTitle, { - startFrom: startFrom, - maxResults: perPage, - }); + const startFrom = (page - 1) * perPage + const searchTitle = String(req.query.title ?? "") + let r: ArrayResult
+ if (searchTitle === "") { + r = await DB.getAllResearch({ + startFrom: startFrom, + maxResults: perPage, + }) + } else { + r = await DB.searchResearchByTitle(searchTitle, { + startFrom: startFrom, + maxResults: perPage, + }) + } + const paginator = new Paginator(Article, { + resultsPerPage: perPage, + currentPage: page, + totalResults: r.totalResults, + data: r.results, + }) + if (page < paginator.lastPage) { + url.searchParams.set("p", String(page + 1)) + paginator.nextPageLocation = url.href + } + if (page > 1) { + url.searchParams.set("p", String(page - 1)) + paginator.prevPageLocation = url.href + } + res.json(paginator) + next() } - const paginator = new Paginator(Article, { - resultsPerPage: perPage, - currentPage: page, - totalResults: r.totalResults, - data: r.results, - }); - if (page < paginator.lastPage) { - url.searchParams.set("p", String(page + 1)); - paginator.nextPageLocation = url.href; - } - if (page > 1) { - url.searchParams.set("p", String(page - 1)); - paginator.prevPageLocation = url.href; - } - res.json(paginator); - next(); - }; - static getResearchById: RequestHandler = async (req, res, next) => { - if (!("id" in req.params)) throw new BadRequestError(); - const id: string = String(req.params.id); + static getResearchById: RequestHandler = async (req, res, next) => { + if (!("id" in req.params)) throw new BadRequestError() + const id: string = String(req.params.id) - const n = await DB.getResearchById(id); - if (n === null) - throw new NotFoundError( - `Research article with id ${req.params.id} does not exist.`, - ); - res.json(n); - next(); - }; + const n = await DB.getResearchById(id) + if (n === null) throw new NotFoundError(`Research article with id ${req.params.id} does not exist.`) + res.json(n) + next() + } - static createResearch: RequestHandler = async (req, res, next) => { - // TODO: use auth headers to auto fill user - try { - const r = new ArticleIn(req.body).toArticle( - ArticleType.research, - DUMMY_USER, - ); - await DB.createResearch(r); - res.json(r); - } catch (e: any) { - throw new BadRequestError(e.message); + static createResearch: RequestHandler = async (req, res, next) => { + // TODO: use auth headers to auto fill user + try { + const r = new ArticleIn(req.body).toArticle(ArticleType.research, DUMMY_USER) + await DB.createResearch(r) + res.json(r) + } catch (e: any) { + throw new BadRequestError(e.message) + } + next() } - next(); - }; - static editResearch: RequestHandler = async (req, res, next) => { - if (!("id" in req.params)) throw new BadRequestError(); - const id: string = String(req.params.id); - const currentArticle = await DB.getResearchById(id); - if (currentArticle === null) - throw new NotFoundError(`Research article with id ${id} does not exist.`); - try { - const r = new ArticleIn(req.body).toArticle( - currentArticle.articleType, - currentArticle.publisher, - ); - currentArticle.lastEditedAt = new Date().toISOString(); - currentArticle.title = r.title; - currentArticle.content = r.content; - currentArticle.subtitle = r.subtitle; - currentArticle.media = r.media; - await DB.editResearch(id, currentArticle); - res.json(currentArticle); - } catch (e: any) { - throw new BadRequestError(e.message); + static editResearch: RequestHandler = async (req, res, next) => { + if (!("id" in req.params)) throw new BadRequestError() + const id: string = String(req.params.id) + const currentArticle = await DB.getResearchById(id) + if (currentArticle === null) throw new NotFoundError(`Research article with id ${id} does not exist.`) + try { + const r = new ArticleIn(req.body).toArticle(currentArticle.articleType, currentArticle.publisher) + currentArticle.lastEditedAt = new Date().toISOString() + currentArticle.title = r.title + currentArticle.content = r.content + currentArticle.subtitle = r.subtitle + currentArticle.media = r.media + await DB.editResearch(id, currentArticle) + res.json(currentArticle) + } catch (e: any) { + throw new BadRequestError(e.message) + } + next() } - next(); - }; - static deleteResearch: RequestHandler = async (req, res, next) => { - if (!("id" in req.params)) throw new BadRequestError(); - const id: string = String(req.params.id); - try { - await DB.deleteResearch(id); - } catch (e) { - throw new NotFoundError( - `Research article with id ${req.params.id} does not exist.`, - ); + static deleteResearch: RequestHandler = async (req, res, next) => { + if (!("id" in req.params)) throw new BadRequestError() + const id: string = String(req.params.id) + try { + await DB.deleteResearch(id) + } catch (e) { + throw new NotFoundError(`Research article with id ${req.params.id} does not exist.`) + } + res.status(204).send() + next() } - res.status(204).send(); - next(); - }; } diff --git a/backend/src/errors/HTTPErrors.ts b/backend/src/errors/HTTPErrors.ts index a10ab86d..cf3a2f5f 100644 --- a/backend/src/errors/HTTPErrors.ts +++ b/backend/src/errors/HTTPErrors.ts @@ -1,33 +1,33 @@ abstract class HTTPError extends Error { - public status: number; + public status: number - protected constructor(status: number) { - super(); - this.status = status; - this.name = "HTTPError"; - } + protected constructor(status: number) { + super() + this.status = status + this.name = "HTTPError" + } } export class NotFoundError extends HTTPError { - constructor(message?: string) { - super(404); - this.message = message ?? "Not Found"; - this.name = this.status.toString(); - } + constructor(message?: string) { + super(404) + this.message = message ?? "Not Found" + this.name = this.status.toString() + } } export class UnauthorizedError extends HTTPError { - constructor(message?: string) { - super(401); - this.message = message ?? "Unauthorized"; - this.name = this.status.toString(); - } + constructor(message?: string) { + super(401) + this.message = message ?? "Unauthorized" + this.name = this.status.toString() + } } export class BadRequestError extends HTTPError { - constructor(message?: string) { - super(400); - this.message = message ?? "Bad Request"; - this.name = this.status.toString(); - } + constructor(message?: string) { + super(400) + this.message = message ?? "Bad Request" + this.name = this.status.toString() + } } diff --git a/backend/src/index.ts b/backend/src/index.ts index 0b2d920b..aa472bc1 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,26 +1,26 @@ -import express, { Express, Request, Response } from "express"; -import dotenv from "dotenv"; -import NewsRouter from "./routes/news.router"; -import ResearchRouter from "./routes/research.router"; +import express, { Express, Request, Response } from "express" +import dotenv from "dotenv" +import NewsRouter from "./routes/news.router" +import ResearchRouter from "./routes/research.router" -dotenv.config(); +dotenv.config() -const app: Express = express(); -const port = process.env.PORT || 3000; +const app: Express = express() +const port = process.env.PORT || 3000 -app.use(express.json()); -app.use(require("cors")()); +app.use(express.json()) +app.use(require("cors")()) app.get("/", (req: Request, res: Response) => { - res.json({ - message: "ok", - environment: (process.env.ENV ?? "local").toLowerCase(), - }); -}); + res.json({ + message: "ok", + environment: (process.env.ENV ?? "local").toLowerCase(), + }) +}) -app.use(NewsRouter.url, NewsRouter.router()); -app.use(ResearchRouter.url, ResearchRouter.router()); +app.use(NewsRouter.url, NewsRouter.router()) +app.use(ResearchRouter.url, ResearchRouter.router()) app.listen(port, () => { - console.log(`Server is running at http://localhost:${port}`); -}); + console.log(`Server is running at http://localhost:${port}`) +}) diff --git a/backend/src/repositories/IRepository.ts b/backend/src/repositories/IRepository.ts index d578c7c8..a78548f2 100644 --- a/backend/src/repositories/IRepository.ts +++ b/backend/src/repositories/IRepository.ts @@ -1,62 +1,51 @@ -import { Article, User } from "@aapc/types"; -import { - ArrayResult, - ArrayResultOptions, - Nullable, - SortOptions, -} from "../util/types/util.types"; -import { ArticleSortFields } from "./memory/sorters/article.sorter"; -import { UserSortFields } from "./memory/sorters/user.sorter"; +import { Article, User } from "@aapc/types" +import { ArrayResult, ArrayResultOptions, Nullable, SortOptions } from "../util/types/util.types" +import { ArticleSortFields } from "./memory/sorters/article.sorter" +import { UserSortFields } from "./memory/sorters/user.sorter" export default interface IRepository { - getAllNews( - options?: ArrayResultOptions>, - ): Promise>; + getAllNews(options?: ArrayResultOptions>): Promise> - getNewsById(id: string): Promise>; + getNewsById(id: string): Promise> - searchNewsByTitle( - title: string, - options?: ArrayResultOptions>, - ): Promise>; + searchNewsByTitle( + title: string, + options?: ArrayResultOptions> + ): Promise> - createNews(a: Article): Promise
; + createNews(a: Article): Promise
- editNews(id: string, a: Article): Promise
; + editNews(id: string, a: Article): Promise
- deleteNews(id: string): Promise; + deleteNews(id: string): Promise - getAllResearch( - options?: ArrayResultOptions>, - ): Promise>; + getAllResearch(options?: ArrayResultOptions>): Promise> - getResearchById(id: string): Promise>; + getResearchById(id: string): Promise> - searchResearchByTitle( - title: string, - options?: ArrayResultOptions>, - ): Promise>; + searchResearchByTitle( + title: string, + options?: ArrayResultOptions> + ): Promise> - createResearch(a: Article): Promise
; + createResearch(a: Article): Promise
- editResearch(id: string, a: Article): Promise
; + editResearch(id: string, a: Article): Promise
- deleteResearch(id: string): Promise; + deleteResearch(id: string): Promise - getAllUsers( - options?: ArrayResultOptions>, - ): Promise>; + getAllUsers(options?: ArrayResultOptions>): Promise> - getUserByUsername(username: string): Promise>; + getUserByUsername(username: string): Promise> - searchUserByUsername( - username: string, - options?: ArrayResultOptions>, - ): Promise>; + searchUserByUsername( + username: string, + options?: ArrayResultOptions> + ): Promise> - createUser(u: User): Promise; + createUser(u: User): Promise - editUser(username: string, u: User): Promise; + editUser(username: string, u: User): Promise - deleteUser(username: string): Promise; + deleteUser(username: string): Promise } diff --git a/backend/src/repositories/memory/MemoryRepository.ts b/backend/src/repositories/memory/MemoryRepository.ts index 84a63919..6ede144e 100644 --- a/backend/src/repositories/memory/MemoryRepository.ts +++ b/backend/src/repositories/memory/MemoryRepository.ts @@ -1,228 +1,215 @@ -import users from "./data/users.json"; -import news from "./data/news.json"; -import researches from "./data/researches.json"; - -import { Article, IArticle, User } from "@aapc/types"; -import IRepository from "../IRepository"; -import { - ArrayResult, - ArrayResultOptions, - Nullable, - SortOptions, -} from "../../util/types/util.types"; -import { ArticleSortFields } from "./sorters/article.sorter"; -import { UserSortFields } from "./sorters/user.sorter"; -import { Sorter } from "./sorters/Sorter"; +import users from "./data/users.json" +import news from "./data/news.json" +import researches from "./data/researches.json" + +import { Article, IArticle, User } from "@aapc/types" +import IRepository from "../IRepository" +import { ArrayResult, ArrayResultOptions, Nullable, SortOptions } from "../../util/types/util.types" +import { ArticleSortFields } from "./sorters/article.sorter" +import { UserSortFields } from "./sorters/user.sorter" +import { Sorter } from "./sorters/Sorter" export default class MemoryRepository implements IRepository { - private readonly users: User[]; - private readonly news: Article[]; - private readonly researches: Article[]; - - constructor() { - this.users = []; - users.forEach((i) => { - this.users.push(new User(i)); - }); - - this.news = []; - news.forEach((i) => { - this.getUserByUsername(i.publisher).then((r) => { - const j: IArticle = { ...i, ...{ publisher: r ?? new User() } }; - this.news.push(new Article(j)); - }); - }); - - this.researches = []; - researches.forEach((i) => { - this.getUserByUsername(i.publisher).then((r) => { - const j: IArticle = { ...i, ...{ publisher: r ?? new User() } }; - this.researches.push(new Article(j)); - }); - }); - } - - handleArrayResultOptions>( - arr: T[], - options?: ArrayResultOptions, - sorter?: Sorter, - ): T[] { - let start, end; - if (options) { - start = options.startFrom ?? 0; - end = options.maxResults ? options.maxResults + start : undefined; - if (sorter) { - sorter(arr, options.sort); - } - } - return arr.slice(start, end); - } - - async getAllNews( - options?: ArrayResultOptions>, - ): Promise> { - let r = structuredClone(this.news); - return { - totalResults: r.length, - results: this.handleArrayResultOptions(r, options), - }; - } - - async getNewsById(id: string): Promise> { - for (const a of this.news) { - if (a.id === id) { - return a; - } - } - return null; - } - - async searchNewsByTitle( - title: string, - options?: ArrayResultOptions>, - ): Promise> { - let r = this.news.filter((a) => - a.title.toLowerCase().includes(title.toLowerCase()), - ); - return { - totalResults: r.length, - results: this.handleArrayResultOptions(r, options), - }; - } - - async createNews(a: Article): Promise
{ - this.news.push(a); - return a; - } - - async editNews(id: string, a: Article): Promise
{ - if (a.id !== id) throw new TypeError("News edit ID mismatch"); - for (let i = 0; i < this.news.length; i++) { - if (this.news[i].id === id) { - this.news[i] = a; - break; - } - } - return a; - } - - async deleteNews(id: string): Promise { - for (let i = 0; i < this.news.length; i++) { - if (this.news[i].id === id) { - this.news.splice(i, 1); - return; - } - } - throw new TypeError(`No news with ID ${id}.`); - } - - async getAllResearch( - options?: ArrayResultOptions>, - ): Promise> { - let r = structuredClone(this.researches); - return { - totalResults: r.length, - results: this.handleArrayResultOptions(r, options), - }; - } - - async getResearchById(id: string): Promise> { - for (const a of this.researches) { - if (a.id === id) return a; - } - return null; - } - - async searchResearchByTitle( - title: string, - options?: ArrayResultOptions>, - ): Promise> { - let r = this.researches.filter((a) => - a.title.toLowerCase().includes(title.toLowerCase()), - ); - return { - totalResults: r.length, - results: this.handleArrayResultOptions(r, options), - }; - } - - async createResearch(a: Article): Promise
{ - this.researches.push(a); - return a; - } - - async editResearch(id: string, a: Article): Promise
{ - if (a.id !== id) throw new TypeError("Research edit ID mismatch"); - for (let i = 0; i < this.researches.length; i++) { - if (this.researches[i].id === id) { - this.researches[i] = a; - break; - } - } - return a; - } - - async deleteResearch(id: string): Promise { - for (let i = 0; i < this.researches.length; i++) { - if (this.researches[i].id === id) { - this.researches.splice(i, 1); - return; - } - } - } - - async getAllUsers( - options?: ArrayResultOptions>, - ): Promise> { - let r = structuredClone(this.users); - return { - totalResults: r.length, - results: this.handleArrayResultOptions(r, options), - }; - } - - async getUserByUsername(username: string): Promise> { - for (const u of this.users) { - if (u.username === username) return u; - } - return null; - } - - async searchUserByUsername( - username: string, - options?: ArrayResultOptions>, - ): Promise> { - let r = this.users.filter((a) => - a.username.toLowerCase().includes(username.toLowerCase()), - ); - return { - totalResults: r.length, - results: this.handleArrayResultOptions(r, options), - }; - } - - async createUser(u: User): Promise { - this.users.push(u); - return u; - } - - async editUser(username: string, u: User): Promise { - if (username !== u.username) throw new TypeError("User edit ID mismatch"); - for (let i = 0; i < this.users.length; i++) { - if (this.users[i].username === username) { - this.users[i] = u; - break; - } - } - return u; - } - - async deleteUser(username: string): Promise { - for (let i = 0; i < this.users.length; i++) { - if (this.users[i].username === username) { - this.users.splice(i, 1); - return; - } - } - } + private readonly users: User[] + private readonly news: Article[] + private readonly researches: Article[] + + constructor() { + this.users = [] + users.forEach((i) => { + this.users.push(new User(i)) + }) + + this.news = [] + news.forEach((i) => { + this.getUserByUsername(i.publisher).then((r) => { + const j: IArticle = { ...i, ...{ publisher: r ?? new User() } } + this.news.push(new Article(j)) + }) + }) + + this.researches = [] + researches.forEach((i) => { + this.getUserByUsername(i.publisher).then((r) => { + const j: IArticle = { ...i, ...{ publisher: r ?? new User() } } + this.researches.push(new Article(j)) + }) + }) + } + + handleArrayResultOptions>( + arr: T[], + options?: ArrayResultOptions, + sorter?: Sorter + ): T[] { + let start, end + if (options) { + start = options.startFrom ?? 0 + end = options.maxResults ? options.maxResults + start : undefined + if (sorter) { + sorter(arr, options.sort) + } + } + return arr.slice(start, end) + } + + async getAllNews( + options?: ArrayResultOptions> + ): Promise> { + let r = structuredClone(this.news) + return { + totalResults: r.length, + results: this.handleArrayResultOptions(r, options), + } + } + + async getNewsById(id: string): Promise> { + for (const a of this.news) { + if (a.id === id) { + return a + } + } + return null + } + + async searchNewsByTitle( + title: string, + options?: ArrayResultOptions> + ): Promise> { + let r = this.news.filter((a) => a.title.toLowerCase().includes(title.toLowerCase())) + return { + totalResults: r.length, + results: this.handleArrayResultOptions(r, options), + } + } + + async createNews(a: Article): Promise
{ + this.news.push(a) + return a + } + + async editNews(id: string, a: Article): Promise
{ + if (a.id !== id) throw new TypeError("News edit ID mismatch") + for (let i = 0; i < this.news.length; i++) { + if (this.news[i].id === id) { + this.news[i] = a + break + } + } + return a + } + + async deleteNews(id: string): Promise { + for (let i = 0; i < this.news.length; i++) { + if (this.news[i].id === id) { + this.news.splice(i, 1) + return + } + } + throw new TypeError(`No news with ID ${id}.`) + } + + async getAllResearch( + options?: ArrayResultOptions> + ): Promise> { + let r = structuredClone(this.researches) + return { + totalResults: r.length, + results: this.handleArrayResultOptions(r, options), + } + } + + async getResearchById(id: string): Promise> { + for (const a of this.researches) { + if (a.id === id) return a + } + return null + } + + async searchResearchByTitle( + title: string, + options?: ArrayResultOptions> + ): Promise> { + let r = this.researches.filter((a) => a.title.toLowerCase().includes(title.toLowerCase())) + return { + totalResults: r.length, + results: this.handleArrayResultOptions(r, options), + } + } + + async createResearch(a: Article): Promise
{ + this.researches.push(a) + return a + } + + async editResearch(id: string, a: Article): Promise
{ + if (a.id !== id) throw new TypeError("Research edit ID mismatch") + for (let i = 0; i < this.researches.length; i++) { + if (this.researches[i].id === id) { + this.researches[i] = a + break + } + } + return a + } + + async deleteResearch(id: string): Promise { + for (let i = 0; i < this.researches.length; i++) { + if (this.researches[i].id === id) { + this.researches.splice(i, 1) + return + } + } + } + + async getAllUsers(options?: ArrayResultOptions>): Promise> { + let r = structuredClone(this.users) + return { + totalResults: r.length, + results: this.handleArrayResultOptions(r, options), + } + } + + async getUserByUsername(username: string): Promise> { + for (const u of this.users) { + if (u.username === username) return u + } + return null + } + + async searchUserByUsername( + username: string, + options?: ArrayResultOptions> + ): Promise> { + let r = this.users.filter((a) => a.username.toLowerCase().includes(username.toLowerCase())) + return { + totalResults: r.length, + results: this.handleArrayResultOptions(r, options), + } + } + + async createUser(u: User): Promise { + this.users.push(u) + return u + } + + async editUser(username: string, u: User): Promise { + if (username !== u.username) throw new TypeError("User edit ID mismatch") + for (let i = 0; i < this.users.length; i++) { + if (this.users[i].username === username) { + this.users[i] = u + break + } + } + return u + } + + async deleteUser(username: string): Promise { + for (let i = 0; i < this.users.length; i++) { + if (this.users[i].username === username) { + this.users.splice(i, 1) + return + } + } + } } diff --git a/backend/src/repositories/memory/data/news.json b/backend/src/repositories/memory/data/news.json index b294a454..4adb1ba6 100644 --- a/backend/src/repositories/memory/data/news.json +++ b/backend/src/repositories/memory/data/news.json @@ -1,277 +1,277 @@ [ - { - "id": "KpZq1NvR", - "title": "Pollen Counts Soar in New Zealand: What You Need to Know", - "subtitle": "Latest updates on allergies", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque tristique ex et gravida cursus. Aliquam erat volutpat. Mauris vitae ante varius, ullamcorper sapien ac, cursus nibh. Morbi tristique, purus sed ultricies feugiat, nulla elit efficitur est, ut ultrices orci arcu vitae magna.", - "articleType": 0, - "publisher": "airmonitor", - "publishedAt": "2024-04-23T08:22:51.924Z", - "lastEditedAt": "2024-04-23T08:22:51.924Z", - "media": [] - }, - { - "id": "aLhD4K2m", - "title": "Pollen Allergies: How New Zealanders Are Coping", - "subtitle": "Practical tips for relief", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed volutpat, elit sit amet interdum tincidunt, libero nibh tincidunt justo, in venenatis urna velit a ante. Nullam venenatis velit sed felis bibendum facilisis. Curabitur eget ante a elit convallis consectetur. Suspendisse potenti.", - "articleType": 0, - "publisher": "nzhealth", - "publishedAt": "2024-04-19T10:47:38.285Z", - "lastEditedAt": "2024-04-19T10:47:38.285Z", - "media": [] - }, - { - "id": "3JhQwX9r", - "title": "Airborne Pollen in New Zealand: A Growing Health Concern", - "subtitle": "Understanding the risks", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus laoreet, nisi a faucibus tempus, augue nulla auctor augue, nec fermentum elit nibh sed eros. Proin luctus, est euismod fringilla ultrices, erat nisi hendrerit turpis, id ultrices libero erat ut risus. Mauris auctor consequat nisl a aliquam.", - "articleType": 0, - "publisher": "kiwihealth", - "publishedAt": "2024-04-15T14:32:17.756Z", - "lastEditedAt": "2024-04-15T14:32:17.756Z", - "media": [] - }, - { - "id": "eFz6n2Yb", - "title": "Climate Change and Its Effects on Pollen Season in New Zealand", - "subtitle": "How weather patterns affect pollen", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum consectetur purus sit amet dolor mollis, at egestas ligula efficitur. Morbi fringilla mi ac venenatis varius. Curabitur convallis libero in sem volutpat, sed fringilla nisi auctor.", - "articleType": 0, - "publisher": "climatewatch", - "publishedAt": "2024-05-05T11:00:30.512Z", - "lastEditedAt": "2024-05-05T11:00:30.512Z", - "media": [] - }, - { - "id": "tWgP3HkR", - "title": "Natural Pollen Remedies for a Healthier New Zealand", - "subtitle": "Herbal and homeopathic solutions", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sed erat sed velit efficitur hendrerit. Vivamus ac sapien purus. Maecenas volutpat, libero quis tempor congue, erat ligula tristique elit, et consequat nibh nunc sit amet nisi.", - "articleType": 0, - "publisher": "airmonitor", - "publishedAt": "2024-04-28T14:20:45.123Z", - "lastEditedAt": "2024-04-28T14:20:45.123Z", - "media": [] - }, - { - "id": "mZ5r9UoB", - "title": "Understanding Pollen Allergies in New Zealand's Environment", - "subtitle": "Causes and treatments", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ac erat ut ante varius viverra vel nec dolor. Donec id magna sit amet est blandit faucibus nec quis est. Morbi sodales orci nec sem malesuada vestibulum. Phasellus vehicula sem at purus.", - "articleType": 0, - "publisher": "airmonitor", - "publishedAt": "2024-05-12T09:35:28.789Z", - "lastEditedAt": "2024-05-12T09:35:28.789Z", - "media": [] - }, - { - "id": "nFwC8T2s", - "title": "Top Tips for Reducing Pollen Exposure in New Zealand", - "subtitle": "Stay safe and breathe easy", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed gravida lorem et justo commodo, vel ullamcorper velit ultricies. Aliquam erat volutpat. Vivamus placerat, nisi nec suscipit volutpat, purus turpis pellentesque ipsum, at finibus dui ligula ut mauris.", - "articleType": 0, - "publisher": "airmonitor", - "publishedAt": "2024-05-02T15:48:51.324Z", - "lastEditedAt": "2024-05-02T15:48:51.324Z", - "media": [] - }, - { - "id": "jHq7uD3V", - "title": "Airborne Pollen Monitoring in New Zealand's Major Cities", - "subtitle": "Keeping track of allergy triggers", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vitae ligula luctus, placerat sapien et, pharetra dolor. Vivamus bibendum risus nec nunc egestas, vel efficitur magna euismod. Donec id ligula et felis dignissim euismod.", - "articleType": 0, - "publisher": "nzhealth", - "publishedAt": "2024-04-30T08:25:40.312Z", - "lastEditedAt": "2024-04-30T08:25:40.312Z", - "media": [] - }, - { - "id": "s2G4v3Yl", - "title": "New Zealand's Approach to Reducing Airborne Pollen", - "subtitle": "Innovative solutions", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur bibendum, ex vel blandit finibus, urna libero egestas lectus, et scelerisque leo augue sit amet felis. Integer ac nulla in risus vulputate vestibulum.", - "articleType": 0, - "publisher": "nzhealth", - "publishedAt": "2024-05-03T16:30:20.789Z", - "lastEditedAt": "2024-05-03T16:30:20.789Z", - "media": [] - }, - { - "id": "r8Kj2Nwq", - "title": "New Zealand's Top Allergy-Friendly Destinations", - "subtitle": "Where to go this season", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer commodo, mauris vel scelerisque facilisis, turpis neque condimentum arcu, vel dapibus dui eros vitae leo. Morbi varius, mi non consectetur malesuada, arcu metus condimentum ante.", - "articleType": 0, - "publisher": "nzhealth", - "publishedAt": "2024-04-29T11:25:17.456Z", - "lastEditedAt": "2024-04-29T11:25:17.456Z", - "media": [] - }, - { - "id": "qP5t2Mzn", - "title": "Rising Pollen Levels Impacting New Zealand's Tourism Industry", - "subtitle": "Travelers face challenges", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras eleifend arcu ut augue euismod, eget malesuada purus bibendum. In hac habitasse platea dictumst. Nullam ac felis eros. Vestibulum id diam felis.", - "articleType": 0, - "publisher": "nzhealth", - "publishedAt": "2024-04-27T08:52:30.341Z", - "lastEditedAt": "2024-04-27T08:52:30.341Z", - "media": [] - }, - { - "id": "p9Rw7UlO", - "title": "New Zealand's Allergy Relief Strategies for High Pollen Days", - "subtitle": "What you need to know", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum in malesuada urna. Donec volutpat facilisis erat sit amet mollis. Vivamus blandit tincidunt libero a fermentum. Donec interdum nisl id nisl cursus, in dapibus libero cursus.", - "articleType": 0, - "publisher": "nzhealth", - "publishedAt": "2024-05-06T12:10:12.789Z", - "lastEditedAt": "2024-05-06T12:10:12.789Z", - "media": [] - }, - { - "id": "L9Bq2NjY", - "title": "How to Navigate New Zealand's Pollen Season Safely", - "subtitle": "Tips for a healthy season", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla vel felis facilisis, congue mi ut, congue sem. Proin id augue vehicula, facilisis odio at, lobortis nisi. Praesent non volutpat nulla.", - "articleType": 0, - "publisher": "kiwihealth", - "publishedAt": "2024-05-10T14:38:45.231Z", - "lastEditedAt": "2024-05-10T14:38:45.231Z", - "media": [] - }, - { - "id": "fG9X4VlK", - "title": "New Zealand's Pollen Season: A Guide to Staying Healthy", - "subtitle": "Keeping allergies at bay", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi nec massa vel nisi fringilla cursus nec a est. Praesent vestibulum, libero et ornare congue, sem nisi consequat augue, ac interdum magna metus at felis.", - "articleType": 0, - "publisher": "kiwihealth", - "publishedAt": "2024-05-12T10:40:38.450Z", - "lastEditedAt": "2024-05-12T10:40:38.450Z", - "media": [] - }, - { - "id": "dH6r9BtY", - "title": "New Zealand Farmers Brace for High Pollen Counts", - "subtitle": "Agricultural challenges", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vel ligula malesuada, placerat libero eu, aliquet sapien. Duis facilisis diam non sem scelerisque, quis pellentesque elit ornare. Curabitur vel convallis neque.", - "articleType": 0, - "publisher": "climatewatch", - "publishedAt": "2024-05-14T07:55:49.105Z", - "lastEditedAt": "2024-05-14T07:55:49.105Z", - "media": [] - }, - { - "id": "aH5j7LrY", - "title": "Keeping Pollen Allergies Under Control in New Zealand", - "subtitle": "Effective management", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eleifend mauris at felis luctus, in varius justo condimentum. Praesent gravida, nulla id commodo scelerisque, sapien ligula ultrices justo, sed luctus neque enim non ligula.", - "articleType": 0, - "publisher": "climatewatch", - "publishedAt": "2024-05-15T13:15:24.789Z", - "lastEditedAt": "2024-05-15T13:15:24.789Z", - "media": [] - }, - { - "id": "wC4j6MxR", - "title": "Pollen Season in New Zealand: How to Stay Informed", - "subtitle": "Daily updates and advice", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed bibendum turpis a vestibulum efficitur. Nulla facilisi. Etiam varius turpis at ante scelerisque, nec convallis sapien pharetra. Morbi efficitur a arcu a varius.", - "articleType": 0, - "publisher": "climatewatch", - "publishedAt": "2024-04-30T10:10:55.789Z", - "lastEditedAt": "2024-04-30T10:10:55.789Z", - "media": [] - }, - { - "id": "zH6r2KtY", - "title": "New Zealand's Coastal Pollen Concerns: Impact on Residents", - "subtitle": "Sea breezes carry allergens", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam eleifend, mauris nec lacinia bibendum, nulla lacus tincidunt risus, sed sodales erat ligula eget dolor.", - "articleType": 0, - "publisher": "climatewatch", - "publishedAt": "2024-04-26T16:30:12.654Z", - "lastEditedAt": "2024-04-26T16:30:12.654Z", - "media": [] - }, - { - "id": "kT3j8NpQ", - "title": "Understanding New Zealand's Pollen Patterns and Health Risks", - "subtitle": "Expert insights", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam fringilla, nibh ut elementum convallis, sapien enim varius libero, vel cursus risus ante at arcu. Nulla facilisi. Integer in orci non metus vulputate auctor.", - "articleType": 0, - "publisher": "climatewatch", - "publishedAt": "2024-04-28T09:10:45.012Z", - "lastEditedAt": "2024-04-28T09:10:45.012Z", - "media": [] - }, - { - "id": "jK8z3HrS", - "title": "New Zealand Pollen Hotspots: Cities with High Allergens", - "subtitle": "Keeping track of problem areas", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ornare ipsum nec nunc sagittis, eget volutpat elit feugiat. Integer tempor sed metus ut pharetra. Suspendisse posuere eros a orci ultrices, sit amet ornare justo eleifend.", - "articleType": 0, - "publisher": "climatewatch", - "publishedAt": "2024-04-29T07:20:12.654Z", - "lastEditedAt": "2024-04-29T07:20:12.654Z", - "media": [] - }, - { - "id": "qT3l5NuR", - "title": "How New Zealand's Pollen Season Affects Children's Health", - "subtitle": "Parents need to be aware", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vehicula nulla eget purus commodo facilisis. Maecenas ac tellus ut lorem volutpat laoreet a sed elit. Donec eget leo justo. Aliquam finibus metus eget.", - "articleType": 0, - "publisher": "climatewatch", - "publishedAt": "2024-05-05T15:28:12.236Z", - "lastEditedAt": "2024-05-05T15:28:12.236Z", - "media": [] - }, - { - "id": "hC7z6LtR", - "title": "New Zealand's Indigenous Plants: Pollen and Health Implications", - "subtitle": "Impact on locals", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ultricies ipsum et eros scelerisque, vel posuere justo vehicula. Nullam non lacinia ex, vel dapibus metus. Donec nec volutpat dui, a lacinia velit.", - "articleType": 0, - "publisher": "climatewatch", - "publishedAt": "2024-05-07T10:32:45.564Z", - "lastEditedAt": "2024-05-07T10:32:45.564Z", - "media": [] - }, - { - "id": "gP4q7WtY", - "title": "New Zealand Pollen Reports: What to Expect This Season", - "subtitle": "Forecasts and updates", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin convallis risus ac sapien vehicula, sit amet ultricies sem ultricies. Suspendisse potenti. Vivamus cursus nisl id volutpat ornare. Nam consectetur orci a dolor scelerisque luctus.", - "articleType": 0, - "publisher": "nzhealth", - "publishedAt": "2024-05-09T08:40:12.234Z", - "lastEditedAt": "2024-05-09T08:40:12.234Z", - "media": [] - }, - { - "id": "wK4n6GqR", - "title": "New Zealand's Climate Change Impact on Pollen Season", - "subtitle": "What does the future hold?", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur nec bibendum odio. Etiam consectetur, risus ut malesuada bibendum, neque enim fermentum sem, non sollicitudin velit augue sit amet dolor.", - "articleType": 0, - "publisher": "nzhealth", - "publishedAt": "2024-05-08T13:45:38.987Z", - "lastEditedAt": "2024-05-08T13:45:38.987Z", - "media": [] - }, - { - "id": "kJ3p6KtY", - "title": "New Zealand's Pollen Crisis: How to Stay Safe", - "subtitle": "Precautions you can take", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse potenti. Curabitur in augue sit amet libero convallis cursus. In hac habitasse platea dictumst. Nulla convallis, arcu at congue tempor, metus enim bibendum arcu.", - "articleType": 0, - "publisher": "kiwihealth", - "publishedAt": "2024-05-02T11:30:15.432Z", - "lastEditedAt": "2024-05-02T11:30:15.432Z", - "media": [] - } + { + "id": "KpZq1NvR", + "title": "Pollen Counts Soar in New Zealand: What You Need to Know", + "subtitle": "Latest updates on allergies", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque tristique ex et gravida cursus. Aliquam erat volutpat. Mauris vitae ante varius, ullamcorper sapien ac, cursus nibh. Morbi tristique, purus sed ultricies feugiat, nulla elit efficitur est, ut ultrices orci arcu vitae magna.", + "articleType": 0, + "publisher": "airmonitor", + "publishedAt": "2024-04-23T08:22:51.924Z", + "lastEditedAt": "2024-04-23T08:22:51.924Z", + "media": [] + }, + { + "id": "aLhD4K2m", + "title": "Pollen Allergies: How New Zealanders Are Coping", + "subtitle": "Practical tips for relief", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed volutpat, elit sit amet interdum tincidunt, libero nibh tincidunt justo, in venenatis urna velit a ante. Nullam venenatis velit sed felis bibendum facilisis. Curabitur eget ante a elit convallis consectetur. Suspendisse potenti.", + "articleType": 0, + "publisher": "nzhealth", + "publishedAt": "2024-04-19T10:47:38.285Z", + "lastEditedAt": "2024-04-19T10:47:38.285Z", + "media": [] + }, + { + "id": "3JhQwX9r", + "title": "Airborne Pollen in New Zealand: A Growing Health Concern", + "subtitle": "Understanding the risks", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus laoreet, nisi a faucibus tempus, augue nulla auctor augue, nec fermentum elit nibh sed eros. Proin luctus, est euismod fringilla ultrices, erat nisi hendrerit turpis, id ultrices libero erat ut risus. Mauris auctor consequat nisl a aliquam.", + "articleType": 0, + "publisher": "kiwihealth", + "publishedAt": "2024-04-15T14:32:17.756Z", + "lastEditedAt": "2024-04-15T14:32:17.756Z", + "media": [] + }, + { + "id": "eFz6n2Yb", + "title": "Climate Change and Its Effects on Pollen Season in New Zealand", + "subtitle": "How weather patterns affect pollen", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum consectetur purus sit amet dolor mollis, at egestas ligula efficitur. Morbi fringilla mi ac venenatis varius. Curabitur convallis libero in sem volutpat, sed fringilla nisi auctor.", + "articleType": 0, + "publisher": "climatewatch", + "publishedAt": "2024-05-05T11:00:30.512Z", + "lastEditedAt": "2024-05-05T11:00:30.512Z", + "media": [] + }, + { + "id": "tWgP3HkR", + "title": "Natural Pollen Remedies for a Healthier New Zealand", + "subtitle": "Herbal and homeopathic solutions", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sed erat sed velit efficitur hendrerit. Vivamus ac sapien purus. Maecenas volutpat, libero quis tempor congue, erat ligula tristique elit, et consequat nibh nunc sit amet nisi.", + "articleType": 0, + "publisher": "airmonitor", + "publishedAt": "2024-04-28T14:20:45.123Z", + "lastEditedAt": "2024-04-28T14:20:45.123Z", + "media": [] + }, + { + "id": "mZ5r9UoB", + "title": "Understanding Pollen Allergies in New Zealand's Environment", + "subtitle": "Causes and treatments", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ac erat ut ante varius viverra vel nec dolor. Donec id magna sit amet est blandit faucibus nec quis est. Morbi sodales orci nec sem malesuada vestibulum. Phasellus vehicula sem at purus.", + "articleType": 0, + "publisher": "airmonitor", + "publishedAt": "2024-05-12T09:35:28.789Z", + "lastEditedAt": "2024-05-12T09:35:28.789Z", + "media": [] + }, + { + "id": "nFwC8T2s", + "title": "Top Tips for Reducing Pollen Exposure in New Zealand", + "subtitle": "Stay safe and breathe easy", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed gravida lorem et justo commodo, vel ullamcorper velit ultricies. Aliquam erat volutpat. Vivamus placerat, nisi nec suscipit volutpat, purus turpis pellentesque ipsum, at finibus dui ligula ut mauris.", + "articleType": 0, + "publisher": "airmonitor", + "publishedAt": "2024-05-02T15:48:51.324Z", + "lastEditedAt": "2024-05-02T15:48:51.324Z", + "media": [] + }, + { + "id": "jHq7uD3V", + "title": "Airborne Pollen Monitoring in New Zealand's Major Cities", + "subtitle": "Keeping track of allergy triggers", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vitae ligula luctus, placerat sapien et, pharetra dolor. Vivamus bibendum risus nec nunc egestas, vel efficitur magna euismod. Donec id ligula et felis dignissim euismod.", + "articleType": 0, + "publisher": "nzhealth", + "publishedAt": "2024-04-30T08:25:40.312Z", + "lastEditedAt": "2024-04-30T08:25:40.312Z", + "media": [] + }, + { + "id": "s2G4v3Yl", + "title": "New Zealand's Approach to Reducing Airborne Pollen", + "subtitle": "Innovative solutions", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur bibendum, ex vel blandit finibus, urna libero egestas lectus, et scelerisque leo augue sit amet felis. Integer ac nulla in risus vulputate vestibulum.", + "articleType": 0, + "publisher": "nzhealth", + "publishedAt": "2024-05-03T16:30:20.789Z", + "lastEditedAt": "2024-05-03T16:30:20.789Z", + "media": [] + }, + { + "id": "r8Kj2Nwq", + "title": "New Zealand's Top Allergy-Friendly Destinations", + "subtitle": "Where to go this season", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer commodo, mauris vel scelerisque facilisis, turpis neque condimentum arcu, vel dapibus dui eros vitae leo. Morbi varius, mi non consectetur malesuada, arcu metus condimentum ante.", + "articleType": 0, + "publisher": "nzhealth", + "publishedAt": "2024-04-29T11:25:17.456Z", + "lastEditedAt": "2024-04-29T11:25:17.456Z", + "media": [] + }, + { + "id": "qP5t2Mzn", + "title": "Rising Pollen Levels Impacting New Zealand's Tourism Industry", + "subtitle": "Travelers face challenges", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras eleifend arcu ut augue euismod, eget malesuada purus bibendum. In hac habitasse platea dictumst. Nullam ac felis eros. Vestibulum id diam felis.", + "articleType": 0, + "publisher": "nzhealth", + "publishedAt": "2024-04-27T08:52:30.341Z", + "lastEditedAt": "2024-04-27T08:52:30.341Z", + "media": [] + }, + { + "id": "p9Rw7UlO", + "title": "New Zealand's Allergy Relief Strategies for High Pollen Days", + "subtitle": "What you need to know", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum in malesuada urna. Donec volutpat facilisis erat sit amet mollis. Vivamus blandit tincidunt libero a fermentum. Donec interdum nisl id nisl cursus, in dapibus libero cursus.", + "articleType": 0, + "publisher": "nzhealth", + "publishedAt": "2024-05-06T12:10:12.789Z", + "lastEditedAt": "2024-05-06T12:10:12.789Z", + "media": [] + }, + { + "id": "L9Bq2NjY", + "title": "How to Navigate New Zealand's Pollen Season Safely", + "subtitle": "Tips for a healthy season", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla vel felis facilisis, congue mi ut, congue sem. Proin id augue vehicula, facilisis odio at, lobortis nisi. Praesent non volutpat nulla.", + "articleType": 0, + "publisher": "kiwihealth", + "publishedAt": "2024-05-10T14:38:45.231Z", + "lastEditedAt": "2024-05-10T14:38:45.231Z", + "media": [] + }, + { + "id": "fG9X4VlK", + "title": "New Zealand's Pollen Season: A Guide to Staying Healthy", + "subtitle": "Keeping allergies at bay", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi nec massa vel nisi fringilla cursus nec a est. Praesent vestibulum, libero et ornare congue, sem nisi consequat augue, ac interdum magna metus at felis.", + "articleType": 0, + "publisher": "kiwihealth", + "publishedAt": "2024-05-12T10:40:38.450Z", + "lastEditedAt": "2024-05-12T10:40:38.450Z", + "media": [] + }, + { + "id": "dH6r9BtY", + "title": "New Zealand Farmers Brace for High Pollen Counts", + "subtitle": "Agricultural challenges", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vel ligula malesuada, placerat libero eu, aliquet sapien. Duis facilisis diam non sem scelerisque, quis pellentesque elit ornare. Curabitur vel convallis neque.", + "articleType": 0, + "publisher": "climatewatch", + "publishedAt": "2024-05-14T07:55:49.105Z", + "lastEditedAt": "2024-05-14T07:55:49.105Z", + "media": [] + }, + { + "id": "aH5j7LrY", + "title": "Keeping Pollen Allergies Under Control in New Zealand", + "subtitle": "Effective management", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eleifend mauris at felis luctus, in varius justo condimentum. Praesent gravida, nulla id commodo scelerisque, sapien ligula ultrices justo, sed luctus neque enim non ligula.", + "articleType": 0, + "publisher": "climatewatch", + "publishedAt": "2024-05-15T13:15:24.789Z", + "lastEditedAt": "2024-05-15T13:15:24.789Z", + "media": [] + }, + { + "id": "wC4j6MxR", + "title": "Pollen Season in New Zealand: How to Stay Informed", + "subtitle": "Daily updates and advice", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed bibendum turpis a vestibulum efficitur. Nulla facilisi. Etiam varius turpis at ante scelerisque, nec convallis sapien pharetra. Morbi efficitur a arcu a varius.", + "articleType": 0, + "publisher": "climatewatch", + "publishedAt": "2024-04-30T10:10:55.789Z", + "lastEditedAt": "2024-04-30T10:10:55.789Z", + "media": [] + }, + { + "id": "zH6r2KtY", + "title": "New Zealand's Coastal Pollen Concerns: Impact on Residents", + "subtitle": "Sea breezes carry allergens", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam eleifend, mauris nec lacinia bibendum, nulla lacus tincidunt risus, sed sodales erat ligula eget dolor.", + "articleType": 0, + "publisher": "climatewatch", + "publishedAt": "2024-04-26T16:30:12.654Z", + "lastEditedAt": "2024-04-26T16:30:12.654Z", + "media": [] + }, + { + "id": "kT3j8NpQ", + "title": "Understanding New Zealand's Pollen Patterns and Health Risks", + "subtitle": "Expert insights", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam fringilla, nibh ut elementum convallis, sapien enim varius libero, vel cursus risus ante at arcu. Nulla facilisi. Integer in orci non metus vulputate auctor.", + "articleType": 0, + "publisher": "climatewatch", + "publishedAt": "2024-04-28T09:10:45.012Z", + "lastEditedAt": "2024-04-28T09:10:45.012Z", + "media": [] + }, + { + "id": "jK8z3HrS", + "title": "New Zealand Pollen Hotspots: Cities with High Allergens", + "subtitle": "Keeping track of problem areas", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ornare ipsum nec nunc sagittis, eget volutpat elit feugiat. Integer tempor sed metus ut pharetra. Suspendisse posuere eros a orci ultrices, sit amet ornare justo eleifend.", + "articleType": 0, + "publisher": "climatewatch", + "publishedAt": "2024-04-29T07:20:12.654Z", + "lastEditedAt": "2024-04-29T07:20:12.654Z", + "media": [] + }, + { + "id": "qT3l5NuR", + "title": "How New Zealand's Pollen Season Affects Children's Health", + "subtitle": "Parents need to be aware", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vehicula nulla eget purus commodo facilisis. Maecenas ac tellus ut lorem volutpat laoreet a sed elit. Donec eget leo justo. Aliquam finibus metus eget.", + "articleType": 0, + "publisher": "climatewatch", + "publishedAt": "2024-05-05T15:28:12.236Z", + "lastEditedAt": "2024-05-05T15:28:12.236Z", + "media": [] + }, + { + "id": "hC7z6LtR", + "title": "New Zealand's Indigenous Plants: Pollen and Health Implications", + "subtitle": "Impact on locals", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ultricies ipsum et eros scelerisque, vel posuere justo vehicula. Nullam non lacinia ex, vel dapibus metus. Donec nec volutpat dui, a lacinia velit.", + "articleType": 0, + "publisher": "climatewatch", + "publishedAt": "2024-05-07T10:32:45.564Z", + "lastEditedAt": "2024-05-07T10:32:45.564Z", + "media": [] + }, + { + "id": "gP4q7WtY", + "title": "New Zealand Pollen Reports: What to Expect This Season", + "subtitle": "Forecasts and updates", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin convallis risus ac sapien vehicula, sit amet ultricies sem ultricies. Suspendisse potenti. Vivamus cursus nisl id volutpat ornare. Nam consectetur orci a dolor scelerisque luctus.", + "articleType": 0, + "publisher": "nzhealth", + "publishedAt": "2024-05-09T08:40:12.234Z", + "lastEditedAt": "2024-05-09T08:40:12.234Z", + "media": [] + }, + { + "id": "wK4n6GqR", + "title": "New Zealand's Climate Change Impact on Pollen Season", + "subtitle": "What does the future hold?", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur nec bibendum odio. Etiam consectetur, risus ut malesuada bibendum, neque enim fermentum sem, non sollicitudin velit augue sit amet dolor.", + "articleType": 0, + "publisher": "nzhealth", + "publishedAt": "2024-05-08T13:45:38.987Z", + "lastEditedAt": "2024-05-08T13:45:38.987Z", + "media": [] + }, + { + "id": "kJ3p6KtY", + "title": "New Zealand's Pollen Crisis: How to Stay Safe", + "subtitle": "Precautions you can take", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse potenti. Curabitur in augue sit amet libero convallis cursus. In hac habitasse platea dictumst. Nulla convallis, arcu at congue tempor, metus enim bibendum arcu.", + "articleType": 0, + "publisher": "kiwihealth", + "publishedAt": "2024-05-02T11:30:15.432Z", + "lastEditedAt": "2024-05-02T11:30:15.432Z", + "media": [] + } ] diff --git a/backend/src/repositories/memory/data/researches.json b/backend/src/repositories/memory/data/researches.json index bc3269a9..f323858c 100644 --- a/backend/src/repositories/memory/data/researches.json +++ b/backend/src/repositories/memory/data/researches.json @@ -1,266 +1,266 @@ [ - { - "id": "Vj4n2GqB", - "title": "New Zealand Researchers Analyze Pollen Data Over the Last Decade", - "subtitle": "Climate and allergy links", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed vel sem vel augue scelerisque fermentum at vel justo. Suspendisse venenatis, libero id cursus tempor, urna sapien finibus nunc, eget malesuada neque nunc non erat.", - "articleType": 1, - "publisher": "nzhealth", - "publishedAt": "2024-05-04T14:00:34.321Z", - "lastEditedAt": "2024-05-04T14:00:34.321Z", - "media": [] - }, - { - "id": "Zh6j2KrW", - "title": "Impact of Urbanization on New Zealand's Pollen Levels", - "subtitle": "Study explores potential causes", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur varius magna sit amet tellus volutpat, non cursus nisi tristique. Vestibulum fringilla nibh nec felis sodales, ut auctor eros vehicula. Phasellus tristique elit nec ex vehicula, at vehicula turpis interdum.", - "articleType": 1, - "publisher": "nzhealth", - "publishedAt": "2024-04-29T09:45:27.789Z", - "lastEditedAt": "2024-04-29T09:45:27.789Z", - "media": [] - }, - { - "id": "Bq8j2XkZ", - "title": "Airborne Pollen Trends: Insights from New Zealand's Agricultural Sectors", - "subtitle": "New perspectives", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla facilisi. Suspendisse tempor est sapien, sit amet scelerisque erat scelerisque in. In hac habitasse platea dictumst. Aenean quis libero a sem laoreet consectetur.", - "articleType": 1, - "publisher": "nzhealth", - "publishedAt": "2024-05-06T10:25:31.654Z", - "lastEditedAt": "2024-05-06T10:25:31.654Z", - "media": [] - }, - { - "id": "Rj9k6BtO", - "title": "Pollen Types and Health Effects in New Zealand: A Comparative Study", - "subtitle": "Detailed research findings", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce tincidunt facilisis arcu, non posuere tortor fringilla eu. Suspendisse potenti. Sed vel libero ullamcorper, vulputate augue quis, condimentum est.", - "articleType": 1, - "publisher": "nzhealth", - "publishedAt": "2024-05-12T11:50:21.789Z", - "lastEditedAt": "2024-05-12T11:50:21.789Z", - "media": [] - }, - { - "id": "Xk3g9YpW", - "title": "New Zealand's Climate and Pollen Season: Research Insights", - "subtitle": "The climate impact", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lacinia quam sed libero hendrerit bibendum. Sed posuere eros id dapibus vehicula. Aenean varius lorem sed ligula posuere, sed accumsan velit scelerisque.", - "articleType": 1, - "publisher": "nzhealth", - "publishedAt": "2024-05-05T13:12:36.455Z", - "lastEditedAt": "2024-05-05T13:12:36.455Z", - "media": [] - }, - { - "id": "Pz8m7XkA", - "title": "Understanding Pollen Dispersion Patterns in New Zealand", - "subtitle": "Research reveals new trends", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vestibulum justo nisi, non bibendum mi pretium et. Donec commodo turpis sed lectus eleifend, at vulputate justo sollicitudin.", - "articleType": 1, - "publisher": "nzhealth", - "publishedAt": "2024-04-26T08:00:14.784Z", - "lastEditedAt": "2024-04-26T08:00:14.784Z", - "media": [] - }, - { - "id": "Ky2n7TrE", - "title": "Airborne Pollen Study Links Allergens to Increased Asthma Cases", - "subtitle": "New Zealand research findings", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed hendrerit velit vitae magna elementum, vel tincidunt mauris gravida. Nulla vel mi a dolor ultrices convallis vel et magna.", - "articleType": 1, - "publisher": "airmonitor", - "publishedAt": "2024-05-03T13:32:45.912Z", - "lastEditedAt": "2024-05-03T13:32:45.912Z", - "media": [] - }, - { - "id": "Vw4g2XkP", - "title": "New Zealand's Pollen Exposure: The Role of Vegetation Types", - "subtitle": "Findings on plant influence", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin varius arcu ut facilisis blandit. Integer vel massa vel nisi lobortis luctus. Maecenas vehicula varius massa, eu dapibus sem commodo vel.", - "articleType": 1, - "publisher": "airmonitor", - "publishedAt": "2024-04-27T11:45:27.312Z", - "lastEditedAt": "2024-04-27T11:45:27.312Z", - "media": [] - }, - { - "id": "Gl3r9WuP", - "title": "The Genetics of Pollen Allergy: Research in New Zealand", - "subtitle": "Exploring genetic links", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis nisl ut ex pharetra, in pretium lacus auctor. Maecenas euismod ex ac metus tincidunt, ac sollicitudin purus finibus.", - "articleType": 1, - "publisher": "airmonitor", - "publishedAt": "2024-04-28T15:00:12.456Z", - "lastEditedAt": "2024-04-28T15:00:12.456Z", - "media": [] - }, - { - "id": "Vh5k3YpW", - "title": "Long-Term Trends in New Zealand's Airborne Pollen", - "subtitle": "A research overview", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer tincidunt, libero ac gravida ullamcorper, libero nisi lacinia odio, in facilisis eros nulla non ex. Sed vel vestibulum arcu.", - "articleType": 1, - "publisher": "airmonitor", - "publishedAt": "2024-05-10T10:45:15.789Z", - "lastEditedAt": "2024-05-10T10:45:15.789Z", - "media": [] - }, - { - "id": "Nr3v7WxQ", - "title": "Research Finds Correlation Between Pollen and Respiratory Issues", - "subtitle": "New Zealand study", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt dolor in mauris bibendum congue. Donec ut ante mauris. Phasellus luctus est in nisi commodo viverra. Nullam fermentum facilisis dui at posuere.", - "articleType": 1, - "publisher": "airmonitor", - "publishedAt": "2024-05-08T12:55:27.125Z", - "lastEditedAt": "2024-05-08T12:55:27.125Z", - "media": [] - }, - { - "id": "Rk7t8TjW", - "title": "Air Quality and Pollen Levels: New Zealand Study", - "subtitle": "A detailed report", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris gravida metus et urna fringilla, in vestibulum ex aliquet. Vestibulum egestas malesuada tellus in faucibus. Curabitur volutpat finibus libero vel aliquet.", - "articleType": 1, - "publisher": "airmonitor", - "publishedAt": "2024-05-02T13:45:28.674Z", - "lastEditedAt": "2024-05-02T13:45:28.674Z", - "media": [] - }, - { - "id": "Hj8t4ZqO", - "title": "New Zealand's Efforts in Pollen Monitoring and Research", - "subtitle": "Advancements and outcomes", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean sit amet odio felis. Cras et dui sed magna pharetra vehicula. Phasellus eu risus ligula. Curabitur et orci nec orci ullamcorper venenatis.", - "articleType": 1, - "publisher": "airmonitor", - "publishedAt": "2024-05-04T14:10:34.789Z", - "lastEditedAt": "2024-05-04T14:10:34.789Z", - "media": [] - }, - { - "id": "Qk3v6RtS", - "title": "The Role of Trees in New Zealand's Pollen Production", - "subtitle": "A comprehensive study", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam posuere nulla ut magna tristique, non euismod elit elementum. In hac habitasse platea dictumst. Donec vel lorem erat.", - "articleType": 1, - "publisher": "airmonitor", - "publishedAt": "2024-05-12T09:25:19.214Z", - "lastEditedAt": "2024-05-12T09:25:19.214Z", - "media": [] - }, - { - "id": "Yq8r9ZqW", - "title": "Understanding the Genetic Predisposition to Pollen Allergies", - "subtitle": "New Zealand research", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse potenti. Aliquam ac lorem vel urna interdum consequat. Donec feugiat risus sed sapien viverra, a fermentum ligula feugiat. Curabitur ac lacus euismod, luctus ligula a, venenatis velit.", - "articleType": 1, - "publisher": "airmonitor", - "publishedAt": "2024-05-09T10:30:21.789Z", - "lastEditedAt": "2024-05-09T10:30:21.789Z", - "media": [] - }, - { - "id": "Nj6t3KlS", - "title": "New Zealand's Pollen and Climate Change: Research Perspectives", - "subtitle": "Exploring the links", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur id nunc placerat, fringilla est a, efficitur purus. Vestibulum nec libero ut nunc ultricies consectetur. Cras malesuada elementum est ut tristique.", - "articleType": 1, - "publisher": "airmonitor", - "publishedAt": "2024-05-11T11:12:32.365Z", - "lastEditedAt": "2024-05-11T11:12:32.365Z", - "media": [] - }, - { - "id": "Vr4v8JkL", - "title": "Impact of Agricultural Practices on Pollen Emissions", - "subtitle": "New Zealand's findings", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec efficitur laoreet dolor, vel fringilla tortor porttitor ac. Suspendisse eget dignissim metus, et cursus est. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.", - "articleType": 1, - "publisher": "airmonitor", - "publishedAt": "2024-04-29T11:35:27.342Z", - "lastEditedAt": "2024-04-29T11:35:27.342Z", - "media": [] - }, - { - "id": "Tp3g8KvQ", - "title": "New Zealand's Initiatives in Airborne Pollen Management", - "subtitle": "Effective strategies", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi feugiat, enim ut ultrices vehicula, nisi metus gravida sapien, sed facilisis tortor ante id nibh. Proin varius, quam vel varius placerat, ligula lectus maximus est, vel sodales odio sapien at est.", - "articleType": 1, - "publisher": "climatewatch", - "publishedAt": "2024-05-06T12:40:28.450Z", - "lastEditedAt": "2024-05-06T12:40:28.450Z", - "media": [] - }, - { - "id": "Jq2n6BrK", - "title": "New Zealand's Indigenous Plants and Pollen Production", - "subtitle": "Research reveals insights", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent interdum arcu et elit malesuada, quis sodales velit suscipit. In hac habitasse platea dictumst. Donec varius quam ut est gravida, at tincidunt nisi egestas.", - "articleType": 1, - "publisher": "climatewatch", - "publishedAt": "2024-04-28T10:25:23.978Z", - "lastEditedAt": "2024-04-28T10:25:23.978Z", - "media": [] - }, - { - "id": "Wv3q7TpN", - "title": "Seasonal Patterns of Pollen in New Zealand", - "subtitle": "Detailed research analysis", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur in sapien nec leo fermentum accumsan. Donec nec aliquet magna. Nam tincidunt nisi et erat varius, sed ultrices erat fringilla. Proin suscipit lacus velit, vel vehicula neque tincidunt at.", - "articleType": 1, - "publisher": "climatewatch", - "publishedAt": "2024-05-08T09:20:38.512Z", - "lastEditedAt": "2024-05-08T09:20:38.512Z", - "media": [] - }, - { - "id": "Yt3p9XqK", - "title": "The Economic Impact of Pollen-Related Health Issues in New Zealand", - "subtitle": "Research highlights costs", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed viverra nunc quis ex efficitur, in vehicula lorem blandit. Sed fringilla diam vel orci accumsan, non dapibus est dapibus. Maecenas placerat vestibulum risus id placerat.", - "articleType": 1, - "publisher": "climatewatch", - "publishedAt": "2024-05-11T15:00:23.342Z", - "lastEditedAt": "2024-05-11T15:00:23.342Z", - "media": [] - }, - { - "id": "Jk3v8TrW", - "title": "New Zealand's Pollen Season Forecast: Implications for Public Health", - "subtitle": "What to expect", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse porttitor ante nec sapien viverra, nec facilisis purus hendrerit. Vestibulum convallis dapibus elit, ut tristique nulla tempor a. Nam varius justo vel nunc luctus, vitae tempor tortor ultricies.", - "articleType": 1, - "publisher": "climatewatch", - "publishedAt": "2024-05-07T14:45:29.987Z", - "lastEditedAt": "2024-05-07T14:45:29.987Z", - "media": [] - }, - { - "id": "Gv4p9KqW", - "title": "The Role of Climate in New Zealand's Pollen Season", - "subtitle": "Research delves deeper", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam quis nisi eget lorem varius scelerisque. Sed elementum, orci a gravida placerat, libero lorem volutpat ligula, sed tincidunt odio mi a orci.", - "articleType": 1, - "publisher": "climatewatch", - "publishedAt": "2024-05-05T15:30:17.324Z", - "lastEditedAt": "2024-05-05T15:30:17.324Z", - "media": [] - }, - { - "id": "Pq8j9KlL", - "title": "New Zealand's Strategy for Reducing Pollen Exposure", - "subtitle": "Effective public measures", - "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla facilisi. Praesent tincidunt volutpat nisl sit amet luctus. Maecenas vel ante vitae nunc placerat aliquet. Suspendisse nec dolor malesuada, hendrerit ante vel, placerat est.", - "articleType": 1, - "publisher": "climatewatch", - "publishedAt": "2024-05-10T13:00:23.112Z", - "lastEditedAt": "2024-05-10T13:00:23.112Z", - "media": [] - } + { + "id": "Vj4n2GqB", + "title": "New Zealand Researchers Analyze Pollen Data Over the Last Decade", + "subtitle": "Climate and allergy links", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed vel sem vel augue scelerisque fermentum at vel justo. Suspendisse venenatis, libero id cursus tempor, urna sapien finibus nunc, eget malesuada neque nunc non erat.", + "articleType": 1, + "publisher": "nzhealth", + "publishedAt": "2024-05-04T14:00:34.321Z", + "lastEditedAt": "2024-05-04T14:00:34.321Z", + "media": [] + }, + { + "id": "Zh6j2KrW", + "title": "Impact of Urbanization on New Zealand's Pollen Levels", + "subtitle": "Study explores potential causes", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur varius magna sit amet tellus volutpat, non cursus nisi tristique. Vestibulum fringilla nibh nec felis sodales, ut auctor eros vehicula. Phasellus tristique elit nec ex vehicula, at vehicula turpis interdum.", + "articleType": 1, + "publisher": "nzhealth", + "publishedAt": "2024-04-29T09:45:27.789Z", + "lastEditedAt": "2024-04-29T09:45:27.789Z", + "media": [] + }, + { + "id": "Bq8j2XkZ", + "title": "Airborne Pollen Trends: Insights from New Zealand's Agricultural Sectors", + "subtitle": "New perspectives", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla facilisi. Suspendisse tempor est sapien, sit amet scelerisque erat scelerisque in. In hac habitasse platea dictumst. Aenean quis libero a sem laoreet consectetur.", + "articleType": 1, + "publisher": "nzhealth", + "publishedAt": "2024-05-06T10:25:31.654Z", + "lastEditedAt": "2024-05-06T10:25:31.654Z", + "media": [] + }, + { + "id": "Rj9k6BtO", + "title": "Pollen Types and Health Effects in New Zealand: A Comparative Study", + "subtitle": "Detailed research findings", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce tincidunt facilisis arcu, non posuere tortor fringilla eu. Suspendisse potenti. Sed vel libero ullamcorper, vulputate augue quis, condimentum est.", + "articleType": 1, + "publisher": "nzhealth", + "publishedAt": "2024-05-12T11:50:21.789Z", + "lastEditedAt": "2024-05-12T11:50:21.789Z", + "media": [] + }, + { + "id": "Xk3g9YpW", + "title": "New Zealand's Climate and Pollen Season: Research Insights", + "subtitle": "The climate impact", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lacinia quam sed libero hendrerit bibendum. Sed posuere eros id dapibus vehicula. Aenean varius lorem sed ligula posuere, sed accumsan velit scelerisque.", + "articleType": 1, + "publisher": "nzhealth", + "publishedAt": "2024-05-05T13:12:36.455Z", + "lastEditedAt": "2024-05-05T13:12:36.455Z", + "media": [] + }, + { + "id": "Pz8m7XkA", + "title": "Understanding Pollen Dispersion Patterns in New Zealand", + "subtitle": "Research reveals new trends", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vestibulum justo nisi, non bibendum mi pretium et. Donec commodo turpis sed lectus eleifend, at vulputate justo sollicitudin.", + "articleType": 1, + "publisher": "nzhealth", + "publishedAt": "2024-04-26T08:00:14.784Z", + "lastEditedAt": "2024-04-26T08:00:14.784Z", + "media": [] + }, + { + "id": "Ky2n7TrE", + "title": "Airborne Pollen Study Links Allergens to Increased Asthma Cases", + "subtitle": "New Zealand research findings", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed hendrerit velit vitae magna elementum, vel tincidunt mauris gravida. Nulla vel mi a dolor ultrices convallis vel et magna.", + "articleType": 1, + "publisher": "airmonitor", + "publishedAt": "2024-05-03T13:32:45.912Z", + "lastEditedAt": "2024-05-03T13:32:45.912Z", + "media": [] + }, + { + "id": "Vw4g2XkP", + "title": "New Zealand's Pollen Exposure: The Role of Vegetation Types", + "subtitle": "Findings on plant influence", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin varius arcu ut facilisis blandit. Integer vel massa vel nisi lobortis luctus. Maecenas vehicula varius massa, eu dapibus sem commodo vel.", + "articleType": 1, + "publisher": "airmonitor", + "publishedAt": "2024-04-27T11:45:27.312Z", + "lastEditedAt": "2024-04-27T11:45:27.312Z", + "media": [] + }, + { + "id": "Gl3r9WuP", + "title": "The Genetics of Pollen Allergy: Research in New Zealand", + "subtitle": "Exploring genetic links", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis nisl ut ex pharetra, in pretium lacus auctor. Maecenas euismod ex ac metus tincidunt, ac sollicitudin purus finibus.", + "articleType": 1, + "publisher": "airmonitor", + "publishedAt": "2024-04-28T15:00:12.456Z", + "lastEditedAt": "2024-04-28T15:00:12.456Z", + "media": [] + }, + { + "id": "Vh5k3YpW", + "title": "Long-Term Trends in New Zealand's Airborne Pollen", + "subtitle": "A research overview", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer tincidunt, libero ac gravida ullamcorper, libero nisi lacinia odio, in facilisis eros nulla non ex. Sed vel vestibulum arcu.", + "articleType": 1, + "publisher": "airmonitor", + "publishedAt": "2024-05-10T10:45:15.789Z", + "lastEditedAt": "2024-05-10T10:45:15.789Z", + "media": [] + }, + { + "id": "Nr3v7WxQ", + "title": "Research Finds Correlation Between Pollen and Respiratory Issues", + "subtitle": "New Zealand study", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tincidunt dolor in mauris bibendum congue. Donec ut ante mauris. Phasellus luctus est in nisi commodo viverra. Nullam fermentum facilisis dui at posuere.", + "articleType": 1, + "publisher": "airmonitor", + "publishedAt": "2024-05-08T12:55:27.125Z", + "lastEditedAt": "2024-05-08T12:55:27.125Z", + "media": [] + }, + { + "id": "Rk7t8TjW", + "title": "Air Quality and Pollen Levels: New Zealand Study", + "subtitle": "A detailed report", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris gravida metus et urna fringilla, in vestibulum ex aliquet. Vestibulum egestas malesuada tellus in faucibus. Curabitur volutpat finibus libero vel aliquet.", + "articleType": 1, + "publisher": "airmonitor", + "publishedAt": "2024-05-02T13:45:28.674Z", + "lastEditedAt": "2024-05-02T13:45:28.674Z", + "media": [] + }, + { + "id": "Hj8t4ZqO", + "title": "New Zealand's Efforts in Pollen Monitoring and Research", + "subtitle": "Advancements and outcomes", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean sit amet odio felis. Cras et dui sed magna pharetra vehicula. Phasellus eu risus ligula. Curabitur et orci nec orci ullamcorper venenatis.", + "articleType": 1, + "publisher": "airmonitor", + "publishedAt": "2024-05-04T14:10:34.789Z", + "lastEditedAt": "2024-05-04T14:10:34.789Z", + "media": [] + }, + { + "id": "Qk3v6RtS", + "title": "The Role of Trees in New Zealand's Pollen Production", + "subtitle": "A comprehensive study", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam posuere nulla ut magna tristique, non euismod elit elementum. In hac habitasse platea dictumst. Donec vel lorem erat.", + "articleType": 1, + "publisher": "airmonitor", + "publishedAt": "2024-05-12T09:25:19.214Z", + "lastEditedAt": "2024-05-12T09:25:19.214Z", + "media": [] + }, + { + "id": "Yq8r9ZqW", + "title": "Understanding the Genetic Predisposition to Pollen Allergies", + "subtitle": "New Zealand research", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse potenti. Aliquam ac lorem vel urna interdum consequat. Donec feugiat risus sed sapien viverra, a fermentum ligula feugiat. Curabitur ac lacus euismod, luctus ligula a, venenatis velit.", + "articleType": 1, + "publisher": "airmonitor", + "publishedAt": "2024-05-09T10:30:21.789Z", + "lastEditedAt": "2024-05-09T10:30:21.789Z", + "media": [] + }, + { + "id": "Nj6t3KlS", + "title": "New Zealand's Pollen and Climate Change: Research Perspectives", + "subtitle": "Exploring the links", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur id nunc placerat, fringilla est a, efficitur purus. Vestibulum nec libero ut nunc ultricies consectetur. Cras malesuada elementum est ut tristique.", + "articleType": 1, + "publisher": "airmonitor", + "publishedAt": "2024-05-11T11:12:32.365Z", + "lastEditedAt": "2024-05-11T11:12:32.365Z", + "media": [] + }, + { + "id": "Vr4v8JkL", + "title": "Impact of Agricultural Practices on Pollen Emissions", + "subtitle": "New Zealand's findings", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec efficitur laoreet dolor, vel fringilla tortor porttitor ac. Suspendisse eget dignissim metus, et cursus est. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.", + "articleType": 1, + "publisher": "airmonitor", + "publishedAt": "2024-04-29T11:35:27.342Z", + "lastEditedAt": "2024-04-29T11:35:27.342Z", + "media": [] + }, + { + "id": "Tp3g8KvQ", + "title": "New Zealand's Initiatives in Airborne Pollen Management", + "subtitle": "Effective strategies", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi feugiat, enim ut ultrices vehicula, nisi metus gravida sapien, sed facilisis tortor ante id nibh. Proin varius, quam vel varius placerat, ligula lectus maximus est, vel sodales odio sapien at est.", + "articleType": 1, + "publisher": "climatewatch", + "publishedAt": "2024-05-06T12:40:28.450Z", + "lastEditedAt": "2024-05-06T12:40:28.450Z", + "media": [] + }, + { + "id": "Jq2n6BrK", + "title": "New Zealand's Indigenous Plants and Pollen Production", + "subtitle": "Research reveals insights", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent interdum arcu et elit malesuada, quis sodales velit suscipit. In hac habitasse platea dictumst. Donec varius quam ut est gravida, at tincidunt nisi egestas.", + "articleType": 1, + "publisher": "climatewatch", + "publishedAt": "2024-04-28T10:25:23.978Z", + "lastEditedAt": "2024-04-28T10:25:23.978Z", + "media": [] + }, + { + "id": "Wv3q7TpN", + "title": "Seasonal Patterns of Pollen in New Zealand", + "subtitle": "Detailed research analysis", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur in sapien nec leo fermentum accumsan. Donec nec aliquet magna. Nam tincidunt nisi et erat varius, sed ultrices erat fringilla. Proin suscipit lacus velit, vel vehicula neque tincidunt at.", + "articleType": 1, + "publisher": "climatewatch", + "publishedAt": "2024-05-08T09:20:38.512Z", + "lastEditedAt": "2024-05-08T09:20:38.512Z", + "media": [] + }, + { + "id": "Yt3p9XqK", + "title": "The Economic Impact of Pollen-Related Health Issues in New Zealand", + "subtitle": "Research highlights costs", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed viverra nunc quis ex efficitur, in vehicula lorem blandit. Sed fringilla diam vel orci accumsan, non dapibus est dapibus. Maecenas placerat vestibulum risus id placerat.", + "articleType": 1, + "publisher": "climatewatch", + "publishedAt": "2024-05-11T15:00:23.342Z", + "lastEditedAt": "2024-05-11T15:00:23.342Z", + "media": [] + }, + { + "id": "Jk3v8TrW", + "title": "New Zealand's Pollen Season Forecast: Implications for Public Health", + "subtitle": "What to expect", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse porttitor ante nec sapien viverra, nec facilisis purus hendrerit. Vestibulum convallis dapibus elit, ut tristique nulla tempor a. Nam varius justo vel nunc luctus, vitae tempor tortor ultricies.", + "articleType": 1, + "publisher": "climatewatch", + "publishedAt": "2024-05-07T14:45:29.987Z", + "lastEditedAt": "2024-05-07T14:45:29.987Z", + "media": [] + }, + { + "id": "Gv4p9KqW", + "title": "The Role of Climate in New Zealand's Pollen Season", + "subtitle": "Research delves deeper", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam quis nisi eget lorem varius scelerisque. Sed elementum, orci a gravida placerat, libero lorem volutpat ligula, sed tincidunt odio mi a orci.", + "articleType": 1, + "publisher": "climatewatch", + "publishedAt": "2024-05-05T15:30:17.324Z", + "lastEditedAt": "2024-05-05T15:30:17.324Z", + "media": [] + }, + { + "id": "Pq8j9KlL", + "title": "New Zealand's Strategy for Reducing Pollen Exposure", + "subtitle": "Effective public measures", + "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla facilisi. Praesent tincidunt volutpat nisl sit amet luctus. Maecenas vel ante vitae nunc placerat aliquet. Suspendisse nec dolor malesuada, hendrerit ante vel, placerat est.", + "articleType": 1, + "publisher": "climatewatch", + "publishedAt": "2024-05-10T13:00:23.112Z", + "lastEditedAt": "2024-05-10T13:00:23.112Z", + "media": [] + } ] diff --git a/backend/src/repositories/memory/data/users.json b/backend/src/repositories/memory/data/users.json index 8a9379e9..55c3efcf 100644 --- a/backend/src/repositories/memory/data/users.json +++ b/backend/src/repositories/memory/data/users.json @@ -1,30 +1,30 @@ [ - { - "username": "airmonitor", - "email": "airmonitor@example.com", - "displayName": "Sarah Davis", - "verified": true, - "registeredAt": "2024-03-16T00:00:00.000000Z" - }, - { - "username": "nzhealth", - "email": "nzhealth@example.com", - "displayName": "John Williams", - "verified": true, - "registeredAt": "2024-03-11T00:00:00.000000Z" - }, - { - "username": "kiwihealth", - "email": "kiwihealth@example.com", - "displayName": "Robert Garcia", - "verified": true, - "registeredAt": "2024-03-08T00:00:00.000000Z" - }, - { - "username": "climatewatch", - "email": "climatewatch@example.com", - "displayName": "Emma Williams", - "verified": true, - "registeredAt": "2024-04-23T00:00:00.000000Z" - } + { + "username": "airmonitor", + "email": "airmonitor@example.com", + "displayName": "Sarah Davis", + "verified": true, + "registeredAt": "2024-03-16T00:00:00.000000Z" + }, + { + "username": "nzhealth", + "email": "nzhealth@example.com", + "displayName": "John Williams", + "verified": true, + "registeredAt": "2024-03-11T00:00:00.000000Z" + }, + { + "username": "kiwihealth", + "email": "kiwihealth@example.com", + "displayName": "Robert Garcia", + "verified": true, + "registeredAt": "2024-03-08T00:00:00.000000Z" + }, + { + "username": "climatewatch", + "email": "climatewatch@example.com", + "displayName": "Emma Williams", + "verified": true, + "registeredAt": "2024-04-23T00:00:00.000000Z" + } ] diff --git a/backend/src/repositories/memory/sorters/Sorter.ts b/backend/src/repositories/memory/sorters/Sorter.ts index f9ea3088..1841a27b 100644 --- a/backend/src/repositories/memory/sorters/Sorter.ts +++ b/backend/src/repositories/memory/sorters/Sorter.ts @@ -1,6 +1,3 @@ -import { SortOptions } from "../../../util/types/util.types"; +import { SortOptions } from "../../../util/types/util.types" -export type Sorter> = ( - arr: T[], - sortOptions?: K[], -) => T[]; +export type Sorter> = (arr: T[], sortOptions?: K[]) => T[] diff --git a/backend/src/repositories/memory/sorters/article.sorter.ts b/backend/src/repositories/memory/sorters/article.sorter.ts index d4d0d6b3..5fc2acc3 100644 --- a/backend/src/repositories/memory/sorters/article.sorter.ts +++ b/backend/src/repositories/memory/sorters/article.sorter.ts @@ -1 +1 @@ -export type ArticleSortFields = "publishedAt" | "lastEditedAt"; +export type ArticleSortFields = "publishedAt" | "lastEditedAt" diff --git a/backend/src/repositories/memory/sorters/user.sorter.ts b/backend/src/repositories/memory/sorters/user.sorter.ts index e65609f1..31f5b51f 100644 --- a/backend/src/repositories/memory/sorters/user.sorter.ts +++ b/backend/src/repositories/memory/sorters/user.sorter.ts @@ -1 +1 @@ -export type UserSortFields = "registeredAt"; +export type UserSortFields = "registeredAt" diff --git a/backend/src/repositories/mongo/MongoRepository.ts b/backend/src/repositories/mongo/MongoRepository.ts index 5d65a5f7..4336be6f 100644 --- a/backend/src/repositories/mongo/MongoRepository.ts +++ b/backend/src/repositories/mongo/MongoRepository.ts @@ -1,269 +1,237 @@ -import IRepository from "../IRepository"; -import { Article, ArticleType, User } from "@aapc/types"; -import { - ArrayResult, - ArrayResultOptions, - Nullable, - SortOptions, -} from "../../util/types/util.types"; -import { ArticleSortFields } from "../memory/sorters/article.sorter"; -import { UserSortFields } from "../memory/sorters/user.sorter"; -import { - Collection, - Db, - Document, - Filter, - FindCursor, - MongoClient, - ServerApiVersion, - WithId, -} from "mongodb"; +import IRepository from "../IRepository" +import { Article, ArticleType, User } from "@aapc/types" +import { ArrayResult, ArrayResultOptions, Nullable, SortOptions } from "../../util/types/util.types" +import { ArticleSortFields } from "../memory/sorters/article.sorter" +import { UserSortFields } from "../memory/sorters/user.sorter" +import { Collection, Db, Document, Filter, FindCursor, MongoClient, ServerApiVersion, WithId } from "mongodb" export default class MongoRepository implements IRepository { - private readonly db: Db; - private readonly articles: Collection; - private readonly users: Collection; - - constructor(uri: string) { - this.db = new MongoClient(uri, { serverApi: ServerApiVersion.v1 }).db( - "AAPC", - ); - this.articles = this.db.collection("Articles"); - this.users = this.db.collection("Users"); - } + private readonly db: Db + private readonly articles: Collection + private readonly users: Collection + + constructor(uri: string) { + this.db = new MongoClient(uri, { serverApi: ServerApiVersion.v1 }).db("AAPC") + this.articles = this.db.collection("Articles") + this.users = this.db.collection("Users") + } - async fetchMongoDocuments( - f: FindCursor>, - options?: ArrayResultOptions>, - ): Promise[]> { - const a: WithId[] = []; - if (options) { - for await (const document of f - .skip(options.startFrom ?? 0) - .limit(options.maxResults ?? Infinity)) { - a.push(document); - } - } else { - for await (const document of f) { - a.push(document); - } + async fetchMongoDocuments( + f: FindCursor>, + options?: ArrayResultOptions> + ): Promise[]> { + const a: WithId[] = [] + if (options) { + for await (const document of f.skip(options.startFrom ?? 0).limit(options.maxResults ?? Infinity)) { + a.push(document) + } + } else { + for await (const document of f) { + a.push(document) + } + } + return a } - return a; - } - async documentToArticle(d: WithId): Promise
{ - const u = (await this.getUserByUsername(d.publisher)) ?? new User(); - const a = new Article(d); - a.publisher = u; - return a; - } + async documentToArticle(d: WithId): Promise
{ + const u = (await this.getUserByUsername(d.publisher)) ?? new User() + const a = new Article(d) + a.publisher = u + return a + } - articleToDocument(a: Article): Promise { - const aObj = a; - aObj.publisher = a.publisher.username; - return aObj; - } + articleToDocument(a: Article): Promise { + const aObj = a + aObj.publisher = a.publisher.username + return aObj + } - async createNews(a: Article): Promise
{ - await this.articles.insertOne(this.articleToDocument(a)); - return a; - } + async createNews(a: Article): Promise
{ + await this.articles.insertOne(this.articleToDocument(a)) + return a + } - async createResearch(a: Article): Promise
{ - await this.articles.insertOne(this.articleToDocument(a)); - return a; - } + async createResearch(a: Article): Promise
{ + await this.articles.insertOne(this.articleToDocument(a)) + return a + } - async createUser(u: User): Promise { - await this.users.insertOne(u); - return u; - } + async createUser(u: User): Promise { + await this.users.insertOne(u) + return u + } - async deleteNews(id: string): Promise { - await this.articles.deleteOne({ id: id, articleType: ArticleType.news }); - } + async deleteNews(id: string): Promise { + await this.articles.deleteOne({ id: id, articleType: ArticleType.news }) + } - async deleteResearch(id: string): Promise { - await this.articles.deleteOne({ - id: id, - articleType: ArticleType.research, - }); - } + async deleteResearch(id: string): Promise { + await this.articles.deleteOne({ + id: id, + articleType: ArticleType.research, + }) + } - async deleteUser(username: string): Promise { - await this.users.deleteOne({ username: username }); - } + async deleteUser(username: string): Promise { + await this.users.deleteOne({ username: username }) + } - async editNews(id: string, a: Article): Promise
{ - if (a.id !== id) { - throw TypeError("Article ID does not match provided ID"); + async editNews(id: string, a: Article): Promise
{ + if (a.id !== id) { + throw TypeError("Article ID does not match provided ID") + } + await this.articles.updateOne( + { + id: id, + articleType: ArticleType.news, + }, + this.articleToDocument(a) + ) + return a } - await this.articles.updateOne( - { - id: id, - articleType: ArticleType.news, - }, - this.articleToDocument(a), - ); - return a; - } - async editResearch(id: string, a: Article): Promise
{ - if (a.id !== id) { - throw TypeError("Article ID does not match provided ID"); + async editResearch(id: string, a: Article): Promise
{ + if (a.id !== id) { + throw TypeError("Article ID does not match provided ID") + } + await this.articles.updateOne( + { + id: id, + articleType: ArticleType.research, + }, + this.articleToDocument(a) + ) + return a } - await this.articles.updateOne( - { - id: id, - articleType: ArticleType.research, - }, - this.articleToDocument(a), - ); - return a; - } - async editUser(username: string, u: User): Promise { - await this.users.updateOne({ username: username }, u); - return u; - } + async editUser(username: string, u: User): Promise { + await this.users.updateOne({ username: username }, u) + return u + } - async getAllNews( - options?: ArrayResultOptions>, - ): Promise> { - const r: Article[] = []; - const q: Filter = { articleType: ArticleType.news }; - const rC = await this.articles.countDocuments(q); - const result = await this.fetchMongoDocuments( - this.articles.find(q), - options, - ); - for (const document of result) { - r.push(await this.documentToArticle(document)); + async getAllNews( + options?: ArrayResultOptions> + ): Promise> { + const r: Article[] = [] + const q: Filter = { articleType: ArticleType.news } + const rC = await this.articles.countDocuments(q) + const result = await this.fetchMongoDocuments(this.articles.find(q), options) + for (const document of result) { + r.push(await this.documentToArticle(document)) + } + return { + totalResults: rC, + results: r, + } } - return { - totalResults: rC, - results: r, - }; - } - async getAllResearch( - options?: ArrayResultOptions>, - ): Promise> { - const r: Article[] = []; - const q: Filter = { articleType: ArticleType.research }; - const rC = await this.articles.countDocuments(q); - const result = await this.fetchMongoDocuments( - this.articles.find(q), - options, - ); - for (const document of result) { - r.push(await this.documentToArticle(document)); + async getAllResearch( + options?: ArrayResultOptions> + ): Promise> { + const r: Article[] = [] + const q: Filter = { articleType: ArticleType.research } + const rC = await this.articles.countDocuments(q) + const result = await this.fetchMongoDocuments(this.articles.find(q), options) + for (const document of result) { + r.push(await this.documentToArticle(document)) + } + return { + totalResults: rC, + results: r, + } } - return { - totalResults: rC, - results: r, - }; - } - async getAllUsers( - options?: ArrayResultOptions>, - ): Promise> { - const r: User[] = []; - const rC = await this.users.countDocuments(); - const result = await this.fetchMongoDocuments(this.users.find(), options); - for (const document of result) { - r.push(new User(document)); + async getAllUsers(options?: ArrayResultOptions>): Promise> { + const r: User[] = [] + const rC = await this.users.countDocuments() + const result = await this.fetchMongoDocuments(this.users.find(), options) + for (const document of result) { + r.push(new User(document)) + } + return { + totalResults: rC, + results: r, + } } - return { - totalResults: rC, - results: r, - }; - } - async getNewsById(id: string): Promise> { - const n = await this.articles.findOne({ articleType: 0, id: id }); - if (n === null) { - return null; + async getNewsById(id: string): Promise> { + const n = await this.articles.findOne({ articleType: 0, id: id }) + if (n === null) { + return null + } + return await this.documentToArticle(n) } - return await this.documentToArticle(n); - } - async getResearchById(id: string): Promise> { - const r = await this.articles.findOne({ articleType: 1, id: id }); - if (r === null) { - return null; + async getResearchById(id: string): Promise> { + const r = await this.articles.findOne({ articleType: 1, id: id }) + if (r === null) { + return null + } + return await this.documentToArticle(r) } - return await this.documentToArticle(r); - } - async getUserByUsername(username: string): Promise> { - const u = await this.users.findOne({ username: username }); - if (u === null) { - return null; + async getUserByUsername(username: string): Promise> { + const u = await this.users.findOne({ username: username }) + if (u === null) { + return null + } + return new User(u) } - return new User(u); - } - async searchNewsByTitle( - title: string, - options?: ArrayResultOptions>, - ): Promise> { - const r: Article[] = []; - const q: Filter = { - articleType: ArticleType.news, - title: { $regex: title }, - }; - const rC: number = await this.articles.countDocuments(q); - const result = await this.fetchMongoDocuments( - this.articles.find(q), - options, - ); - for (const document of result) { - r.push(await this.documentToArticle(document)); + async searchNewsByTitle( + title: string, + options?: ArrayResultOptions> + ): Promise> { + const r: Article[] = [] + const q: Filter = { + articleType: ArticleType.news, + title: { $regex: title }, + } + const rC: number = await this.articles.countDocuments(q) + const result = await this.fetchMongoDocuments(this.articles.find(q), options) + for (const document of result) { + r.push(await this.documentToArticle(document)) + } + return { + totalResults: rC, + results: r, + } } - return { - totalResults: rC, - results: r, - }; - } - async searchResearchByTitle( - title: string, - options?: ArrayResultOptions>, - ): Promise> { - const r: Article[] = []; - const q: Filter = { - articleType: ArticleType.research, - title: { $regex: title }, - }; - const rC: number = await this.articles.countDocuments(q); - const result = await this.fetchMongoDocuments( - this.articles.find(q), - options, - ); - for (const document of result) { - r.push(await this.documentToArticle(document)); + async searchResearchByTitle( + title: string, + options?: ArrayResultOptions> + ): Promise> { + const r: Article[] = [] + const q: Filter = { + articleType: ArticleType.research, + title: { $regex: title }, + } + const rC: number = await this.articles.countDocuments(q) + const result = await this.fetchMongoDocuments(this.articles.find(q), options) + for (const document of result) { + r.push(await this.documentToArticle(document)) + } + return { + totalResults: rC, + results: r, + } } - return { - totalResults: rC, - results: r, - }; - } - async searchUserByUsername( - username: string, - options?: ArrayResultOptions>, - ): Promise> { - const r: User[] = []; - const q: Filter = { username: { $regex: username } }; - const rC = await this.users.countDocuments(q); - const result = await this.fetchMongoDocuments(this.users.find(q), options); - for (const document of result) { - r.push(new User(document)); + async searchUserByUsername( + username: string, + options?: ArrayResultOptions> + ): Promise> { + const r: User[] = [] + const q: Filter = { username: { $regex: username } } + const rC = await this.users.countDocuments(q) + const result = await this.fetchMongoDocuments(this.users.find(q), options) + for (const document of result) { + r.push(new User(document)) + } + return { + totalResults: rC, + results: r, + } } - return { - totalResults: rC, - results: r, - }; - } } diff --git a/backend/src/repositories/repository.ts b/backend/src/repositories/repository.ts index 73fc35bd..411234f0 100644 --- a/backend/src/repositories/repository.ts +++ b/backend/src/repositories/repository.ts @@ -1,42 +1,42 @@ -import dotenv from "dotenv"; -import IRepository from "./IRepository"; -import MemoryRepository from "./memory/MemoryRepository"; -import MongoRepository from "./mongo/MongoRepository"; +import dotenv from "dotenv" +import IRepository from "./IRepository" +import MemoryRepository from "./memory/MemoryRepository" +import MongoRepository from "./mongo/MongoRepository" -dotenv.config(); +dotenv.config() -let repo: "memory" | "mongo-dev" | "mongo-prod"; +let repo: "memory" | "mongo-dev" | "mongo-prod" switch (process.env.ENV) { - case "LOCAL": { - repo = "memory"; - break; - } - case "DEV": { - repo = "mongo-dev"; - break; - } - case "PROD": { - repo = "mongo-prod"; - break; - } - default: { - repo = "memory"; - } + case "LOCAL": { + repo = "memory" + break + } + case "DEV": { + repo = "mongo-dev" + break + } + case "PROD": { + repo = "mongo-prod" + break + } + default: { + repo = "memory" + } } -export let DB: IRepository; +export let DB: IRepository switch (repo) { - case "mongo-dev": { - DB = new MongoRepository(process.env.MONGO_DEV_URI ?? ""); - break; - } - case "mongo-prod": { - DB = new MongoRepository(process.env.MONGO_PROD_URI ?? ""); - break; - } - default: - DB = new MemoryRepository(); - break; + case "mongo-dev": { + DB = new MongoRepository(process.env.MONGO_DEV_URI ?? "") + break + } + case "mongo-prod": { + DB = new MongoRepository(process.env.MONGO_PROD_URI ?? "") + break + } + default: + DB = new MemoryRepository() + break } diff --git a/backend/src/routes/news.router.ts b/backend/src/routes/news.router.ts index 9950c1f4..148e8853 100644 --- a/backend/src/routes/news.router.ts +++ b/backend/src/routes/news.router.ts @@ -1,20 +1,20 @@ -import express, { Router } from "express"; -import NewsController from "../controllers/news.controller"; -import expressAsyncHandler from "express-async-handler"; +import express, { Router } from "express" +import NewsController from "../controllers/news.controller" +import expressAsyncHandler from "express-async-handler" export default class NewsRouter { - static url = "/content/news"; + static url = "/content/news" - static router(): Router { - const router = express.Router(); + static router(): Router { + const router = express.Router() - router.get("/", expressAsyncHandler(NewsController.getNews)); - router.post("/", expressAsyncHandler(NewsController.createNews)); + router.get("/", expressAsyncHandler(NewsController.getNews)) + router.post("/", expressAsyncHandler(NewsController.createNews)) - router.get("/:id", expressAsyncHandler(NewsController.getNewsById)); - router.put("/:id", expressAsyncHandler(NewsController.editNews)); - router.delete("/:id", expressAsyncHandler(NewsController.deleteNews)); + router.get("/:id", expressAsyncHandler(NewsController.getNewsById)) + router.put("/:id", expressAsyncHandler(NewsController.editNews)) + router.delete("/:id", expressAsyncHandler(NewsController.deleteNews)) - return router; - } + return router + } } diff --git a/backend/src/routes/research.router.ts b/backend/src/routes/research.router.ts index b4ba6499..667d7a34 100644 --- a/backend/src/routes/research.router.ts +++ b/backend/src/routes/research.router.ts @@ -1,23 +1,20 @@ -import express, { Router } from "express"; -import ResearchController from "../controllers/research.controller"; -import expressAsyncHandler from "express-async-handler"; +import express, { Router } from "express" +import ResearchController from "../controllers/research.controller" +import expressAsyncHandler from "express-async-handler" export default class ResearchRouter { - static url = "/content/research"; + static url = "/content/research" - static router(): Router { - const router = express.Router(); + static router(): Router { + const router = express.Router() - router.get("/", expressAsyncHandler(ResearchController.getResearch)); - router.post("/", expressAsyncHandler(ResearchController.createResearch)); + router.get("/", expressAsyncHandler(ResearchController.getResearch)) + router.post("/", expressAsyncHandler(ResearchController.createResearch)) - router.get("/:id", expressAsyncHandler(ResearchController.getResearchById)); - router.put("/:id", expressAsyncHandler(ResearchController.editResearch)); - router.delete( - "/:id", - expressAsyncHandler(ResearchController.deleteResearch), - ); + router.get("/:id", expressAsyncHandler(ResearchController.getResearchById)) + router.put("/:id", expressAsyncHandler(ResearchController.editResearch)) + router.delete("/:id", expressAsyncHandler(ResearchController.deleteResearch)) - return router; - } + return router + } } diff --git a/backend/src/util/const.ts b/backend/src/util/const.ts index 186d93b8..5f80226b 100644 --- a/backend/src/util/const.ts +++ b/backend/src/util/const.ts @@ -1,11 +1,11 @@ -import { User } from "@aapc/types"; +import { User } from "@aapc/types" -export const DEFAULT_PER_PAGE = 15; +export const DEFAULT_PER_PAGE = 15 export const DUMMY_USER = new User({ - username: "foobar", - displayName: "John Doe", - email: "john.doe@example.com", - verified: true, - registeredAt: new Date().toISOString(), -}); + username: "foobar", + displayName: "John Doe", + email: "john.doe@example.com", + verified: true, + registeredAt: new Date().toISOString(), +}) diff --git a/backend/src/util/functions.ts b/backend/src/util/functions.ts index 5e216daa..7b129452 100644 --- a/backend/src/util/functions.ts +++ b/backend/src/util/functions.ts @@ -1,8 +1,8 @@ export function getRandomID(length: number = 8) { - let result = ""; - const characters = "abcdefghijklmnopqrstuvwxyz0123456789-_"; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * characters.length)); - } - return result; + let result = "" + const characters = "abcdefghijklmnopqrstuvwxyz0123456789-_" + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * characters.length)) + } + return result } diff --git a/backend/src/util/types/input.types.ts b/backend/src/util/types/input.types.ts index bcca4db7..34ddec43 100644 --- a/backend/src/util/types/input.types.ts +++ b/backend/src/util/types/input.types.ts @@ -1,93 +1,86 @@ -import { Article, ArticleType, IArticle, IUser, User } from "@aapc/types"; -import { getRandomID } from "../functions"; +import { Article, ArticleType, IArticle, IUser, User } from "@aapc/types" +import { getRandomID } from "../functions" export interface InputValidationError { - field: keyof T; - message: string; + field: keyof T + message: string } export interface IArticleIn - extends Omit< - IArticle, - "id" | "lastEditedAt" | "publishedAt" | "publisher" | "articleType" - > {} + extends Omit {} export interface IUserIn extends Omit {} class Validator { - errors: InputValidationError[] = []; + errors: InputValidationError[] = [] - checkMissing(obj: any, k: keyof T): any { - if (obj[k] === undefined) { - this.errors.push({ - field: k, - message: `Required attribute ${String(k)} not present in request body.`, - }); - return null; - } else { - return obj[k]; + checkMissing(obj: any, k: keyof T): any { + if (obj[k] === undefined) { + this.errors.push({ + field: k, + message: `Required attribute ${String(k)} not present in request body.`, + }) + return null + } else { + return obj[k] + } } - } } export class ArticleIn extends Validator implements IArticleIn { - title: string; - subtitle: string; - content: string; - media: string[]; + title: string + subtitle: string + content: string + media: string[] - constructor(obj: any) { - super(); - this.title = this.checkMissing(obj, "title"); - this.subtitle = this.checkMissing(obj, "subtitle"); - this.content = this.checkMissing(obj, "content"); - this.media = this.checkMissing(obj, "media"); - if (this.errors.length > 0) { - throw new TypeError(JSON.stringify(this.errors)); + constructor(obj: any) { + super() + this.title = this.checkMissing(obj, "title") + this.subtitle = this.checkMissing(obj, "subtitle") + this.content = this.checkMissing(obj, "content") + this.media = this.checkMissing(obj, "media") + if (this.errors.length > 0) { + throw new TypeError(JSON.stringify(this.errors)) + } } - } - toArticle( - articleType: ArticleType, - publisher: User, - articleID?: string, - ): Article { - return new Article({ - id: articleID ?? getRandomID(), // TODO: implement id checks - title: this.title, - subtitle: this.subtitle, - content: this.content, - media: this.media, - articleType: articleType, - publisher: publisher, - publishedAt: new Date().toISOString(), - lastEditedAt: new Date().toISOString(), - }); - } + toArticle(articleType: ArticleType, publisher: User, articleID?: string): Article { + return new Article({ + id: articleID ?? getRandomID(), // TODO: implement id checks + title: this.title, + subtitle: this.subtitle, + content: this.content, + media: this.media, + articleType: articleType, + publisher: publisher, + publishedAt: new Date().toISOString(), + lastEditedAt: new Date().toISOString(), + }) + } } export class UserIn extends Validator implements IUserIn { - username: string; - email: string; - displayName: string; + username: string + email: string + displayName: string - constructor(obj: any) { - super(); - this.username = this.checkMissing(obj, "username"); - this.email = this.checkMissing(obj, "email"); - this.displayName = this.checkMissing(obj, "displayName"); - if (this.errors.length > 0) { - throw new TypeError(JSON.stringify(this.errors)); + constructor(obj: any) { + super() + this.username = this.checkMissing(obj, "username") + this.email = this.checkMissing(obj, "email") + this.displayName = this.checkMissing(obj, "displayName") + if (this.errors.length > 0) { + throw new TypeError(JSON.stringify(this.errors)) + } } - } - toUser(): User { - return new User({ - username: this.username, - email: this.email, - displayName: this.displayName, - verified: false, - registeredAt: new Date().toISOString(), - }); - } + toUser(): User { + return new User({ + username: this.username, + email: this.email, + displayName: this.displayName, + verified: false, + registeredAt: new Date().toISOString(), + }) + } } diff --git a/backend/src/util/types/util.types.ts b/backend/src/util/types/util.types.ts index 79de47ad..9705ac63 100644 --- a/backend/src/util/types/util.types.ts +++ b/backend/src/util/types/util.types.ts @@ -1,17 +1,17 @@ -export type Nullable = T | null; +export type Nullable = T | null export interface ArrayResultOptions> { - startFrom?: number; - maxResults?: number; - sort?: T[]; + startFrom?: number + maxResults?: number + sort?: T[] } export interface SortOptions { - field: T; - descending?: boolean; + field: T + descending?: boolean } export interface ArrayResult { - totalResults: number; - results: T[]; + totalResults: number + results: T[] } diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 68c8b59d..a0455284 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -1,109 +1,109 @@ { - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + /* Language and Environment */ + "target": "es2016", + /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ - // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ - // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ - // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + /* Modules */ + "module": "commonjs", + /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + "resolveJsonModule": true, + /* Enable importing .json files. */ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./dist", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./dist", + /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, + /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, + /* Ensure that casing is correct in imports. */ /* Type Checking */ + "strict": true, + /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true + /* Skip type checking all .d.ts files. */ + } } diff --git a/backend/vercel.json b/backend/vercel.json index b02f3234..52e64b66 100644 --- a/backend/vercel.json +++ b/backend/vercel.json @@ -1,14 +1,14 @@ { - "builds": [ - { - "src": "dist/index.js", - "use": "@vercel/node" - } - ], - "rewrites": [ - { - "source": "/(.*)", - "destination": "/dist/index.js" - } - ] -} \ No newline at end of file + "builds": [ + { + "src": "dist/index.js", + "use": "@vercel/node" + } + ], + "rewrites": [ + { + "source": "/(.*)", + "destination": "/dist/index.js" + } + ] +} diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index bffb357a..1c2aa65d 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": "next/core-web-vitals" + "extends": "next/core-web-vitals" } diff --git a/frontend/.prettierignore b/frontend/.prettierignore new file mode 100644 index 00000000..28aff6b7 --- /dev/null +++ b/frontend/.prettierignore @@ -0,0 +1,18 @@ +/dist + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# misc +.DS_Store +*.pem + +# typescript +next-env.d.ts +.vercel diff --git a/frontend/README.md b/frontend/README.md index 21cd2f9d..51b46ae4 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -11,6 +11,7 @@ unique approach to styling to provide an efficient, and aesthetically pleasing w # Starting the Local Server Change directory to the frontend (only if you are currently in the root directory): + ```bash cd frontend ``` @@ -18,6 +19,7 @@ cd frontend ## Install Dependencies Install dependencies using `npm`: + ```bash npm i ``` @@ -34,17 +36,20 @@ Open [http://localhost:3001](http://localhost:3001) with your browser to access # Deployment Rules -- Any changes pushed to github on **any** branch will be deployed to Vercel Development Preview. This is not public. -- Any changes pushed on the `dev` branch will be deployed to the **development** environment ([https://dev.aapc-nz.org](https://dev.aapc-nz.org)). -- Any changes pushed on the `main` branch will be deployed to the **production** environment ([https://www.aapc-nz.org](https://aapc-nz.org)). +- Any changes pushed to github on **any** branch will be deployed to Vercel Development Preview. This is not public. +- Any changes pushed on the `dev` branch will be deployed to the **development** environment ([https://dev.aapc-nz.org](https://dev.aapc-nz.org)). +- Any changes pushed on the `main` branch will be deployed to the **production** environment ([https://www.aapc-nz.org](https://aapc-nz.org)). # Environments ### `LOCAL` + When running the frontend locally, the `ENV` will be `LOCAL`, and the backend endpoint URI will be configured to `http://localhost:3000`. ### `DEV` + On [https://dev.aapc-nz.org](https://dev.aapc-nz.org) (the **development** environment), the `ENV` will be `DEV`, and the backend endpoint URI will be configured to `https://dev-api.aapc-nz.org`. ### `PROD` + On [https://www.aapc-nz.org](https://aapc-nz.org) (the **production** environment), the `ENV` will be `PROD`, and the backend endpoint URI will be configured to `https://api.aapc-nz.org`. diff --git a/frontend/app/(cms)/layout.tsx b/frontend/app/(cms)/layout.tsx index 1452b70c..1b691082 100644 --- a/frontend/app/(cms)/layout.tsx +++ b/frontend/app/(cms)/layout.tsx @@ -1,6 +1,6 @@ -import React from "react"; +import React from "react" -export default function CMSLayout({ children, }: { children: React.ReactNode }) { +export default function CMSLayout({ children }: { children: React.ReactNode }) { return (
{/*
*/} diff --git a/frontend/app/(cms)/news/[id]/edit/layout.tsx b/frontend/app/(cms)/news/[id]/edit/layout.tsx index 0e6094a1..e1f197b6 100644 --- a/frontend/app/(cms)/news/[id]/edit/layout.tsx +++ b/frontend/app/(cms)/news/[id]/edit/layout.tsx @@ -1,13 +1,9 @@ -import type { Metadata } from "next"; -import { getMetadata } from "@/app/util"; -import React from "react"; +import type { Metadata } from "next" +import { getMetadata } from "@/app/util" +import React from "react" export const metadata: Metadata = getMetadata("Edit News") -export default function Layout({ children, }: { children: React.ReactNode }) { - return ( -
- {children} -
- ) +export default function Layout({ children }: { children: React.ReactNode }) { + return
{children}
} diff --git a/frontend/app/(cms)/news/[id]/edit/page.tsx b/frontend/app/(cms)/news/[id]/edit/page.tsx index 585aece8..1a67c7bb 100644 --- a/frontend/app/(cms)/news/[id]/edit/page.tsx +++ b/frontend/app/(cms)/news/[id]/edit/page.tsx @@ -1,13 +1,13 @@ "use client" -import React, { useState } from "react"; -import { Article } from "@aapc/types"; -import { API_URI } from "@/app/consts"; +import React, { useState } from "react" +import { Article } from "@aapc/types" +import { API_URI } from "@/app/consts" export default function EditNewsPage({ params }: { params: { id: string } }) { const [article, setArticle] = useState
() - fetch(`${API_URI}/content/news/${params.id}`, { method: "get" }).then(r => { - r.json().then(d => setArticle(new Article(d))) + fetch(`${API_URI}/content/news/${params.id}`, { method: "get" }).then((r) => { + r.json().then((d) => setArticle(new Article(d))) }) return ( diff --git a/frontend/app/(cms)/news/publish/example/page.tsx b/frontend/app/(cms)/news/publish/example/page.tsx index 2c6908be..88c6e9f1 100644 --- a/frontend/app/(cms)/news/publish/example/page.tsx +++ b/frontend/app/(cms)/news/publish/example/page.tsx @@ -1,23 +1,24 @@ "use client" -import React from "react"; -import ArticleForm from "@/app/components/ArticleForm"; -import { Article, ArticleType } from "@aapc/types"; -import ButtonLink from "@/app/components/ButtonLink"; +import React from "react" +import ArticleForm from "@/app/components/ArticleForm" +import { Article, ArticleType } from "@aapc/types" +import ButtonLink from "@/app/components/ButtonLink" -export default function ExampleCreateNewsPage () { +export default function ExampleCreateNewsPage() { const exampleArticle = new Article({ title: "An Example Article", subtitle: "This example article shows the capabilities of the rich text editor.", - content: "

Lorem ipsum dolor sit amet

Praesent sit amet ligula nec ante facilisis molestie. Sed tincidunt tortor a malesuada interdum. In imperdiet dolor at dolor posuere, dictum bibendum lacus ultricies. Curabitur eu neque in nisi tempor luctus a ac sapien. Nulla facilisi.

Quisque in dui vitae libero efficitur maximus.

Sed nec nisl in massa consectetur venenatis. Vestibulum in tellus vestibulum, cursus lectus gravida, volutpat tellus.

Suspendisse potenti. Curabitur neque nulla, fermentum ac arcu eu, interdum mattis ante. Vestibulum vitae ultrices risus. Integer nec interdum neque, imperdiet efficitur urna. Cras enim nulla, cursus in scelerisque sed, mattis sed augue. Ut ante mauris, faucibus id dolor id, volutpat consectetur diam. Morbi gravida turpis at turpis ornare suscipit. Nunc eleifend quam vitae sapien convallis, at rhoncus libero pellentesque. Vestibulum molestie libero tincidunt, tempus mi ut, pretium velit. Donec ac fringilla tellus, imperdiet porttitor urna. Sed egestas ligula orci, vel interdum magna malesuada eu. Nunc ac tincidunt est.

Pellentesque auctor elit ligula, at posuere sem lobortis at

Maecenas aliquet venenatis nisl a ullamcorper. Maecenas dignissim massa lacus. Mauris euismod odio non risus pharetra suscipit. Cras bibendum, felis ac lacinia egestas, turpis neque sodales leo, et tempus nisl metus et purus.

  • Curabitur vel condimentum orci.

  • Phasellus euismod nisi eu orci egestas dignissim vitae id massa.

  • Lorem ipsum dolor sit amet, consectetur adipiscing elit.

In fermentum nibh et ipsum dapibus, quis auctor tortor pellentesque. In hac habitasse platea dictumst. Nunc nibh nisi, consequat ac aliquam vitae, pharetra posuere elit. Duis finibus, purus eget tempor consectetur, urna turpis congue turpis, commodo aliquam quam metus sed elit. Pellentesque sodales faucibus neque et iaculis. Fusce consectetur fermentum nisl, at dictum tortor tristique vel. Curabitur elementum faucibus nisi vitae malesuada.

Vestibulum blandit id felis in tincidunt

Suspendisse faucibus tempor tortor, sed tempor dolor bibendum tempor. Nulla varius est et ligula iaculis, at ullamcorper nisl porta. Nulla at tristique lacus. Nunc iaculis iaculis nulla vel lacinia. Quisque dictum nibh et facilisis luctus. Etiam facilisis leo lectus, egestas iaculis ante bibendum at.

", - media: [] + content: + "

Lorem ipsum dolor sit amet

Praesent sit amet ligula nec ante facilisis molestie. Sed tincidunt tortor a malesuada interdum. In imperdiet dolor at dolor posuere, dictum bibendum lacus ultricies. Curabitur eu neque in nisi tempor luctus a ac sapien. Nulla facilisi.

Quisque in dui vitae libero efficitur maximus.

Sed nec nisl in massa consectetur venenatis. Vestibulum in tellus vestibulum, cursus lectus gravida, volutpat tellus.

Suspendisse potenti. Curabitur neque nulla, fermentum ac arcu eu, interdum mattis ante. Vestibulum vitae ultrices risus. Integer nec interdum neque, imperdiet efficitur urna. Cras enim nulla, cursus in scelerisque sed, mattis sed augue. Ut ante mauris, faucibus id dolor id, volutpat consectetur diam. Morbi gravida turpis at turpis ornare suscipit. Nunc eleifend quam vitae sapien convallis, at rhoncus libero pellentesque. Vestibulum molestie libero tincidunt, tempus mi ut, pretium velit. Donec ac fringilla tellus, imperdiet porttitor urna. Sed egestas ligula orci, vel interdum magna malesuada eu. Nunc ac tincidunt est.

Pellentesque auctor elit ligula, at posuere sem lobortis at

Maecenas aliquet venenatis nisl a ullamcorper. Maecenas dignissim massa lacus. Mauris euismod odio non risus pharetra suscipit. Cras bibendum, felis ac lacinia egestas, turpis neque sodales leo, et tempus nisl metus et purus.

  • Curabitur vel condimentum orci.

  • Phasellus euismod nisi eu orci egestas dignissim vitae id massa.

  • Lorem ipsum dolor sit amet, consectetur adipiscing elit.

In fermentum nibh et ipsum dapibus, quis auctor tortor pellentesque. In hac habitasse platea dictumst. Nunc nibh nisi, consequat ac aliquam vitae, pharetra posuere elit. Duis finibus, purus eget tempor consectetur, urna turpis congue turpis, commodo aliquam quam metus sed elit. Pellentesque sodales faucibus neque et iaculis. Fusce consectetur fermentum nisl, at dictum tortor tristique vel. Curabitur elementum faucibus nisi vitae malesuada.

Vestibulum blandit id felis in tincidunt

Suspendisse faucibus tempor tortor, sed tempor dolor bibendum tempor. Nulla varius est et ligula iaculis, at ullamcorper nisl porta. Nulla at tristique lacus. Nunc iaculis iaculis nulla vel lacinia. Quisque dictum nibh et facilisis luctus. Etiam facilisis leo lectus, egestas iaculis ante bibendum at.

", + media: [], }) return (

Publish a News Article - Example

- - + +
) } diff --git a/frontend/app/(cms)/news/publish/layout.tsx b/frontend/app/(cms)/news/publish/layout.tsx index dfd458db..837daeb0 100644 --- a/frontend/app/(cms)/news/publish/layout.tsx +++ b/frontend/app/(cms)/news/publish/layout.tsx @@ -1,13 +1,9 @@ -import type { Metadata } from "next"; -import { getMetadata } from "@/app/util"; -import React from "react"; +import type { Metadata } from "next" +import { getMetadata } from "@/app/util" +import React from "react" export const metadata: Metadata = getMetadata("Publish News") -export default function Layout({ children, }: { children: React.ReactNode }) { - return ( -
- {children} -
- ) +export default function Layout({ children }: { children: React.ReactNode }) { + return
{children}
} diff --git a/frontend/app/(cms)/news/publish/page.tsx b/frontend/app/(cms)/news/publish/page.tsx index f05a62e7..e76f9e6a 100644 --- a/frontend/app/(cms)/news/publish/page.tsx +++ b/frontend/app/(cms)/news/publish/page.tsx @@ -1,16 +1,16 @@ "use client" -import React from "react"; -import ArticleForm from "@/app/components/ArticleForm"; -import { ArticleType } from "@aapc/types"; -import ButtonLink from "@/app/components/ButtonLink"; +import React from "react" +import ArticleForm from "@/app/components/ArticleForm" +import { ArticleType } from "@aapc/types" +import ButtonLink from "@/app/components/ButtonLink" export default function CreateNewsPage() { return (

Publish a News Article

- - + +
) } diff --git a/frontend/app/(cms)/research/[id]/edit/layout.tsx b/frontend/app/(cms)/research/[id]/edit/layout.tsx index 8e17db27..8c2c6fc2 100644 --- a/frontend/app/(cms)/research/[id]/edit/layout.tsx +++ b/frontend/app/(cms)/research/[id]/edit/layout.tsx @@ -1,13 +1,9 @@ -import type { Metadata } from "next"; -import { getMetadata } from "@/app/util"; -import React from "react"; +import type { Metadata } from "next" +import { getMetadata } from "@/app/util" +import React from "react" export const metadata: Metadata = getMetadata("Edit Research") -export default function Layout({ children, }: { children: React.ReactNode }) { - return ( -
- {children} -
- ) +export default function Layout({ children }: { children: React.ReactNode }) { + return
{children}
} diff --git a/frontend/app/(cms)/research/[id]/edit/page.tsx b/frontend/app/(cms)/research/[id]/edit/page.tsx index 8239c743..ede6b85c 100644 --- a/frontend/app/(cms)/research/[id]/edit/page.tsx +++ b/frontend/app/(cms)/research/[id]/edit/page.tsx @@ -1,14 +1,14 @@ "use client" -import React, { useState } from "react"; -import { API_URI } from "@/app/consts"; -import { Article, ArticleType } from "@aapc/types"; -import ArticleForm from "@/app/components/ArticleForm"; +import React, { useState } from "react" +import { API_URI } from "@/app/consts" +import { Article, ArticleType } from "@aapc/types" +import ArticleForm from "@/app/components/ArticleForm" export default function EditResearchPage({ params }: { params: { id: string } }) { - const [ article, setArticle ] = useState
() - fetch(`${API_URI}/content/research/${params.id}`, { method: "get" }).then(r => { - r.json().then(r => setArticle(new Article(r))) + const [article, setArticle] = useState
() + fetch(`${API_URI}/content/research/${params.id}`, { method: "get" }).then((r) => { + r.json().then((r) => setArticle(new Article(r))) }) return ( diff --git a/frontend/app/(cms)/research/publish/layout.tsx b/frontend/app/(cms)/research/publish/layout.tsx index fccb307e..a3bca2e3 100644 --- a/frontend/app/(cms)/research/publish/layout.tsx +++ b/frontend/app/(cms)/research/publish/layout.tsx @@ -1,13 +1,9 @@ -import type { Metadata } from "next"; -import { getMetadata } from "@/app/util"; -import React from "react"; +import type { Metadata } from "next" +import { getMetadata } from "@/app/util" +import React from "react" export const metadata: Metadata = getMetadata("Publish Research") -export default function Layout ({ children, }: { children: React.ReactNode }) { - return ( -
- {children} -
- ) +export default function Layout({ children }: { children: React.ReactNode }) { + return
{children}
} diff --git a/frontend/app/(cms)/research/publish/page.tsx b/frontend/app/(cms)/research/publish/page.tsx index 7d5321f1..c56c7252 100644 --- a/frontend/app/(cms)/research/publish/page.tsx +++ b/frontend/app/(cms)/research/publish/page.tsx @@ -1,8 +1,8 @@ "use client" -import React from "react"; -import ArticleForm from "@/app/components/ArticleForm"; -import { ArticleType } from "@aapc/types"; +import React from "react" +import ArticleForm from "@/app/components/ArticleForm" +import { ArticleType } from "@aapc/types" export default function CreateResearchPage() { return ( diff --git a/frontend/app/(content)/about/page.tsx b/frontend/app/(content)/about/page.tsx index ed41c4b2..ec4b9893 100644 --- a/frontend/app/(content)/about/page.tsx +++ b/frontend/app/(content)/about/page.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React from "react" export default function CreateResearchPage() { return ( diff --git a/frontend/app/(content)/layout.tsx b/frontend/app/(content)/layout.tsx index b3fdfc42..0e2580d6 100644 --- a/frontend/app/(content)/layout.tsx +++ b/frontend/app/(content)/layout.tsx @@ -1,9 +1,5 @@ -import React from "react"; +import React from "react" -export default function ContentLayout({ children, }: { children: React.ReactNode }) { - return ( -
- {children} -
- ) +export default function ContentLayout({ children }: { children: React.ReactNode }) { + return
{children}
} diff --git a/frontend/app/(content)/news/[id]/page.tsx b/frontend/app/(content)/news/[id]/page.tsx index 82b8355a..13469a54 100644 --- a/frontend/app/(content)/news/[id]/page.tsx +++ b/frontend/app/(content)/news/[id]/page.tsx @@ -1,11 +1,13 @@ -import React from "react"; -import Link from "next/link"; -import { Article } from "@aapc/types"; -import { API_URI } from "@/app/consts"; +import React from "react" +import Link from "next/link" +import { Article } from "@aapc/types" +import { API_URI } from "@/app/consts" export default async function NewsPage({ params }: { params: { id: string } }) { const req = await fetch(API_URI + `/content/news/${params.id}`, { method: "get" }) - if (req.status === 404) { return

Not Found

} + if (req.status === 404) { + return

Not Found

+ } const article = new Article(await req.json()) return ( diff --git a/frontend/app/(content)/news/page.tsx b/frontend/app/(content)/news/page.tsx index c192bb4a..a7560b0c 100644 --- a/frontend/app/(content)/news/page.tsx +++ b/frontend/app/(content)/news/page.tsx @@ -1,27 +1,30 @@ -import React from "react"; -import { Article, Paginator } from "@aapc/types"; -import { API_URI } from "@/app/consts"; -import ArticleCard from "@/app/components/ArticleCard"; -import Link from "next/link"; -import ButtonLink from "@/app/components/ButtonLink"; -import { getMetadata } from "@/app/util"; +import React from "react" +import { Article, Paginator } from "@aapc/types" +import { API_URI } from "@/app/consts" +import ArticleCard from "@/app/components/ArticleCard" +import Link from "next/link" +import ButtonLink from "@/app/components/ButtonLink" +import { getMetadata } from "@/app/util" export const metadata = getMetadata("All News") -export default async function AllNewsPage () { - const news = new Paginator(Article, await(await fetch(API_URI + "/content/news?pp=1000", { method: "get" })).json()) +export default async function AllNewsPage() { + const news = new Paginator( + Article, + await (await fetch(API_URI + "/content/news?pp=1000", { method: "get" })).json() + ) const newsCards: React.JSX.Element[] = [] for (const a of news.data) { - newsCards.push() + newsCards.push() } return (

All News

-
-
- {newsCards} +
+
+
{newsCards}
) } diff --git a/frontend/app/(content)/research/[id]/page.tsx b/frontend/app/(content)/research/[id]/page.tsx index 5186611d..dd80ebe1 100644 --- a/frontend/app/(content)/research/[id]/page.tsx +++ b/frontend/app/(content)/research/[id]/page.tsx @@ -1,11 +1,13 @@ -import React from "react"; -import Link from "next/link"; -import { API_URI } from "@/app/consts"; -import { Article } from "@aapc/types"; +import React from "react" +import Link from "next/link" +import { API_URI } from "@/app/consts" +import { Article } from "@aapc/types" export default async function ResearchPage({ params }: { params: { id: string } }) { const req = await fetch(API_URI + `/content/research/${params.id}`, { method: "get" }) - if (req.status === 404) { return

Not Found

} + if (req.status === 404) { + return

Not Found

+ } const article = new Article(await req.json()) return ( diff --git a/frontend/app/(content)/research/page.tsx b/frontend/app/(content)/research/page.tsx index 328a48ad..a642398f 100644 --- a/frontend/app/(content)/research/page.tsx +++ b/frontend/app/(content)/research/page.tsx @@ -1,26 +1,29 @@ -import React from "react"; -import { Article, Paginator } from "@aapc/types"; -import { API_URI } from "@/app/consts"; -import ArticleCard from "@/app/components/ArticleCard"; -import ButtonLink from "@/app/components/ButtonLink"; -import { getMetadata } from "@/app/util"; +import React from "react" +import { Article, Paginator } from "@aapc/types" +import { API_URI } from "@/app/consts" +import ArticleCard from "@/app/components/ArticleCard" +import ButtonLink from "@/app/components/ButtonLink" +import { getMetadata } from "@/app/util" export const metadata = getMetadata("All Research") -export default async function AllResearchPage () { - const research = new Paginator(Article, await(await fetch(API_URI + "/content/research?pp=1000", { method: "get" })).json()) +export default async function AllResearchPage() { + const research = new Paginator( + Article, + await (await fetch(API_URI + "/content/research?pp=1000", { method: "get" })).json() + ) const researchCards: React.JSX.Element[] = [] for (const a of research.data) { - researchCards.push() + researchCards.push() } return (

All Research

-
-
- {researchCards} +
+
+
{researchCards}
) } diff --git a/frontend/app/(homepage)/layout.tsx b/frontend/app/(homepage)/layout.tsx index 077ba775..f8c09539 100644 --- a/frontend/app/(homepage)/layout.tsx +++ b/frontend/app/(homepage)/layout.tsx @@ -1,9 +1,5 @@ -import React from "react"; +import React from "react" -export default function HomepageLayout({ children, }: { children: React.ReactNode }) { - return ( -
- {children} -
- ) +export default function HomepageLayout({ children }: { children: React.ReactNode }) { + return
{children}
} diff --git a/frontend/app/(homepage)/page.tsx b/frontend/app/(homepage)/page.tsx index d67e4517..7ce6cc93 100644 --- a/frontend/app/(homepage)/page.tsx +++ b/frontend/app/(homepage)/page.tsx @@ -1,7 +1,7 @@ -import React from "react"; -import Link from "next/link"; -import ButtonLink from "@/app/components/ButtonLink"; -import { getMetadata } from "@/app/util"; +import React from "react" +import Link from "next/link" +import ButtonLink from "@/app/components/ButtonLink" +import { getMetadata } from "@/app/util" export const metadata = getMetadata() @@ -10,11 +10,11 @@ export default async function Home() {

Home

- - + +
- - + +
diff --git a/frontend/app/components/ArticleCard.tsx b/frontend/app/components/ArticleCard.tsx index 67ba1ed6..ac16894b 100644 --- a/frontend/app/components/ArticleCard.tsx +++ b/frontend/app/components/ArticleCard.tsx @@ -1,14 +1,26 @@ -import React from "react"; -import { ArticleType, IArticle } from "@aapc/types"; -import Link from "next/link"; +import React from "react" +import { ArticleType, IArticle } from "@aapc/types" +import Link from "next/link" -export default function ArticleCard ({ article }: { article: IArticle }): React.JSX.Element { +export default function ArticleCard({ article }: { article: IArticle }): React.JSX.Element { return ( - +
{article.title} {article.subtitle} - Published by {article.publisher.displayName} on {new Date(article.publishedAt).toLocaleDateString('en-us', {weekday:"long", year:"numeric", month:"long", day:"numeric"})} + + Published by {article.publisher.displayName} on{" "} + + {new Date(article.publishedAt).toLocaleDateString("en-us", { + weekday: "long", + year: "numeric", + month: "long", + day: "numeric", + })} + +
) diff --git a/frontend/app/components/ArticleForm.tsx b/frontend/app/components/ArticleForm.tsx index 1a56a861..b466368f 100644 --- a/frontend/app/components/ArticleForm.tsx +++ b/frontend/app/components/ArticleForm.tsx @@ -1,10 +1,18 @@ -import ContentEditor from "@/app/components/ContentEditor"; -import { ArticleFromCMS } from "@/app/components/ArticleFromCMS"; -import { Article, ArticleType, IArticle } from "@aapc/types"; -import React, { useState } from "react"; -import { API_URI } from "@/app/consts"; +import ContentEditor from "@/app/components/ContentEditor" +import { ArticleFromCMS } from "@/app/components/ArticleFromCMS" +import { Article, ArticleType, IArticle } from "@aapc/types" +import React, { useState } from "react" +import { API_URI } from "@/app/consts" -export default function ArticleForm ({ articleType, actionType, article }: { articleType: ArticleType, article?: IArticle, actionType: "create" | "edit" }) { +export default function ArticleForm({ + articleType, + actionType, + article, +}: { + articleType: ArticleType + article?: IArticle + actionType: "create" | "edit" +}) { const [editorContent, setEditorContent] = useState(article?.content ?? "") const [title, setTitle] = useState(article?.title ?? "") const [subtitle, setSubtitle] = useState(article?.subtitle ?? "") @@ -14,13 +22,13 @@ export default function ArticleForm ({ articleType, actionType, article }: { art title: title, subtitle: subtitle, content: editorContent, - media: [] + media: [], } switch (actionType) { case "create": { - fetch(`${API_URI}/content/${articleType === ArticleType.news? 'news': 'research'}`, { + fetch(`${API_URI}/content/${articleType === ArticleType.news ? "news" : "research"}`, { method: "post", - body: JSON.stringify(a) + body: JSON.stringify(a), }).then() } } @@ -39,32 +47,38 @@ export default function ArticleForm ({ articleType, actionType, article }: { art return ( <>

Title

-