diff --git a/.gitignore b/.gitignore index 9a5aced..8383561 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,8 @@ pids # Directory for instrumented libs generated by jscoverage/JSCover lib-cov +/logging/log.txt +/logging/*.log # Coverage directory used by tools like istanbul coverage diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..cd5e4bb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "terminal.integrated.defaultProfile.windows": "PowerShell" +} \ No newline at end of file diff --git a/data/books.json b/data/books.json index c33e7b8..20f6ed1 100644 --- a/data/books.json +++ b/data/books.json @@ -1,7 +1,7 @@ { "books": [ { - "id": "1", + "id": 1, "title": "Fundamentals of Classical Mechanics", "author": "Dr. Ahmad Al-Kindi", "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", @@ -27,7 +27,7 @@ "featured": true }, { - "id": "2", + "id": 2, "title": "Quantum Physics: Principles and Applications", "author": "Prof. Fatima Al-Haytham", "description": "An advanced textbook exploring quantum mechanics, wave functions, uncertainty principles, and quantum applications in modern technology.", @@ -53,7 +53,7 @@ "featured": true }, { - "id": "3", + "id": 3, "title": "Stellar Astrophysics and Galactic Structure", "author": "Dr. Omar Al-Battani", "description": "Explores stellar evolution, galactic dynamics, and cosmological structures with emphasis on observational techniques and theoretical frameworks.", @@ -77,6 +77,550 @@ "reviewCount": 12, "inStock": false, "featured": false + }, + { + "id": 4, + "title": "Fundamentals of Classical Mechanics", + "author": "Dr. Hahsem Mdoukh", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 99.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 1000, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.8, + "reviewCount": 15, + "inStock": false, + "featured": true + }, + { + "id": 5, + "title": "Fundamentals of Classical Mechanics", + "author": "Dr. Hahsem ’Mohammed", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 99.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 1000, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.8, + "reviewCount": 15, + "inStock": false, + "featured": true + }, + { + "id": 6, + "title": "Fundamentals of Classical Mechanics", + "author": "Dr. Hahsem ’Mohammed", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 99.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 1000, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.8, + "reviewCount": 15, + "inStock": false, + "featured": false + }, + { + "id": 7, + "title": "eeeee of Classical Mechanics", + "author": "Dr. Yousef", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 12.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.4, + "reviewCount": 15, + "inStock": false, + "featured": true + }, + { + "id": 8, + "title": "Fundamentals of Classical Mechanics", + "author": "Dr. Yousef", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 12.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.4, + "reviewCount": 15, + "inStock": false, + "featured": true + }, + { + "id": 9, + "title": "Fundamentals of Classical Mechanics", + "author": "Dr. Yousef", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 12.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.4, + "reviewCount": 15, + "inStock": false, + "featured": true + }, + { + "id": 10, + "title": "Fundamentals of Classical Mechanics", + "author": "Dr. Yousef", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 12.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.4, + "reviewCount": 15, + "inStock": false, + "featured": true + }, + { + "id": 11, + "title": "ddddd of Classical Mechanics", + "author": "Dr. Yousef", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 12.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.4, + "reviewCount": 15, + "inStock": false, + "featured": true + }, + { + "id": 12, + "title": "Classical Mechanics", + "author": "Dr. Hashem", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 12.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.4, + "reviewCount": 15, + "inStock": false, + "featured": true + }, + { + "id": 13, + "title": "test 1", + "author": "Dr. Hashem mdoukh", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.9, + "reviewCount": 20, + "inStock": true, + "featured": true + }, + { + "id": 14, + "title": "test 1", + "author": "Dr. Hashem mdoukh", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.9, + "reviewCount": 20, + "inStock": true, + "featured": true + }, + { + "id": 15, + "title": "test 1", + "author": "Dr. Hashem mdoukh", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.9, + "reviewCount": 20, + "inStock": true, + "featured": true + }, + { + "id": 16, + "title": "test 1", + "author": "Dr. Hashem mdoukh", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.9, + "reviewCount": 20, + "inStock": true, + "featured": true + }, + { + "id": 17, + "title": "test 1", + "author": "Dr. Hashem mdoukh", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.9, + "reviewCount": 20, + "inStock": true, + "featured": true + }, + { + "id": 18, + "title": "test 1", + "author": "Dr. Hashem mdoukh", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.9, + "reviewCount": 20, + "inStock": true, + "featured": true + }, + { + "id": 19, + "title": "test 1", + "author": "Dr. Hashem mdoukh", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.9, + "reviewCount": 20, + "inStock": true, + "featured": true + }, + { + "id": 20, + "title": "test 1", + "author": "Dr. Hashem mdoukh", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.9, + "reviewCount": 20, + "inStock": true, + "featured": true + }, + { + "id": 21, + "title": "test 1", + "author": "Dr. Hashem mdoukh", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.9, + "reviewCount": 20, + "inStock": true, + "featured": true + }, + { + "id": 22, + "title": "test 1", + "author": "Dr. Hashem mdoukh", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics", + "University" + ], + "datePublished": "2022-01-15", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.9, + "reviewCount": 20, + "inStock": false, + "featured": true + }, + { + "id": 23, + "title": "test 2", + "author": "Dr. Hashem mohammed", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics" + ], + "datePublished": "2022-01-23", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 4.9, + "reviewCount": 20, + "inStock": false, + "featured": false + }, + { + "id": 24, + "title": "test 2", + "author": "Dr. Hashem mohammed", + "description": "A comprehensive introduction to classical mechanics covering Newtonian dynamics, conservation laws, rotational motion, and oscillations with modern applications.", + "price": 30.99, + "image": "/images/book1.jpg", + "isbn": "978-0123456789", + "genre": [ + "Physics", + "Textbook" + ], + "tags": [ + "Mechanics", + "Physics" + ], + "datePublished": "2022-01-23", + "pages": 150, + "language": "English", + "publisher": "Al-Biruni Academic Press", + "rating": 5, + "reviewCount": 20, + "inStock": false, + "featured": false } ] } \ No newline at end of file diff --git a/data/logging/log.txt b/data/logging/log.txt new file mode 100644 index 0000000..d885209 --- /dev/null +++ b/data/logging/log.txt @@ -0,0 +1,6 @@ +::1 - - [09/Oct/2025:09:37:17 +0000] "POST /api/books/ HTTP/1.1" 500 33 "-" "PostmanRuntime/7.48.0" +::1 - - [09/Oct/2025:09:44:10 +0000] "POST /api/books/ HTTP/1.1" 201 581 "-" "PostmanRuntime/7.48.0" +::1 - - [09/Oct/2025:09:44:44 +0000] "POST /api/books/ HTTP/1.1" 201 581 "-" "PostmanRuntime/7.48.0" +::1 - - [09/Oct/2025:09:45:00 +0000] "POST /api/books/ HTTP/1.1" 201 581 "-" "PostmanRuntime/7.48.0" +::1 - - [09/Oct/2025:09:48:01 +0000] "POST /api/books/ HTTP/1.1" 201 581 "-" "PostmanRuntime/7.48.0" +::1 - - [09/Oct/2025:10:11:18 +0000] "POST /api/books/ HTTP/1.1" 201 581 "-" "PostmanRuntime/7.48.0" diff --git a/data/reviews.json b/data/reviews.json index da7e78c..708796f 100644 --- a/data/reviews.json +++ b/data/reviews.json @@ -2,7 +2,7 @@ "reviews": [ { "id": "review-1", - "bookId": "1", + "bookId": 1, "author": "Dr. Yasmin Al-Baghdadi", "rating": 5, "title": "Excellent foundation for physics students", @@ -12,7 +12,7 @@ }, { "id": "review-2", - "bookId": "1", + "bookId": 1, "author": "Ahmad Khalil", "rating": 4, "title": "Clear explanations of complex concepts", @@ -22,7 +22,7 @@ }, { "id": "review-3", - "bookId": "1", + "bookId": 1, "author": "Prof. Layla Al-Masri", "rating": 5, "title": "Perfect for engineering applications", @@ -32,7 +32,7 @@ }, { "id": "review-4", - "bookId": "1", + "bookId": 1, "author": "Omar Hassan", "rating": 4, "title": "Good mathematical rigor", @@ -42,7 +42,7 @@ }, { "id": "review-5", - "bookId": "1", + "bookId": 1, "author": "Fatima Al-Zahra", "rating": 5, "title": "Essential for physics majors", @@ -52,7 +52,7 @@ }, { "id": "review-6", - "bookId": "2", + "bookId": 2, "author": "Prof. Khalid Al-Razi", "rating": 5, "title": "Outstanding quantum mechanics text", @@ -62,7 +62,7 @@ }, { "id": "review-7", - "bookId": "2", + "bookId": 2, "author": "Zahra Mansour", "rating": 4, "title": "Advanced but accessible", @@ -72,7 +72,7 @@ }, { "id": "review-8", - "bookId": "2", + "bookId": 2, "author": "Dr. Samir Al-Kindi", "rating": 5, "title": "Comprehensive quantum theory", @@ -82,7 +82,7 @@ }, { "id": "review-9", - "bookId": "2", + "bookId": 2, "author": "Nadia Al-Sharif", "rating": 4, "title": "Excellent for graduate students", @@ -92,7 +92,7 @@ }, { "id": "review-10", - "bookId": "2", + "bookId": 2, "author": "Prof. Tariq Al-Dimashqi", "rating": 5, "title": "Modern approach to quantum mechanics", @@ -102,13 +102,157 @@ }, { "id": "review-60", - "bookId": "15", + "bookId": 15, "author": "Dr. Amina Al-Andalusi", "rating": 4, "title": "Excellent climate science integration", "comment": "Great integration of geophysics with climate science. The plate tectonics chapters are well-written and current.", "timestamp": "2024-03-08T11:40:00Z", "verified": true + }, + { + "id": "r12", + "bookId": 6, + "user": "Hashem Mdoukh", + "rating": 5, + "comment": "" + }, + { + "id": "r13", + "bookId": 20, + "user": "Hashem Mdoukh", + "rating": 5, + "comment": "This Is Amazing book" + }, + { + "id": "review-61", + "bookId": 3, + "author": "Dr. Hahsem ’Mohammed", + "rating": 5, + "title": "Fundamentals of Classical Mechanics", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-08T08:39:42.340Z", + "verified": true + }, + { + "id": "review-62", + "bookId": 1, + "author": "Dr. Hahsem ’Mohammed", + "rating": 5, + "title": "Fundamentals of Classical Mechanics", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-08T08:55:02.890Z", + "verified": true + }, + { + "id": "review-63", + "bookId": 7, + "author": "Dr. Hahsem ’Mohammed", + "rating": 5, + "title": "Fundamentals of Classical Mechanics", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-08T09:00:53.390Z", + "verified": true + }, + { + "id": "review-64", + "bookId": 1, + "author": "Dr. Hahsem ’Mohammed", + "rating": 5, + "title": "Fundamentals of Classical Mechanics", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-08T09:17:41.217Z", + "verified": true + }, + { + "id": "review-65", + "bookId": 1, + "author": "Dr. Hahsem ’Mohammed", + "rating": 5, + "title": "Fundamentals of Classical Mechanics", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-08T09:18:53.770Z", + "verified": true + }, + { + "id": "review-66", + "bookId": 3, + "author": "Dr. Hahsem ’Mohammed", + "rating": 5, + "title": "Fundamentals of Classical Mechanics", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-08T09:21:52.966Z", + "verified": true + }, + { + "id": "review-67", + "bookId": 4, + "author": "Dr. Hahsem mdoukh", + "rating": 5, + "title": "Fundamentals of Classical Mechanics", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-08T10:02:57.442Z", + "verified": true + }, + { + "id": "review-68", + "bookId": 4, + "author": "Dr. yousef", + "rating": 4, + "title": "Fundamentals of Classical Mechanics", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-08T10:03:59.129Z", + "verified": true + }, + { + "id": "review-69", + "bookId": 7, + "author": "Dr. yousef", + "rating": 4, + "title": "Fundamentals of Classical Mechanics", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-08T10:10:59.382Z", + "verified": true + }, + { + "id": "review-70", + "bookId": 10, + "author": "Dr. yousef", + "rating": 4, + "title": "Fundamentals of Classical Mechanics", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-08T10:19:26.366Z", + "verified": true + }, + { + "id": "review-71", + "bookId": 160, + "author": "Dr. yousef", + "rating": 4, + "title": "Fundamentals of Classical Mechanics", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-08T10:30:44.930Z", + "verified": true + }, + { + "id": "review-72", + "bookId": 3, + "author": "Hashem Mohammed", + "rating": 3, + "title": "Fundamentals of Developments", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-10T08:38:52.173Z", + "verified": true + }, + { + "id": "review-73", + "bookId": 4, + "author": "Hashem Mohammed", + "rating": 3, + "title": "Fundamentals of Developments", + "comment": "A must-read for every developer!", + "timestamp": "2025-10-10T08:39:16.887Z", + "verified": true } ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b82d325 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1346 @@ +{ + "name": "amana-bookstore-express-api", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "amana-bookstore-express-api", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "cors": "^2.8.5", + "dotenv": "^17.2.3", + "express": "^5.1.0", + "jsonwebtoken": "^9.0.2", + "mongodb": "^7.0.0", + "mongoose": "^8.20.0", + "morgan": "^1.10.1" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.2.tgz", + "integrity": "sha512-QgA5AySqB27cGTXBFmnpifAi7HxoGUeezwo6p9dI03MuDB6Pp33zgclqVb6oVK3j6I9Vesg0+oojW2XxB59SGg==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/bson": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-7.0.0.tgz", + "integrity": "sha512-Kwc6Wh4lQ5OmkqqKhYGKIuELXl+EPYSCObVE6bWsp1T/cGkOCBN0I8wF/T44BiuhHyNi1mmKVPXk60d41xZ7kw==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kareem": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", + "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/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==", + "license": "MIT" + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mongodb": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.0.0.tgz", + "integrity": "sha512-vG/A5cQrvGGvZm2mTnCSz1LUcbOPl83hfB6bxULKQ8oFZauyox/2xbZOoGNl+64m8VBrETkdGCDBdOsCr3F3jg==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.3.0", + "bson": "^7.0.0", + "mongodb-connection-string-url": "^7.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.806.0", + "@mongodb-js/zstd": "^7.0.0", + "gcp-metadata": "^7.0.1", + "kerberos": "^7.0.0", + "mongodb-client-encryption": ">=7.0.0 <7.1.0", + "snappy": "^7.3.2", + "socks": "^2.8.6" + }, + "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": "7.0.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.0.tgz", + "integrity": "sha512-irhhjRVLE20hbkRl4zpAYLnDMM+zIZnp0IDB9akAFFUZp/3XdOfwwddc7y6cNvF2WCEtfTYRwYbIfYa2kVY0og==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^13.0.0", + "whatwg-url": "^14.1.0" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/mongoose": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.20.0.tgz", + "integrity": "sha512-SxqNb8yx+VOjIOx2l7HqkGvYuLC/T85d+jPvqGDdUbKJFz/5PVSsVxQzypQsX7chenYvq5bd8jIr4LtunedE7g==", + "license": "MIT", + "dependencies": { + "bson": "^6.10.4", + "kareem": "2.6.3", + "mongodb": "~6.20.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "17.1.3" + }, + "engines": { + "node": ">=16.20.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose/node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/mongoose/node_modules/bson": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", + "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/mongoose/node_modules/mongodb": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.20.0.tgz", + "integrity": "sha512-Tl6MEIU3K4Rq3TSHd+sZQqRBoGlFsOgNrH5ltAcFBV62Re3Fd+FcaVf8uSEQFOJ51SDowDVttBTONMfoYWrWlQ==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.3.0", + "bson": "^6.10.4", + "mongodb-connection-string-url": "^3.0.2" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.3.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/mongoose/node_modules/mongodb-connection-string-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^14.1.0 || ^13.0.0" + } + }, + "node_modules/morgan": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.1.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "license": "MIT", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", + "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.7.0", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sift": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/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==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..e86cc5f --- /dev/null +++ b/package.json @@ -0,0 +1,31 @@ +{ + "name": "amana-bookstore-express-api", + "version": "1.0.0", + "description": "this is a first server for amana bookstore api ", + "homepage": "https://github.com/hashem-mdoukh/Amana-Bookstore-Express-API#readme", + "bugs": { + "url": "https://github.com/hashem-mdoukh/Amana-Bookstore-Express-API/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/hashem-mdoukh/Amana-Bookstore-Express-API.git" + }, + "license": "ISC", + "author": "hashem", + "type": "commonjs", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js" + }, + "dependencies": { + "cors": "^2.8.5", + "dotenv": "^17.2.3", + "express": "^5.1.0", + "jsonwebtoken": "^9.0.2", + "mongodb": "^7.0.0", + "mongoose": "^8.20.0", + "morgan": "^1.10.1" + }, + "keywords": [] +} diff --git a/server.js b/server.js index e69de29..88fb581 100644 --- a/server.js +++ b/server.js @@ -0,0 +1,7 @@ +const app = require('./src/app'); +const PORT = process.env.PORT || 3000; + +// Run server +app.listen(PORT, () => { + console.log(`🚀 Server running on http://localhost:${PORT}`); +}); \ No newline at end of file diff --git a/src/Configuration/db.js b/src/Configuration/db.js new file mode 100644 index 0000000..2ed4b31 --- /dev/null +++ b/src/Configuration/db.js @@ -0,0 +1,15 @@ +const mongoose = require("mongoose"); + +const connectDB = async () => { + try { + await mongoose.connect(process.env.MONGO_URL, { + useNewUrlParser: true, + useUnifiedTopology: true, + }); + console.log("MongoDB connected successfully with our server!"); + } catch (err) { + console.error("MongoDB connection error:", err); + } +}; + +module.exports = connectDB; diff --git a/src/app.js b/src/app.js new file mode 100644 index 0000000..9342ebf --- /dev/null +++ b/src/app.js @@ -0,0 +1,50 @@ +const express = require('express'); +const cors = require('cors'); +const morgan = require('morgan'); +const connectDB = require('./Configuration/db'); +require('dotenv').config(); // Must be at the top +const fs = require('fs'); +const path = require('path'); +const booksRoutes = require('./routes/booksRoutes'); +const reviewsRoutes = require('./routes/reviewsRoutes'); +const errorHandler = require('./middleware/errorHandler'); + +const app = express(); + +connectDB(); + +// Define the path to data/logging/log.txt +const logFilePath = path.join(__dirname, '..', 'logging', 'log.txt'); + +// Create the directory if it doesn't exist (optional, but good practice) +const logDir = path.dirname(logFilePath); +if (!fs.existsSync(logDir)) { + fs.mkdirSync(logDir, { recursive: true }); +} + +// Create a write stream (in 'a' append mode, so it never creates a new file, +// but adds to the existing one). +const accessLogStream = fs.createWriteStream(logFilePath, { flags: 'a' }); + +// --- START MIDDLEWARES --- + +// 1. Logging Middleware (first to capture all requests) +app.use(morgan('combined', { stream: accessLogStream })); + +// 2. Cross-Origin Resource Sharing +app.use(cors()); +app.use(express.json()); + +// --- END MIDDLEWARES --- + + + + +// Routes +app.use('/api/books', booksRoutes); +app.use('/api/reviews', reviewsRoutes); + +// Error handling middleware +app.use(errorHandler); + +module.exports = app; \ No newline at end of file diff --git a/src/controllers/booksController.js b/src/controllers/booksController.js new file mode 100644 index 0000000..dccf509 --- /dev/null +++ b/src/controllers/booksController.js @@ -0,0 +1,308 @@ +const fs = require("fs"); +const path = require("path"); +const { loadJSON } = require("../utils/fileUtils"); + +const booksPath = path.join(__dirname, "..", "..", "data", "books.json"); + +const booksData = loadJSON("books.json"); +const reviewsData = loadJSON("reviews.json"); + +let books = booksData?.books || []; +let reviews = reviewsData?.reviews || []; + +// Get all books +const getAllBooks = (req, res) => { + return res.json({ + message: "All books retrieved successfully", + status: 200, + count: books.length, + data: books, + }); +}; + +exports.getAllBooks = (req, res) => { + return res.json({ + message: "All books retrieved successfully", + status: 200, + count: books.length, + data: books, + }); +}; + +// Get book by ID +const getBookById = (req, res) => { + const { id } = req.params; + + const book = books.find((b) => b.id === +id); + + if (!book) { + return res.json({ + error: "Book not found please Porvide a a vailde ID", + status: 404, + }); + } + + return res.json({ + message: "Book By ID retrieved successfully", + status: 200, + data: book, + }); +}; + +// Get books within date range +const getBooksByRange = (req, res) => { + const { start, end } = req.query; + + if (!start || !end) { + return res.json({ + error:"Please provide both 'start' and 'end' query parameters (YYYY-MM-DD).", + status: 400, + }); + } + + const startDate = new Date(start); + const endDate = new Date(end); + + if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) { + return res.json({ + error: "Invalid date format. Please use the format YYYY-MM-DD.", + status: 400, + }); + } + + if (startDate > endDate) { + return res.json({ + error: "'start' date must be earlier than or equal to 'end' date.", + status: 400, + }); + } + + const filtered = books.filter((b) => { + const date = new Date(b.datePublished); + return date >= startDate && date <= endDate; + }); + + return res.json({ + message: "Books retrieved successfully by date range.", + status: 200, + count: filtered.length, + data: filtered, + }); +}; + +// Get top-rated books +const getTopRatedBooks = (req, res) => { + const sorted = [...books].sort( + (a, b) => b.rating * b.reviewCount - a.rating * a.reviewCount + ); + return res.json({ + message: "Top-rated books retrieved successfully", + status: 200, + data: sorted.slice(0, 10), + }); +}; + +// Get featured books +const getFeaturedBooks = (req, res) => { + const featured = books.filter((b) => b.featured); + return res.json({ + message: "Featured books retrieved successfully", + status: 200, + data: featured, + }); +}; + +// Get reviews for specific book +const getBookReviews = (req, res) => { + const { id } = req.params; + const bookExists = books.some((b) => b.id === +id); + if (!bookExists) return res.json({ error: "Book not found", status: 404 }); + + const related = reviews.filter((r) => r.bookId === +id); + return res.json({ + message: "Book reviews retrieved successfully", + status: 200, + data: related, + }); +}; + +// Get book by search +const searchBooks = (req, res) => { + try { + const { name, start, end, rate } = req.query; + + if (!books || books.length === 0) { + return res.json({ + error: "No books available.", + status: 404, + }); + } + + let filtered = books; + + if (name) { + const lowerName = name.toLowerCase(); + filtered = filtered.filter((b) => + b.title.toLowerCase().includes(lowerName) + ); + } + + if (start || end) { + const startDate = start ? new Date(start) : new Date("1900-01-01"); + const endDate = end ? new Date(end) : new Date(); + + if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) { + return res.json({ + error: "Invalid date format. Use YYYY-MM-DD.", + status: 400, + }); + } + + if (startDate > endDate) { + return res.json({ + error: "'start' date must be before 'end' date.", + status: 400, + }); + } + + filtered = filtered.filter((b) => { + const bookDate = new Date(b.datePublished); + return bookDate >= startDate && bookDate <= endDate; + }); + } + + if (rate) { + const rateNum = parseFloat(rate); + if (isNaN(rateNum) || rateNum < 0 || rateNum > 5) { + return res.json({ + error: "Rate must be a number between 0 and 5.", + status: 400, + }); + } + + filtered = filtered.filter((b) => b.rating >= rateNum); + } + + return res.json({ + message: "Books filtered successfully.", + status: 200, + totalResults: filtered.length, + data: filtered, + }); + } catch (error) { + console.error("Error filtering books:", error); + return res.json({ + error: "Internal server error.", + status: 500, + }); + } +}; + +// POST: Add a new book +const addBook = (req, res) => { + const maxId = books.reduce((max, book) => { + const currentIdNum = parseInt(book.id, 10); + return currentIdNum && currentIdNum > max ? currentIdNum : max; + }, 0); + + const newId = maxId + 1; + + const { + title, + author, + description, + price, + image, + isbn, + genre, + tags, + datePublished, + pages, + language, + publisher, + rating, + reviewCount, + inStock, + featured, + } = req.body; + + if (!title || !author) { + return res.json({ + error: "Title and author are required.", + status: 400, + }); + } + + const newBook = { + id: newId, + title, + author, + description: description || "No description provided.", + price: price !== undefined ? price : 0, + image: image || "/images/default.jpg", + isbn: isbn || "000-0000000000", + genre: Array.isArray(genre) ? genre : [], + tags: Array.isArray(tags) ? tags : [], + datePublished: datePublished || new Date().toISOString().split("T")[0], + pages: pages !== undefined ? pages : 0, + language: language || "English", + publisher: publisher || "Unknown Publisher", + rating: rating !== undefined ? rating : 0, + reviewCount: reviewCount !== undefined ? reviewCount : 0, + inStock: typeof inStock === "boolean" ? inStock : false, + featured: typeof featured === "boolean" ? featured : false, + }; + + books.push(newBook); + + fs.writeFileSync(booksPath, JSON.stringify({ books }, null, 2)); + + return res.json({ + message: "Book added successfully", + status: 201, + book: newBook, + }); +}; + +const deleteBookById = (req, res) => { + const { id } = req.params; + + try { + const bookIndex = books.findIndex((b) => b.id === +id); + + if (bookIndex === -1) { + return res.json({ + error: "Book not found", + status: 404, + }); + } + + books.splice(bookIndex, 1); + + fs.writeFileSync(booksPath, JSON.stringify({ books }, null, 2)); + + return res.json({ + message: "Book deleted successfully", + status: 200, + }); + } catch (err) { + console.error("Error deleting book:", err); + return res.json({ + error: "Internal Server Error", + message: "An unexpected error occurred", + status: 500, + }); + } +}; + +module.exports = { + getAllBooks, + getBookById, + getBooksByRange, + getTopRatedBooks, + getFeaturedBooks, + getBookReviews, + searchBooks, + addBook, + deleteBookById, +}; diff --git a/src/controllers/reviewController.js b/src/controllers/reviewController.js new file mode 100644 index 0000000..47b3eb9 --- /dev/null +++ b/src/controllers/reviewController.js @@ -0,0 +1,66 @@ +const fs = require("fs"); +const path = require("path"); +const { loadJSON } = require("../utils/fileUtils"); + +const reviewsPath = path.join(__dirname, "..", "..", "data", "reviews.json"); + +const addReview = (req, res) => { + const reviewsData = loadJSON("reviews.json"); + const booksData = loadJSON("books.json"); + + let reviews = reviewsData?.reviews || []; + let books = booksData?.books || []; + + try { + const { bookId, author, rating, title, comment } = req.body; + + if (!bookId || !author || !rating || !title) { + return res.json({ + error: "bookId, author, rating, and title are required.", + status: 400 + }); + } + + const bookExists = books.some((b) => b.id === bookId); + if (!bookExists) { + return res.json({ + error: `Book with ID ${bookId} not found.`, + status: 404 + }); + } + + const maxIdNum = reviews.reduce((max, review) => { + const num = parseInt(review.id?.split("-")[1], 10); + return num && num > max ? num : max; + }, 0); + + const newReviewId = `review-${maxIdNum + 1}`; + + const newReview = { + id: newReviewId, + bookId, + author, + rating, + title, + comment: comment || "", + timestamp: new Date().toISOString(), + verified: true, + }; + + reviews.push(newReview); + fs.writeFileSync(reviewsPath, JSON.stringify({ reviews }, null, 2)); + + res.json({ + message: "Review added successfully.", + status: 201, + review: newReview, + }); + } catch (error) { + console.error("Error adding review:", error); + res.json({ error: "Internal server error.", status: 500 }); + } +}; + +module.exports = { + addReview, +}; diff --git a/src/middleware/authMiddleware.js b/src/middleware/authMiddleware.js new file mode 100644 index 0000000..bdbb910 --- /dev/null +++ b/src/middleware/authMiddleware.js @@ -0,0 +1,14 @@ +// A very simple mock authentication middleware +const AUTH_TOKEN = 'mysecrettoken123'; // you can store this in .env in production + +function authenticate(req, res, next) { + const token = req.headers['authorization']; + + if (!token || token !== `Bearer ${AUTH_TOKEN}`) { + return res.status(403).json({ error: 'Access denied. Invalid or missing token.' }); + } + + next(); +} + +module.exports = authenticate; diff --git a/src/middleware/errorHandler.js b/src/middleware/errorHandler.js new file mode 100644 index 0000000..aa68b5d --- /dev/null +++ b/src/middleware/errorHandler.js @@ -0,0 +1,6 @@ +function errorHandler(err, req, res, next) { + console.error('Error:', err); + res.status(500).json({ error: 'Internal Server Error' }); +} + +module.exports = errorHandler; diff --git a/src/routes/booksRoutes.js b/src/routes/booksRoutes.js new file mode 100644 index 0000000..29dba65 --- /dev/null +++ b/src/routes/booksRoutes.js @@ -0,0 +1,20 @@ +const express = require('express'); +const router = express.Router(); +const booksController = require('../controllers/booksController'); +const authenticate = require('../middleware/authMiddleware'); + +router.get('/', booksController.getAllBooks); +router.get('/range', booksController.getBooksByRange); +router.get('/top-rated', booksController.getTopRatedBooks); +router.get('/featured', booksController.getFeaturedBooks); +router.get('/search', booksController.searchBooks); +router.get('/:id/reviews', booksController.getBookReviews); +router.get('/:id', booksController.getBookById); + + +router.post('/', authenticate, booksController.addBook); + +router.delete('/:id', authenticate, booksController.deleteBookById); + + +module.exports = router; diff --git a/src/routes/reviewsRoutes.js b/src/routes/reviewsRoutes.js new file mode 100644 index 0000000..1efe5a9 --- /dev/null +++ b/src/routes/reviewsRoutes.js @@ -0,0 +1,9 @@ +const express = require('express'); +const router = express.Router(); +const reviewsController = require('../controllers/reviewController'); +const authenticate = require('../middleware/authMiddleware'); + +// Add a new review +router.post('/', authenticate, reviewsController.addReview); + +module.exports = router; diff --git a/src/utils/fileUtils.js b/src/utils/fileUtils.js new file mode 100644 index 0000000..3e5d3df --- /dev/null +++ b/src/utils/fileUtils.js @@ -0,0 +1,15 @@ +const fs = require('fs'); +const path = require('path'); + +function loadJSON(filename) { + try { + const filePath = path.join(__dirname, '..', '..', 'data', filename); + const data = fs.readFileSync(filePath, 'utf-8'); + return JSON.parse(data); + } catch (err) { + console.error(`Error reading ${filename}:`, err); + return null; + } +} + +module.exports = { loadJSON }; diff --git a/logging/log.txt b/src/utils/generateToken.js similarity index 100% rename from logging/log.txt rename to src/utils/generateToken.js