├── .env.example ├── .gitignore ├── build ├── index.js ├── middlewares │ └── authMiddleware.js ├── routes │ ├── authRoutes.js │ ├── tweetRoutes.js │ └── userRoutes.js └── services │ └── emailService.js ├── package-lock.json ├── package.json ├── prisma ├── dev.db └── schema.prisma ├── readme.md ├── src ├── index.ts ├── middlewares │ └── authMiddleware.ts ├── routes │ ├── authRoutes.ts │ ├── tweetRoutes.ts │ └── userRoutes.ts └── services │ └── emailService.ts └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | # Environment variables declared in this file are automatically made available to Prisma. 2 | # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema 3 | 4 | # Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. 5 | # See the documentation for all the connection string options: https://pris.ly/d/connection-strings 6 | 7 | DATABASE_URL="" 8 | JWT_SECRET="" 9 | 10 | # AWS_ACCESS_KEY_ID= 11 | # AWS_SECRET_ACCESS_KEY= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | .pnpm-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # Snowpack dependency directory (https://snowpack.dev/) 50 | web_modules/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Optional stylelint cache 62 | .stylelintcache 63 | 64 | # Microbundle cache 65 | .rpt2_cache/ 66 | .rts2_cache_cjs/ 67 | .rts2_cache_es/ 68 | .rts2_cache_umd/ 69 | 70 | # Optional REPL history 71 | .node_repl_history 72 | 73 | # Output of 'npm pack' 74 | *.tgz 75 | 76 | # Yarn Integrity file 77 | .yarn-integrity 78 | 79 | # dotenv environment variable files 80 | .env 81 | .env.development.local 82 | .env.test.local 83 | .env.production.local 84 | .env.local 85 | 86 | # parcel-bundler cache (https://parceljs.org/) 87 | .cache 88 | .parcel-cache 89 | 90 | # Next.js build output 91 | .next 92 | out 93 | 94 | # Nuxt.js build / generate output 95 | .nuxt 96 | dist 97 | 98 | # Gatsby files 99 | .cache/ 100 | # Comment in the public line in if your project uses Gatsby and not Next.js 101 | # https://nextjs.org/blog/next-9-1#public-directory-support 102 | # public 103 | 104 | # vuepress build output 105 | .vuepress/dist 106 | 107 | # vuepress v2.x temp and cache directory 108 | .temp 109 | 110 | # Docusaurus cache and generated files 111 | .docusaurus 112 | 113 | # Serverless directories 114 | .serverless/ 115 | 116 | # FuseBox cache 117 | .fusebox/ 118 | 119 | # DynamoDB Local files 120 | .dynamodb/ 121 | 122 | # TernJS port file 123 | .tern-port 124 | 125 | # Stores VSCode versions used for testing VSCode extensions 126 | .vscode-test 127 | 128 | # yarn v2 129 | .yarn/cache 130 | .yarn/unplugged 131 | .yarn/build-state.yml 132 | .yarn/install-state.gz 133 | .pnp.* 134 | 135 | ### Node Patch ### 136 | # Serverless Webpack directories 137 | .webpack/ 138 | 139 | # Optional stylelint cache 140 | 141 | # SvelteKit build / generate output 142 | .svelte-kit 143 | 144 | # End of https://www.toptal.com/developers/gitignore/api/node -------------------------------------------------------------------------------- /build/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const express_1 = __importDefault(require("express")); 7 | const userRoutes_1 = __importDefault(require("./routes/userRoutes")); 8 | const tweetRoutes_1 = __importDefault(require("./routes/tweetRoutes")); 9 | const authRoutes_1 = __importDefault(require("./routes/authRoutes")); 10 | const authMiddleware_1 = require("./middlewares/authMiddleware"); 11 | const app = (0, express_1.default)(); 12 | app.use(express_1.default.json()); 13 | app.use('/user', authMiddleware_1.authenticateToken, userRoutes_1.default); 14 | app.use('/tweet', authMiddleware_1.authenticateToken, tweetRoutes_1.default); 15 | app.use('/auth', authRoutes_1.default); 16 | app.get('/', (req, res) => { 17 | res.send('Hello world'); 18 | }); 19 | app.listen(3000, () => { 20 | console.log('Server ready at localhost:3000'); 21 | }); 22 | -------------------------------------------------------------------------------- /build/middlewares/authMiddleware.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __importDefault = (this && this.__importDefault) || function (mod) { 12 | return (mod && mod.__esModule) ? mod : { "default": mod }; 13 | }; 14 | Object.defineProperty(exports, "__esModule", { value: true }); 15 | exports.authenticateToken = void 0; 16 | const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); 17 | const client_1 = require("@prisma/client"); 18 | const JWT_SECRET = process.env.JWT_SECRET || 'SUPER SECRET'; 19 | const prisma = new client_1.PrismaClient(); 20 | function authenticateToken(req, res, next) { 21 | return __awaiter(this, void 0, void 0, function* () { 22 | // Authentication 23 | const authHeader = req.headers['authorization']; 24 | const jwtToken = authHeader === null || authHeader === void 0 ? void 0 : authHeader.split(' ')[1]; 25 | if (!jwtToken) { 26 | return res.sendStatus(401); 27 | } 28 | // decode the jwt token 29 | try { 30 | const payload = (yield jsonwebtoken_1.default.verify(jwtToken, JWT_SECRET)); 31 | const dbToken = yield prisma.token.findUnique({ 32 | where: { id: payload.tokenId }, 33 | include: { user: true }, 34 | }); 35 | if (!(dbToken === null || dbToken === void 0 ? void 0 : dbToken.valid) || dbToken.expiration < new Date()) { 36 | return res.status(401).json({ error: 'API token expired' }); 37 | } 38 | req.user = dbToken.user; 39 | } 40 | catch (e) { 41 | return res.sendStatus(401); 42 | } 43 | next(); 44 | }); 45 | } 46 | exports.authenticateToken = authenticateToken; 47 | -------------------------------------------------------------------------------- /build/routes/authRoutes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __importDefault = (this && this.__importDefault) || function (mod) { 12 | return (mod && mod.__esModule) ? mod : { "default": mod }; 13 | }; 14 | Object.defineProperty(exports, "__esModule", { value: true }); 15 | const express_1 = require("express"); 16 | const client_1 = require("@prisma/client"); 17 | const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); 18 | const emailService_1 = require("../services/emailService"); 19 | const EMAIL_TOKEN_EXPIRATION_MINUTES = 10; 20 | const AUTHENTICATION_EXPIRATION_HOURS = 12; 21 | const JWT_SECRET = process.env.JWT_SECRET || 'SUPER SECRET'; 22 | const router = (0, express_1.Router)(); 23 | const prisma = new client_1.PrismaClient(); 24 | // Generate a random 8 digit number as the email token 25 | function generateEmailToken() { 26 | return Math.floor(10000000 + Math.random() * 90000000).toString(); 27 | } 28 | function generateAuthToken(tokenId) { 29 | const jwtPayload = { tokenId }; 30 | return jsonwebtoken_1.default.sign(jwtPayload, JWT_SECRET, { 31 | algorithm: 'HS256', 32 | noTimestamp: true, 33 | }); 34 | } 35 | // Create a user, if it doesn't exist, 36 | // generate the emailToken and send it to their email 37 | router.post('/login', (req, res) => __awaiter(void 0, void 0, void 0, function* () { 38 | const { email } = req.body; 39 | // generate token 40 | const emailToken = generateEmailToken(); 41 | const expiration = new Date(new Date().getTime() + EMAIL_TOKEN_EXPIRATION_MINUTES * 60 * 1000); 42 | try { 43 | const createdToken = yield prisma.token.create({ 44 | data: { 45 | type: 'EMAIL', 46 | emailToken, 47 | expiration, 48 | user: { 49 | connectOrCreate: { 50 | where: { email }, 51 | create: { email }, 52 | }, 53 | }, 54 | }, 55 | }); 56 | console.log(createdToken); 57 | // TODO send emailToken to user's email 58 | yield (0, emailService_1.sendEmailToken)(email, emailToken); 59 | res.sendStatus(200); 60 | } 61 | catch (e) { 62 | console.log(e); 63 | res 64 | .status(400) 65 | .json({ error: "Couldn't start the authentication process" }); 66 | } 67 | })); 68 | // Validate the emailToken 69 | // Generate a long-lived JWT token 70 | router.post('/authenticate', (req, res) => __awaiter(void 0, void 0, void 0, function* () { 71 | var _a; 72 | const { email, emailToken } = req.body; 73 | const dbEmailToken = yield prisma.token.findUnique({ 74 | where: { 75 | emailToken, 76 | }, 77 | include: { 78 | user: true, 79 | }, 80 | }); 81 | if (!dbEmailToken || !dbEmailToken.valid) { 82 | return res.sendStatus(401); 83 | } 84 | if (dbEmailToken.expiration < new Date()) { 85 | return res.status(401).json({ error: 'Token expired!' }); 86 | } 87 | if (((_a = dbEmailToken === null || dbEmailToken === void 0 ? void 0 : dbEmailToken.user) === null || _a === void 0 ? void 0 : _a.email) !== email) { 88 | return res.sendStatus(401); 89 | } 90 | // Here we validated that the user is the owner of the email 91 | // generate an API token 92 | const expiration = new Date(new Date().getTime() + AUTHENTICATION_EXPIRATION_HOURS * 60 * 60 * 1000); 93 | const apiToken = yield prisma.token.create({ 94 | data: { 95 | type: 'API', 96 | expiration, 97 | user: { 98 | connect: { 99 | email, 100 | }, 101 | }, 102 | }, 103 | }); 104 | // Invalidate the email 105 | yield prisma.token.update({ 106 | where: { id: dbEmailToken.id }, 107 | data: { valid: false }, 108 | }); 109 | // generate the JWT token 110 | const authToken = generateAuthToken(apiToken.id); 111 | res.json({ authToken }); 112 | })); 113 | exports.default = router; 114 | -------------------------------------------------------------------------------- /build/routes/tweetRoutes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | const express_1 = require("express"); 13 | const client_1 = require("@prisma/client"); 14 | const router = (0, express_1.Router)(); 15 | const prisma = new client_1.PrismaClient(); 16 | // Tweet CRUD 17 | // Create Tweet 18 | router.post('/', (req, res) => __awaiter(void 0, void 0, void 0, function* () { 19 | const { content, image } = req.body; 20 | // @ts-ignore 21 | const user = req.user; 22 | try { 23 | const result = yield prisma.tweet.create({ 24 | data: { 25 | content, 26 | image, 27 | userId: user.id, 28 | }, 29 | include: { user: true }, 30 | }); 31 | res.json(result); 32 | } 33 | catch (e) { 34 | res.status(400).json({ error: 'Username and email should be unique' }); 35 | } 36 | })); 37 | // list Tweet 38 | router.get('/', (req, res) => __awaiter(void 0, void 0, void 0, function* () { 39 | const allTweets = yield prisma.tweet.findMany({ 40 | include: { 41 | user: { 42 | select: { 43 | id: true, 44 | name: true, 45 | username: true, 46 | image: true, 47 | }, 48 | }, 49 | }, 50 | }); 51 | res.json(allTweets); 52 | })); 53 | // get one Tweet 54 | router.get('/:id', (req, res) => __awaiter(void 0, void 0, void 0, function* () { 55 | const { id } = req.params; 56 | console.log('Query tweet with id: ', id); 57 | const tweet = yield prisma.tweet.findUnique({ 58 | where: { id: Number(id) }, 59 | include: { user: true }, 60 | }); 61 | if (!tweet) { 62 | return res.status(404).json({ error: 'Tweet not found!' }); 63 | } 64 | res.json(tweet); 65 | })); 66 | // update Tweet 67 | router.put('/:id', (req, res) => { 68 | const { id } = req.params; 69 | res.status(501).json({ error: `Not Implemented: ${id}` }); 70 | }); 71 | // delete Tweet 72 | router.delete('/:id', (req, res) => __awaiter(void 0, void 0, void 0, function* () { 73 | const { id } = req.params; 74 | yield prisma.tweet.delete({ where: { id: Number(id) } }); 75 | res.sendStatus(200); 76 | })); 77 | exports.default = router; 78 | -------------------------------------------------------------------------------- /build/routes/userRoutes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | const express_1 = require("express"); 13 | const client_1 = require("@prisma/client"); 14 | const router = (0, express_1.Router)(); 15 | const prisma = new client_1.PrismaClient(); 16 | // User CRUD 17 | /* 18 | Test with curl: 19 | 20 | curl -X POST -H "Content-Type: application/json" \ 21 | -d '{"name": "Elon Musk", "email": "doge@twitter.com", "username": "elon"}' \ 22 | http://localhost:3000/user/ 23 | 24 | */ 25 | // Create user 26 | router.post('/', (req, res) => __awaiter(void 0, void 0, void 0, function* () { 27 | const { email, name, username } = req.body; 28 | try { 29 | const result = yield prisma.user.create({ 30 | data: { 31 | email, 32 | name, 33 | username, 34 | bio: "Hello, I'm new on Twitter", 35 | }, 36 | }); 37 | res.json(result); 38 | } 39 | catch (e) { 40 | res.status(400).json({ error: 'Username and email should be unique' }); 41 | } 42 | })); 43 | // list users 44 | router.get('/', (req, res) => __awaiter(void 0, void 0, void 0, function* () { 45 | const allUser = yield prisma.user.findMany({ 46 | // select: { 47 | // id: true, 48 | // name: true, 49 | // image: true, 50 | // bio: true, 51 | // }, 52 | }); 53 | res.json(allUser); 54 | })); 55 | // get one user 56 | router.get('/:id', (req, res) => __awaiter(void 0, void 0, void 0, function* () { 57 | const { id } = req.params; 58 | const user = yield prisma.user.findUnique({ 59 | where: { id: Number(id) }, 60 | include: { tweets: true }, 61 | }); 62 | res.json(user); 63 | })); 64 | /* 65 | Test with curl: 66 | 67 | curl -X PUT -H "Content-Type: application/json" \ 68 | -d '{"name": "Vadim", "bio": "Hello there!"}' \ 69 | http://localhost:3000/user/1 70 | 71 | */ 72 | // update user 73 | router.put('/:id', (req, res) => __awaiter(void 0, void 0, void 0, function* () { 74 | const { id } = req.params; 75 | const { bio, name, image } = req.body; 76 | try { 77 | const result = yield prisma.user.update({ 78 | where: { id: Number(id) }, 79 | data: { bio, name, image }, 80 | }); 81 | res.json(result); 82 | } 83 | catch (e) { 84 | res.status(400).json({ error: `Failed to update the user` }); 85 | } 86 | })); 87 | // curl -X DELETE http://localhost:3000/user/6 88 | // delete user 89 | router.delete('/:id', (req, res) => __awaiter(void 0, void 0, void 0, function* () { 90 | const { id } = req.params; 91 | yield prisma.user.delete({ where: { id: Number(id) } }); 92 | res.sendStatus(200); 93 | })); 94 | exports.default = router; 95 | -------------------------------------------------------------------------------- /build/services/emailService.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.sendEmailToken = void 0; 13 | const client_ses_1 = require("@aws-sdk/client-ses"); 14 | const console_1 = require("console"); 15 | require('dotenv').config(); 16 | const ses = new client_ses_1.SESClient({}); 17 | function createSendEmailCommand(toAddress, fromAddress, message) { 18 | return new client_ses_1.SendEmailCommand({ 19 | Destination: { 20 | ToAddresses: [toAddress], 21 | }, 22 | Source: fromAddress, 23 | Message: { 24 | Subject: { 25 | Charset: 'UTF-8', 26 | Data: 'Your one-time password', 27 | }, 28 | Body: { 29 | Text: { 30 | Charset: 'UTF-8', 31 | Data: message, 32 | }, 33 | }, 34 | }, 35 | }); 36 | } 37 | function sendEmailToken(email, token) { 38 | return __awaiter(this, void 0, void 0, function* () { 39 | console.log('email: ', email, token); 40 | const message = `Your one time password: ${token}`; 41 | const command = createSendEmailCommand(email, 'savinvadim1312@gmail.com', message); 42 | try { 43 | return yield ses.send(command); 44 | } 45 | catch (e) { 46 | console.log('Error sending email', e); 47 | return console_1.error; 48 | } 49 | }); 50 | } 51 | exports.sendEmailToken = sendEmailToken; 52 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twitterbackend", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "twitterbackend", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@aws-sdk/client-ses": "^3.327.0", 13 | "@prisma/client": "^4.13.0", 14 | "dotenv": "^16.0.3", 15 | "express": "^4.18.2", 16 | "jsonwebtoken": "^9.0.0" 17 | }, 18 | "devDependencies": { 19 | "@types/express": "^4.17.17", 20 | "@types/jsonwebtoken": "^9.0.2", 21 | "@types/node": "^20.0.0", 22 | "nodemon": "^2.0.22", 23 | "prisma": "^4.13.0", 24 | "ts-node": "^10.9.1", 25 | "typescript": "^5.0.4" 26 | } 27 | }, 28 | "node_modules/@aws-crypto/ie11-detection": { 29 | "version": "3.0.0", 30 | "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", 31 | "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", 32 | "dependencies": { 33 | "tslib": "^1.11.1" 34 | } 35 | }, 36 | "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { 37 | "version": "1.14.1", 38 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 39 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" 40 | }, 41 | "node_modules/@aws-crypto/sha256-browser": { 42 | "version": "3.0.0", 43 | "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", 44 | "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", 45 | "dependencies": { 46 | "@aws-crypto/ie11-detection": "^3.0.0", 47 | "@aws-crypto/sha256-js": "^3.0.0", 48 | "@aws-crypto/supports-web-crypto": "^3.0.0", 49 | "@aws-crypto/util": "^3.0.0", 50 | "@aws-sdk/types": "^3.222.0", 51 | "@aws-sdk/util-locate-window": "^3.0.0", 52 | "@aws-sdk/util-utf8-browser": "^3.0.0", 53 | "tslib": "^1.11.1" 54 | } 55 | }, 56 | "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { 57 | "version": "1.14.1", 58 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 59 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" 60 | }, 61 | "node_modules/@aws-crypto/sha256-js": { 62 | "version": "3.0.0", 63 | "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", 64 | "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", 65 | "dependencies": { 66 | "@aws-crypto/util": "^3.0.0", 67 | "@aws-sdk/types": "^3.222.0", 68 | "tslib": "^1.11.1" 69 | } 70 | }, 71 | "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { 72 | "version": "1.14.1", 73 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 74 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" 75 | }, 76 | "node_modules/@aws-crypto/supports-web-crypto": { 77 | "version": "3.0.0", 78 | "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", 79 | "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", 80 | "dependencies": { 81 | "tslib": "^1.11.1" 82 | } 83 | }, 84 | "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { 85 | "version": "1.14.1", 86 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 87 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" 88 | }, 89 | "node_modules/@aws-crypto/util": { 90 | "version": "3.0.0", 91 | "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", 92 | "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", 93 | "dependencies": { 94 | "@aws-sdk/types": "^3.222.0", 95 | "@aws-sdk/util-utf8-browser": "^3.0.0", 96 | "tslib": "^1.11.1" 97 | } 98 | }, 99 | "node_modules/@aws-crypto/util/node_modules/tslib": { 100 | "version": "1.14.1", 101 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 102 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" 103 | }, 104 | "node_modules/@aws-sdk/abort-controller": { 105 | "version": "3.310.0", 106 | "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.310.0.tgz", 107 | "integrity": "sha512-v1zrRQxDLA1MdPim159Vx/CPHqsB4uybSxRi1CnfHO5ZjHryx3a5htW2gdGAykVCul40+yJXvfpufMrELVxH+g==", 108 | "dependencies": { 109 | "@aws-sdk/types": "3.310.0", 110 | "tslib": "^2.5.0" 111 | }, 112 | "engines": { 113 | "node": ">=14.0.0" 114 | } 115 | }, 116 | "node_modules/@aws-sdk/client-ses": { 117 | "version": "3.327.0", 118 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.327.0.tgz", 119 | "integrity": "sha512-QZgIC7gwgDxlkgiR26/GD19OyQveXKmo/hWy1Rn89iCqvt2nObjn0JDS7cCOLUxc6dIous/yLvLruE6YncO6zg==", 120 | "dependencies": { 121 | "@aws-crypto/sha256-browser": "3.0.0", 122 | "@aws-crypto/sha256-js": "3.0.0", 123 | "@aws-sdk/client-sts": "3.327.0", 124 | "@aws-sdk/config-resolver": "3.310.0", 125 | "@aws-sdk/credential-provider-node": "3.327.0", 126 | "@aws-sdk/fetch-http-handler": "3.310.0", 127 | "@aws-sdk/hash-node": "3.310.0", 128 | "@aws-sdk/invalid-dependency": "3.310.0", 129 | "@aws-sdk/middleware-content-length": "3.325.0", 130 | "@aws-sdk/middleware-endpoint": "3.325.0", 131 | "@aws-sdk/middleware-host-header": "3.325.0", 132 | "@aws-sdk/middleware-logger": "3.325.0", 133 | "@aws-sdk/middleware-recursion-detection": "3.325.0", 134 | "@aws-sdk/middleware-retry": "3.327.0", 135 | "@aws-sdk/middleware-serde": "3.325.0", 136 | "@aws-sdk/middleware-signing": "3.325.0", 137 | "@aws-sdk/middleware-stack": "3.325.0", 138 | "@aws-sdk/middleware-user-agent": "3.327.0", 139 | "@aws-sdk/node-config-provider": "3.310.0", 140 | "@aws-sdk/node-http-handler": "3.321.1", 141 | "@aws-sdk/protocol-http": "3.310.0", 142 | "@aws-sdk/smithy-client": "3.325.0", 143 | "@aws-sdk/types": "3.310.0", 144 | "@aws-sdk/url-parser": "3.310.0", 145 | "@aws-sdk/util-base64": "3.310.0", 146 | "@aws-sdk/util-body-length-browser": "3.310.0", 147 | "@aws-sdk/util-body-length-node": "3.310.0", 148 | "@aws-sdk/util-defaults-mode-browser": "3.325.0", 149 | "@aws-sdk/util-defaults-mode-node": "3.325.0", 150 | "@aws-sdk/util-endpoints": "3.327.0", 151 | "@aws-sdk/util-retry": "3.327.0", 152 | "@aws-sdk/util-user-agent-browser": "3.310.0", 153 | "@aws-sdk/util-user-agent-node": "3.310.0", 154 | "@aws-sdk/util-utf8": "3.310.0", 155 | "@aws-sdk/util-waiter": "3.310.0", 156 | "fast-xml-parser": "4.1.2", 157 | "tslib": "^2.5.0" 158 | }, 159 | "engines": { 160 | "node": ">=14.0.0" 161 | } 162 | }, 163 | "node_modules/@aws-sdk/client-sso": { 164 | "version": "3.327.0", 165 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.327.0.tgz", 166 | "integrity": "sha512-4cJzDs5GHSED47QYo3LSgqX+CBtKV0lp6HugkX5pvERB+FGCNLenUcSzyU93BCV2oWUP4K+m7dxV6h3RmD4/ow==", 167 | "dependencies": { 168 | "@aws-crypto/sha256-browser": "3.0.0", 169 | "@aws-crypto/sha256-js": "3.0.0", 170 | "@aws-sdk/config-resolver": "3.310.0", 171 | "@aws-sdk/fetch-http-handler": "3.310.0", 172 | "@aws-sdk/hash-node": "3.310.0", 173 | "@aws-sdk/invalid-dependency": "3.310.0", 174 | "@aws-sdk/middleware-content-length": "3.325.0", 175 | "@aws-sdk/middleware-endpoint": "3.325.0", 176 | "@aws-sdk/middleware-host-header": "3.325.0", 177 | "@aws-sdk/middleware-logger": "3.325.0", 178 | "@aws-sdk/middleware-recursion-detection": "3.325.0", 179 | "@aws-sdk/middleware-retry": "3.327.0", 180 | "@aws-sdk/middleware-serde": "3.325.0", 181 | "@aws-sdk/middleware-stack": "3.325.0", 182 | "@aws-sdk/middleware-user-agent": "3.327.0", 183 | "@aws-sdk/node-config-provider": "3.310.0", 184 | "@aws-sdk/node-http-handler": "3.321.1", 185 | "@aws-sdk/protocol-http": "3.310.0", 186 | "@aws-sdk/smithy-client": "3.325.0", 187 | "@aws-sdk/types": "3.310.0", 188 | "@aws-sdk/url-parser": "3.310.0", 189 | "@aws-sdk/util-base64": "3.310.0", 190 | "@aws-sdk/util-body-length-browser": "3.310.0", 191 | "@aws-sdk/util-body-length-node": "3.310.0", 192 | "@aws-sdk/util-defaults-mode-browser": "3.325.0", 193 | "@aws-sdk/util-defaults-mode-node": "3.325.0", 194 | "@aws-sdk/util-endpoints": "3.327.0", 195 | "@aws-sdk/util-retry": "3.327.0", 196 | "@aws-sdk/util-user-agent-browser": "3.310.0", 197 | "@aws-sdk/util-user-agent-node": "3.310.0", 198 | "@aws-sdk/util-utf8": "3.310.0", 199 | "tslib": "^2.5.0" 200 | }, 201 | "engines": { 202 | "node": ">=14.0.0" 203 | } 204 | }, 205 | "node_modules/@aws-sdk/client-sso-oidc": { 206 | "version": "3.327.0", 207 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.327.0.tgz", 208 | "integrity": "sha512-sN7uvHT2TYkLRTNnfrdeWoJoryeWOEuEwd4i52AKSq6QBgRnQm897yAe3y4Pe9vjz3F38butgfx+PKwD0xJQFw==", 209 | "dependencies": { 210 | "@aws-crypto/sha256-browser": "3.0.0", 211 | "@aws-crypto/sha256-js": "3.0.0", 212 | "@aws-sdk/config-resolver": "3.310.0", 213 | "@aws-sdk/fetch-http-handler": "3.310.0", 214 | "@aws-sdk/hash-node": "3.310.0", 215 | "@aws-sdk/invalid-dependency": "3.310.0", 216 | "@aws-sdk/middleware-content-length": "3.325.0", 217 | "@aws-sdk/middleware-endpoint": "3.325.0", 218 | "@aws-sdk/middleware-host-header": "3.325.0", 219 | "@aws-sdk/middleware-logger": "3.325.0", 220 | "@aws-sdk/middleware-recursion-detection": "3.325.0", 221 | "@aws-sdk/middleware-retry": "3.327.0", 222 | "@aws-sdk/middleware-serde": "3.325.0", 223 | "@aws-sdk/middleware-stack": "3.325.0", 224 | "@aws-sdk/middleware-user-agent": "3.327.0", 225 | "@aws-sdk/node-config-provider": "3.310.0", 226 | "@aws-sdk/node-http-handler": "3.321.1", 227 | "@aws-sdk/protocol-http": "3.310.0", 228 | "@aws-sdk/smithy-client": "3.325.0", 229 | "@aws-sdk/types": "3.310.0", 230 | "@aws-sdk/url-parser": "3.310.0", 231 | "@aws-sdk/util-base64": "3.310.0", 232 | "@aws-sdk/util-body-length-browser": "3.310.0", 233 | "@aws-sdk/util-body-length-node": "3.310.0", 234 | "@aws-sdk/util-defaults-mode-browser": "3.325.0", 235 | "@aws-sdk/util-defaults-mode-node": "3.325.0", 236 | "@aws-sdk/util-endpoints": "3.327.0", 237 | "@aws-sdk/util-retry": "3.327.0", 238 | "@aws-sdk/util-user-agent-browser": "3.310.0", 239 | "@aws-sdk/util-user-agent-node": "3.310.0", 240 | "@aws-sdk/util-utf8": "3.310.0", 241 | "tslib": "^2.5.0" 242 | }, 243 | "engines": { 244 | "node": ">=14.0.0" 245 | } 246 | }, 247 | "node_modules/@aws-sdk/client-sts": { 248 | "version": "3.327.0", 249 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.327.0.tgz", 250 | "integrity": "sha512-9gNE2QjcDZIVMSdSYkEX+biWkgn7yhk43j7Mj65o4vVWagv3S2ubDm/ofz4hfaZw16U3je/hyRxprGpT/iCABw==", 251 | "dependencies": { 252 | "@aws-crypto/sha256-browser": "3.0.0", 253 | "@aws-crypto/sha256-js": "3.0.0", 254 | "@aws-sdk/config-resolver": "3.310.0", 255 | "@aws-sdk/credential-provider-node": "3.327.0", 256 | "@aws-sdk/fetch-http-handler": "3.310.0", 257 | "@aws-sdk/hash-node": "3.310.0", 258 | "@aws-sdk/invalid-dependency": "3.310.0", 259 | "@aws-sdk/middleware-content-length": "3.325.0", 260 | "@aws-sdk/middleware-endpoint": "3.325.0", 261 | "@aws-sdk/middleware-host-header": "3.325.0", 262 | "@aws-sdk/middleware-logger": "3.325.0", 263 | "@aws-sdk/middleware-recursion-detection": "3.325.0", 264 | "@aws-sdk/middleware-retry": "3.327.0", 265 | "@aws-sdk/middleware-sdk-sts": "3.326.0", 266 | "@aws-sdk/middleware-serde": "3.325.0", 267 | "@aws-sdk/middleware-signing": "3.325.0", 268 | "@aws-sdk/middleware-stack": "3.325.0", 269 | "@aws-sdk/middleware-user-agent": "3.327.0", 270 | "@aws-sdk/node-config-provider": "3.310.0", 271 | "@aws-sdk/node-http-handler": "3.321.1", 272 | "@aws-sdk/protocol-http": "3.310.0", 273 | "@aws-sdk/smithy-client": "3.325.0", 274 | "@aws-sdk/types": "3.310.0", 275 | "@aws-sdk/url-parser": "3.310.0", 276 | "@aws-sdk/util-base64": "3.310.0", 277 | "@aws-sdk/util-body-length-browser": "3.310.0", 278 | "@aws-sdk/util-body-length-node": "3.310.0", 279 | "@aws-sdk/util-defaults-mode-browser": "3.325.0", 280 | "@aws-sdk/util-defaults-mode-node": "3.325.0", 281 | "@aws-sdk/util-endpoints": "3.327.0", 282 | "@aws-sdk/util-retry": "3.327.0", 283 | "@aws-sdk/util-user-agent-browser": "3.310.0", 284 | "@aws-sdk/util-user-agent-node": "3.310.0", 285 | "@aws-sdk/util-utf8": "3.310.0", 286 | "fast-xml-parser": "4.1.2", 287 | "tslib": "^2.5.0" 288 | }, 289 | "engines": { 290 | "node": ">=14.0.0" 291 | } 292 | }, 293 | "node_modules/@aws-sdk/config-resolver": { 294 | "version": "3.310.0", 295 | "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.310.0.tgz", 296 | "integrity": "sha512-8vsT+/50lOqfDxka9m/rRt6oxv1WuGZoP8oPMk0Dt+TxXMbAzf4+rejBgiB96wshI1k3gLokYRjSQZn+dDtT8g==", 297 | "dependencies": { 298 | "@aws-sdk/types": "3.310.0", 299 | "@aws-sdk/util-config-provider": "3.310.0", 300 | "@aws-sdk/util-middleware": "3.310.0", 301 | "tslib": "^2.5.0" 302 | }, 303 | "engines": { 304 | "node": ">=14.0.0" 305 | } 306 | }, 307 | "node_modules/@aws-sdk/credential-provider-env": { 308 | "version": "3.310.0", 309 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.310.0.tgz", 310 | "integrity": "sha512-vvIPQpI16fj95xwS7M3D48F7QhZJBnnCgB5lR+b7So+vsG9ibm1mZRVGzVpdxCvgyOhHFbvrby9aalNJmmIP1A==", 311 | "dependencies": { 312 | "@aws-sdk/property-provider": "3.310.0", 313 | "@aws-sdk/types": "3.310.0", 314 | "tslib": "^2.5.0" 315 | }, 316 | "engines": { 317 | "node": ">=14.0.0" 318 | } 319 | }, 320 | "node_modules/@aws-sdk/credential-provider-imds": { 321 | "version": "3.310.0", 322 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.310.0.tgz", 323 | "integrity": "sha512-baxK7Zp6dai5AGW01FIW27xS2KAaPUmKLIXv5SvFYsUgXXvNW55im4uG3b+2gA0F7V+hXvVBH08OEqmwW6we5w==", 324 | "dependencies": { 325 | "@aws-sdk/node-config-provider": "3.310.0", 326 | "@aws-sdk/property-provider": "3.310.0", 327 | "@aws-sdk/types": "3.310.0", 328 | "@aws-sdk/url-parser": "3.310.0", 329 | "tslib": "^2.5.0" 330 | }, 331 | "engines": { 332 | "node": ">=14.0.0" 333 | } 334 | }, 335 | "node_modules/@aws-sdk/credential-provider-ini": { 336 | "version": "3.327.0", 337 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.327.0.tgz", 338 | "integrity": "sha512-pB1wb5kbvg77ouXyDXXxZcDkShBq9bk10qdu5nGOlazC5dFZ61lKnVipd/3zkGm0PVdeac7PsHnbi+d8uRKE0Q==", 339 | "dependencies": { 340 | "@aws-sdk/credential-provider-env": "3.310.0", 341 | "@aws-sdk/credential-provider-imds": "3.310.0", 342 | "@aws-sdk/credential-provider-process": "3.310.0", 343 | "@aws-sdk/credential-provider-sso": "3.327.0", 344 | "@aws-sdk/credential-provider-web-identity": "3.310.0", 345 | "@aws-sdk/property-provider": "3.310.0", 346 | "@aws-sdk/shared-ini-file-loader": "3.310.0", 347 | "@aws-sdk/types": "3.310.0", 348 | "tslib": "^2.5.0" 349 | }, 350 | "engines": { 351 | "node": ">=14.0.0" 352 | } 353 | }, 354 | "node_modules/@aws-sdk/credential-provider-node": { 355 | "version": "3.327.0", 356 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.327.0.tgz", 357 | "integrity": "sha512-fHlS5/V8qfyPyxPcL609xnpEuDRW2KiVRsi4WkikYdJsUREDS1UeQ5AS9xFY1ARFeQuoFDjJ1XeiWYyKZep1yw==", 358 | "dependencies": { 359 | "@aws-sdk/credential-provider-env": "3.310.0", 360 | "@aws-sdk/credential-provider-imds": "3.310.0", 361 | "@aws-sdk/credential-provider-ini": "3.327.0", 362 | "@aws-sdk/credential-provider-process": "3.310.0", 363 | "@aws-sdk/credential-provider-sso": "3.327.0", 364 | "@aws-sdk/credential-provider-web-identity": "3.310.0", 365 | "@aws-sdk/property-provider": "3.310.0", 366 | "@aws-sdk/shared-ini-file-loader": "3.310.0", 367 | "@aws-sdk/types": "3.310.0", 368 | "tslib": "^2.5.0" 369 | }, 370 | "engines": { 371 | "node": ">=14.0.0" 372 | } 373 | }, 374 | "node_modules/@aws-sdk/credential-provider-process": { 375 | "version": "3.310.0", 376 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.310.0.tgz", 377 | "integrity": "sha512-h73sg6GPMUWC+3zMCbA1nZ2O03nNJt7G96JdmnantiXBwHpRKWW8nBTLzx5uhXn6hTuTaoQRP/P+oxQJKYdMmA==", 378 | "dependencies": { 379 | "@aws-sdk/property-provider": "3.310.0", 380 | "@aws-sdk/shared-ini-file-loader": "3.310.0", 381 | "@aws-sdk/types": "3.310.0", 382 | "tslib": "^2.5.0" 383 | }, 384 | "engines": { 385 | "node": ">=14.0.0" 386 | } 387 | }, 388 | "node_modules/@aws-sdk/credential-provider-sso": { 389 | "version": "3.327.0", 390 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.327.0.tgz", 391 | "integrity": "sha512-BiY87WKAgnBjN5Hfm2LBcJ/0gRnRwvBAG09MrsyTwGju8FYGV+e0YvFrT70CKFMUFD9t5/eztntox+q7sHOXkg==", 392 | "dependencies": { 393 | "@aws-sdk/client-sso": "3.327.0", 394 | "@aws-sdk/property-provider": "3.310.0", 395 | "@aws-sdk/shared-ini-file-loader": "3.310.0", 396 | "@aws-sdk/token-providers": "3.327.0", 397 | "@aws-sdk/types": "3.310.0", 398 | "tslib": "^2.5.0" 399 | }, 400 | "engines": { 401 | "node": ">=14.0.0" 402 | } 403 | }, 404 | "node_modules/@aws-sdk/credential-provider-web-identity": { 405 | "version": "3.310.0", 406 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.310.0.tgz", 407 | "integrity": "sha512-H4SzuZXILNhK6/IR1uVvsUDZvzc051hem7GLyYghBCu8mU+tq28YhKE8MfSroi6eL2e5Vujloij1OM2EQQkPkw==", 408 | "dependencies": { 409 | "@aws-sdk/property-provider": "3.310.0", 410 | "@aws-sdk/types": "3.310.0", 411 | "tslib": "^2.5.0" 412 | }, 413 | "engines": { 414 | "node": ">=14.0.0" 415 | } 416 | }, 417 | "node_modules/@aws-sdk/fetch-http-handler": { 418 | "version": "3.310.0", 419 | "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.310.0.tgz", 420 | "integrity": "sha512-Bi9vIwzdkw1zMcvi/zGzlWS9KfIEnAq4NNhsnCxbQ4OoIRU9wvU+WGZdBBhxg0ZxZmpp1j1aZhU53lLjA07MHw==", 421 | "dependencies": { 422 | "@aws-sdk/protocol-http": "3.310.0", 423 | "@aws-sdk/querystring-builder": "3.310.0", 424 | "@aws-sdk/types": "3.310.0", 425 | "@aws-sdk/util-base64": "3.310.0", 426 | "tslib": "^2.5.0" 427 | } 428 | }, 429 | "node_modules/@aws-sdk/hash-node": { 430 | "version": "3.310.0", 431 | "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.310.0.tgz", 432 | "integrity": "sha512-NvE2fhRc8GRwCXBfDehxVAWCmVwVMILliAKVPAEr4yz2CkYs0tqU51S48x23dtna07H4qHtgpeNqVTthcIQOEQ==", 433 | "dependencies": { 434 | "@aws-sdk/types": "3.310.0", 435 | "@aws-sdk/util-buffer-from": "3.310.0", 436 | "@aws-sdk/util-utf8": "3.310.0", 437 | "tslib": "^2.5.0" 438 | }, 439 | "engines": { 440 | "node": ">=14.0.0" 441 | } 442 | }, 443 | "node_modules/@aws-sdk/invalid-dependency": { 444 | "version": "3.310.0", 445 | "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.310.0.tgz", 446 | "integrity": "sha512-1s5RG5rSPXoa/aZ/Kqr5U/7lqpx+Ry81GprQ2bxWqJvWQIJ0IRUwo5pk8XFxbKVr/2a+4lZT/c3OGoBOM1yRRA==", 447 | "dependencies": { 448 | "@aws-sdk/types": "3.310.0", 449 | "tslib": "^2.5.0" 450 | } 451 | }, 452 | "node_modules/@aws-sdk/is-array-buffer": { 453 | "version": "3.310.0", 454 | "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.310.0.tgz", 455 | "integrity": "sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==", 456 | "dependencies": { 457 | "tslib": "^2.5.0" 458 | }, 459 | "engines": { 460 | "node": ">=14.0.0" 461 | } 462 | }, 463 | "node_modules/@aws-sdk/middleware-content-length": { 464 | "version": "3.325.0", 465 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.325.0.tgz", 466 | "integrity": "sha512-t38VBKCpNqSKqSu0OfWMJs7cwaRHFGQxIF9lV8JMCM/2lyUpN4JcfuzSTK+MFN2eDZEHp5DiNg8w07GXXusRYg==", 467 | "dependencies": { 468 | "@aws-sdk/protocol-http": "3.310.0", 469 | "@aws-sdk/types": "3.310.0", 470 | "tslib": "^2.5.0" 471 | }, 472 | "engines": { 473 | "node": ">=14.0.0" 474 | } 475 | }, 476 | "node_modules/@aws-sdk/middleware-endpoint": { 477 | "version": "3.325.0", 478 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.325.0.tgz", 479 | "integrity": "sha512-3CavuOHCKiWUnCtzrUFbhbEP26qIgzzRs5C3vpOJhDUhugBubIWgPGGRLpbnIro+P4XJPwM3pMziNzhKVuSDlQ==", 480 | "dependencies": { 481 | "@aws-sdk/middleware-serde": "3.325.0", 482 | "@aws-sdk/types": "3.310.0", 483 | "@aws-sdk/url-parser": "3.310.0", 484 | "@aws-sdk/util-middleware": "3.310.0", 485 | "tslib": "^2.5.0" 486 | }, 487 | "engines": { 488 | "node": ">=14.0.0" 489 | } 490 | }, 491 | "node_modules/@aws-sdk/middleware-host-header": { 492 | "version": "3.325.0", 493 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.325.0.tgz", 494 | "integrity": "sha512-IN28gsxcRy4J+FxxCHvzb2NORBx8uMA+h9QYS4BBZfpKVYIZh+mudHgYcdNHWlKXmlTGjhWBNWTeByhzuSKAiA==", 495 | "dependencies": { 496 | "@aws-sdk/protocol-http": "3.310.0", 497 | "@aws-sdk/types": "3.310.0", 498 | "tslib": "^2.5.0" 499 | }, 500 | "engines": { 501 | "node": ">=14.0.0" 502 | } 503 | }, 504 | "node_modules/@aws-sdk/middleware-logger": { 505 | "version": "3.325.0", 506 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.325.0.tgz", 507 | "integrity": "sha512-S8rWgTpN2b/+UDDm+yZMFM6rw1zwO8KT0GAIQbAhB96shyD5eKen/UfihCTB7YMvbD2piebymwJTvxv6bn1VqQ==", 508 | "dependencies": { 509 | "@aws-sdk/types": "3.310.0", 510 | "tslib": "^2.5.0" 511 | }, 512 | "engines": { 513 | "node": ">=14.0.0" 514 | } 515 | }, 516 | "node_modules/@aws-sdk/middleware-recursion-detection": { 517 | "version": "3.325.0", 518 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.325.0.tgz", 519 | "integrity": "sha512-2l1ABF7KePsoKz8KaNvD2uxo1zHqkFHK4PL/wW/FbcwOcE08f0R7qX++st/bPpVjXX/j/5vWTnNNgJOIOrZhyw==", 520 | "dependencies": { 521 | "@aws-sdk/protocol-http": "3.310.0", 522 | "@aws-sdk/types": "3.310.0", 523 | "tslib": "^2.5.0" 524 | }, 525 | "engines": { 526 | "node": ">=14.0.0" 527 | } 528 | }, 529 | "node_modules/@aws-sdk/middleware-retry": { 530 | "version": "3.327.0", 531 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.327.0.tgz", 532 | "integrity": "sha512-LCG+oRIPc4XJ+DYqkSCgggavxWi4+hP3Rw40vHdHMNvJpCiUJMwVJ+dULEywEP/WZvr4AEkWiRrHmJVpSLeZ+Q==", 533 | "dependencies": { 534 | "@aws-sdk/protocol-http": "3.310.0", 535 | "@aws-sdk/service-error-classification": "3.327.0", 536 | "@aws-sdk/types": "3.310.0", 537 | "@aws-sdk/util-middleware": "3.310.0", 538 | "@aws-sdk/util-retry": "3.327.0", 539 | "tslib": "^2.5.0", 540 | "uuid": "^8.3.2" 541 | }, 542 | "engines": { 543 | "node": ">=14.0.0" 544 | } 545 | }, 546 | "node_modules/@aws-sdk/middleware-sdk-sts": { 547 | "version": "3.326.0", 548 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.326.0.tgz", 549 | "integrity": "sha512-suOkuXxyAfOH0hznK63ZU10EoytKX5YPs9amO416VbgYFtuIeliCmntYfnl1jUvutp0fctGGpEGE9OnoYI+fhw==", 550 | "dependencies": { 551 | "@aws-sdk/middleware-signing": "3.325.0", 552 | "@aws-sdk/types": "3.310.0", 553 | "tslib": "^2.5.0" 554 | }, 555 | "engines": { 556 | "node": ">=14.0.0" 557 | } 558 | }, 559 | "node_modules/@aws-sdk/middleware-serde": { 560 | "version": "3.325.0", 561 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.325.0.tgz", 562 | "integrity": "sha512-QAZYaFfAw1a06Vg39JiYIq0kSJ6EuUPOiKfK/Goj0cBv78lrXWuKdf04UF3U8Rqk/4mamnsTqUSwf4NoKkF0hw==", 563 | "dependencies": { 564 | "@aws-sdk/types": "3.310.0", 565 | "tslib": "^2.5.0" 566 | }, 567 | "engines": { 568 | "node": ">=14.0.0" 569 | } 570 | }, 571 | "node_modules/@aws-sdk/middleware-signing": { 572 | "version": "3.325.0", 573 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.325.0.tgz", 574 | "integrity": "sha512-SOwPwaCE3vSCGwFzkIlnOUSkeCUzKTyIQnFVjlQkqGuMxMX/iDaQQGaX+HUbuGIuULCEQqjZH4dLKZcor8eVZw==", 575 | "dependencies": { 576 | "@aws-sdk/property-provider": "3.310.0", 577 | "@aws-sdk/protocol-http": "3.310.0", 578 | "@aws-sdk/signature-v4": "3.310.0", 579 | "@aws-sdk/types": "3.310.0", 580 | "@aws-sdk/util-middleware": "3.310.0", 581 | "tslib": "^2.5.0" 582 | }, 583 | "engines": { 584 | "node": ">=14.0.0" 585 | } 586 | }, 587 | "node_modules/@aws-sdk/middleware-stack": { 588 | "version": "3.325.0", 589 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.325.0.tgz", 590 | "integrity": "sha512-cZWehA4grGvX1IKlY9atJgD0bq3ew7YRJgY7GA6DSgsU7GrZ61Qvi+H7IuGx5AdeAwaTnbnTGN4qCaA2EfxNhA==", 591 | "dependencies": { 592 | "tslib": "^2.5.0" 593 | }, 594 | "engines": { 595 | "node": ">=14.0.0" 596 | } 597 | }, 598 | "node_modules/@aws-sdk/middleware-user-agent": { 599 | "version": "3.327.0", 600 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.327.0.tgz", 601 | "integrity": "sha512-4rDSNY1xhlqfRcY97CQKcgs6AOe4ovtiRdCAjg2InnLOZHRVFoHhOIDxWNK2W1K2Pl65z4EGH6RXmB1t0srJHA==", 602 | "dependencies": { 603 | "@aws-sdk/protocol-http": "3.310.0", 604 | "@aws-sdk/types": "3.310.0", 605 | "@aws-sdk/util-endpoints": "3.327.0", 606 | "tslib": "^2.5.0" 607 | }, 608 | "engines": { 609 | "node": ">=14.0.0" 610 | } 611 | }, 612 | "node_modules/@aws-sdk/node-config-provider": { 613 | "version": "3.310.0", 614 | "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.310.0.tgz", 615 | "integrity": "sha512-T/Pp6htc6hq/Cq+MLNDSyiwWCMVF6GqbBbXKVlO5L8rdHx4sq9xPdoPveZhGWrxvkanjA6eCwUp6E0riBOSVng==", 616 | "dependencies": { 617 | "@aws-sdk/property-provider": "3.310.0", 618 | "@aws-sdk/shared-ini-file-loader": "3.310.0", 619 | "@aws-sdk/types": "3.310.0", 620 | "tslib": "^2.5.0" 621 | }, 622 | "engines": { 623 | "node": ">=14.0.0" 624 | } 625 | }, 626 | "node_modules/@aws-sdk/node-http-handler": { 627 | "version": "3.321.1", 628 | "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.321.1.tgz", 629 | "integrity": "sha512-DdQBrtFFDNtzphJIN3s93Vf+qd9LHSzH6WTQRrWoXhTDMHDzSI2Cn+c5KWfk89Nggp/n3+OTwUPQeCiBT5EBuw==", 630 | "dependencies": { 631 | "@aws-sdk/abort-controller": "3.310.0", 632 | "@aws-sdk/protocol-http": "3.310.0", 633 | "@aws-sdk/querystring-builder": "3.310.0", 634 | "@aws-sdk/types": "3.310.0", 635 | "tslib": "^2.5.0" 636 | }, 637 | "engines": { 638 | "node": ">=14.0.0" 639 | } 640 | }, 641 | "node_modules/@aws-sdk/property-provider": { 642 | "version": "3.310.0", 643 | "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.310.0.tgz", 644 | "integrity": "sha512-3lxDb0akV6BBzmFe4nLPaoliQbAifyWJhuvuDOu7e8NzouvpQXs0275w9LePhhcgjKAEVXUIse05ZW2DLbxo/g==", 645 | "dependencies": { 646 | "@aws-sdk/types": "3.310.0", 647 | "tslib": "^2.5.0" 648 | }, 649 | "engines": { 650 | "node": ">=14.0.0" 651 | } 652 | }, 653 | "node_modules/@aws-sdk/protocol-http": { 654 | "version": "3.310.0", 655 | "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.310.0.tgz", 656 | "integrity": "sha512-fgZ1aw/irQtnrsR58pS8ThKOWo57Py3xX6giRvwSgZDEcxHfVzuQjy9yPuV++v04fdmdtgpbGf8WfvAAJ11yXQ==", 657 | "dependencies": { 658 | "@aws-sdk/types": "3.310.0", 659 | "tslib": "^2.5.0" 660 | }, 661 | "engines": { 662 | "node": ">=14.0.0" 663 | } 664 | }, 665 | "node_modules/@aws-sdk/querystring-builder": { 666 | "version": "3.310.0", 667 | "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.310.0.tgz", 668 | "integrity": "sha512-ZHH8GV/80+pWGo7DzsvwvXR5xVxUHXUvPJPFAkhr6nCf78igdoF8gR10ScFoEKbtEapoNTaZlKHPXxpD8aPG7A==", 669 | "dependencies": { 670 | "@aws-sdk/types": "3.310.0", 671 | "@aws-sdk/util-uri-escape": "3.310.0", 672 | "tslib": "^2.5.0" 673 | }, 674 | "engines": { 675 | "node": ">=14.0.0" 676 | } 677 | }, 678 | "node_modules/@aws-sdk/querystring-parser": { 679 | "version": "3.310.0", 680 | "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.310.0.tgz", 681 | "integrity": "sha512-YkIznoP6lsiIUHinx++/lbb3tlMURGGqMpo0Pnn32zYzGrJXA6eC3D0as2EcMjo55onTfuLcIiX4qzXes2MYOA==", 682 | "dependencies": { 683 | "@aws-sdk/types": "3.310.0", 684 | "tslib": "^2.5.0" 685 | }, 686 | "engines": { 687 | "node": ">=14.0.0" 688 | } 689 | }, 690 | "node_modules/@aws-sdk/service-error-classification": { 691 | "version": "3.327.0", 692 | "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.327.0.tgz", 693 | "integrity": "sha512-bCWnw+uH3gI6yPxLi4a4WV71P1KlJU7Z4+iMBY1Gt4+ZsaPAJX9pAbuQcFhFH++4xTk/QaVMzSvD0uQ+u0B/NQ==", 694 | "engines": { 695 | "node": ">=14.0.0" 696 | } 697 | }, 698 | "node_modules/@aws-sdk/shared-ini-file-loader": { 699 | "version": "3.310.0", 700 | "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.310.0.tgz", 701 | "integrity": "sha512-N0q9pG0xSjQwc690YQND5bofm+4nfUviQ/Ppgan2kU6aU0WUq8KwgHJBto/YEEI+VlrME30jZJnxtOvcZJc2XA==", 702 | "dependencies": { 703 | "@aws-sdk/types": "3.310.0", 704 | "tslib": "^2.5.0" 705 | }, 706 | "engines": { 707 | "node": ">=14.0.0" 708 | } 709 | }, 710 | "node_modules/@aws-sdk/signature-v4": { 711 | "version": "3.310.0", 712 | "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.310.0.tgz", 713 | "integrity": "sha512-1M60P1ZBNAjCFv9sYW29OF6okktaeibWyW3lMXqzoHF70lHBZh+838iUchznXUA5FLabfn4jBFWMRxlAXJUY2Q==", 714 | "dependencies": { 715 | "@aws-sdk/is-array-buffer": "3.310.0", 716 | "@aws-sdk/types": "3.310.0", 717 | "@aws-sdk/util-hex-encoding": "3.310.0", 718 | "@aws-sdk/util-middleware": "3.310.0", 719 | "@aws-sdk/util-uri-escape": "3.310.0", 720 | "@aws-sdk/util-utf8": "3.310.0", 721 | "tslib": "^2.5.0" 722 | }, 723 | "engines": { 724 | "node": ">=14.0.0" 725 | } 726 | }, 727 | "node_modules/@aws-sdk/smithy-client": { 728 | "version": "3.325.0", 729 | "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.325.0.tgz", 730 | "integrity": "sha512-sqDFuhjxd8+Q9qI8MmXe/g1/FgoViwetv14K+bpHK7pGlOIvDyT7TboDNClfgqSLdgTDCEaoC3JRSi9Y5RgbmA==", 731 | "dependencies": { 732 | "@aws-sdk/middleware-stack": "3.325.0", 733 | "@aws-sdk/types": "3.310.0", 734 | "tslib": "^2.5.0" 735 | }, 736 | "engines": { 737 | "node": ">=14.0.0" 738 | } 739 | }, 740 | "node_modules/@aws-sdk/token-providers": { 741 | "version": "3.327.0", 742 | "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.327.0.tgz", 743 | "integrity": "sha512-7x1nXJiFlXz6umdkcvZJAR8GxyhxqmgLi4laBc1ZYcxHzOb02EFqloSmax6/SNJNKlL2QmGbEXuPIGV1wf45uQ==", 744 | "dependencies": { 745 | "@aws-sdk/client-sso-oidc": "3.327.0", 746 | "@aws-sdk/property-provider": "3.310.0", 747 | "@aws-sdk/shared-ini-file-loader": "3.310.0", 748 | "@aws-sdk/types": "3.310.0", 749 | "tslib": "^2.5.0" 750 | }, 751 | "engines": { 752 | "node": ">=14.0.0" 753 | } 754 | }, 755 | "node_modules/@aws-sdk/types": { 756 | "version": "3.310.0", 757 | "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.310.0.tgz", 758 | "integrity": "sha512-j8eamQJ7YcIhw7fneUfs8LYl3t01k4uHi4ZDmNRgtbmbmTTG3FZc2MotStZnp3nZB6vLiPF1o5aoJxWVvkzS6A==", 759 | "dependencies": { 760 | "tslib": "^2.5.0" 761 | }, 762 | "engines": { 763 | "node": ">=14.0.0" 764 | } 765 | }, 766 | "node_modules/@aws-sdk/url-parser": { 767 | "version": "3.310.0", 768 | "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.310.0.tgz", 769 | "integrity": "sha512-mCLnCaSB9rQvAgx33u0DujLvr4d5yEm/W5r789GblwwQnlNXedVu50QRizMLTpltYWyAUoXjJgQnJHmJMaKXhw==", 770 | "dependencies": { 771 | "@aws-sdk/querystring-parser": "3.310.0", 772 | "@aws-sdk/types": "3.310.0", 773 | "tslib": "^2.5.0" 774 | } 775 | }, 776 | "node_modules/@aws-sdk/util-base64": { 777 | "version": "3.310.0", 778 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.310.0.tgz", 779 | "integrity": "sha512-v3+HBKQvqgdzcbL+pFswlx5HQsd9L6ZTlyPVL2LS9nNXnCcR3XgGz9jRskikRUuUvUXtkSG1J88GAOnJ/apTPg==", 780 | "dependencies": { 781 | "@aws-sdk/util-buffer-from": "3.310.0", 782 | "tslib": "^2.5.0" 783 | }, 784 | "engines": { 785 | "node": ">=14.0.0" 786 | } 787 | }, 788 | "node_modules/@aws-sdk/util-body-length-browser": { 789 | "version": "3.310.0", 790 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.310.0.tgz", 791 | "integrity": "sha512-sxsC3lPBGfpHtNTUoGXMQXLwjmR0zVpx0rSvzTPAuoVILVsp5AU/w5FphNPxD5OVIjNbZv9KsKTuvNTiZjDp9g==", 792 | "dependencies": { 793 | "tslib": "^2.5.0" 794 | } 795 | }, 796 | "node_modules/@aws-sdk/util-body-length-node": { 797 | "version": "3.310.0", 798 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.310.0.tgz", 799 | "integrity": "sha512-2tqGXdyKhyA6w4zz7UPoS8Ip+7sayOg9BwHNidiGm2ikbDxm1YrCfYXvCBdwaJxa4hJfRVz+aL9e+d3GqPI9pQ==", 800 | "dependencies": { 801 | "tslib": "^2.5.0" 802 | }, 803 | "engines": { 804 | "node": ">=14.0.0" 805 | } 806 | }, 807 | "node_modules/@aws-sdk/util-buffer-from": { 808 | "version": "3.310.0", 809 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.310.0.tgz", 810 | "integrity": "sha512-i6LVeXFtGih5Zs8enLrt+ExXY92QV25jtEnTKHsmlFqFAuL3VBeod6boeMXkN2p9lbSVVQ1sAOOYZOHYbYkntw==", 811 | "dependencies": { 812 | "@aws-sdk/is-array-buffer": "3.310.0", 813 | "tslib": "^2.5.0" 814 | }, 815 | "engines": { 816 | "node": ">=14.0.0" 817 | } 818 | }, 819 | "node_modules/@aws-sdk/util-config-provider": { 820 | "version": "3.310.0", 821 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.310.0.tgz", 822 | "integrity": "sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==", 823 | "dependencies": { 824 | "tslib": "^2.5.0" 825 | }, 826 | "engines": { 827 | "node": ">=14.0.0" 828 | } 829 | }, 830 | "node_modules/@aws-sdk/util-defaults-mode-browser": { 831 | "version": "3.325.0", 832 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.325.0.tgz", 833 | "integrity": "sha512-gcowpXTo8E8N3jxD2KW+csiicJ7HPkhWnpL925xgwe0oq091OpATsKFrBOL18h72VfRWf4FAsR9lVwxSQ78zSA==", 834 | "dependencies": { 835 | "@aws-sdk/property-provider": "3.310.0", 836 | "@aws-sdk/types": "3.310.0", 837 | "bowser": "^2.11.0", 838 | "tslib": "^2.5.0" 839 | }, 840 | "engines": { 841 | "node": ">= 10.0.0" 842 | } 843 | }, 844 | "node_modules/@aws-sdk/util-defaults-mode-node": { 845 | "version": "3.325.0", 846 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.325.0.tgz", 847 | "integrity": "sha512-/5uoOrgNxoUxv3AwsdXjMA3f6KJA6fi69otA0RiINjilCdcbOxq5GI11AFEyRio/+e+imriX4+UYjsguUR+f4g==", 848 | "dependencies": { 849 | "@aws-sdk/config-resolver": "3.310.0", 850 | "@aws-sdk/credential-provider-imds": "3.310.0", 851 | "@aws-sdk/node-config-provider": "3.310.0", 852 | "@aws-sdk/property-provider": "3.310.0", 853 | "@aws-sdk/types": "3.310.0", 854 | "tslib": "^2.5.0" 855 | }, 856 | "engines": { 857 | "node": ">= 10.0.0" 858 | } 859 | }, 860 | "node_modules/@aws-sdk/util-endpoints": { 861 | "version": "3.327.0", 862 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.327.0.tgz", 863 | "integrity": "sha512-2+2jTfBzhXsfpOci61gzaoBUVdGhFWja7k5cLAfOaRROkK+m+Zv532+m3cCQZjBXJ6pJ952MbiAroRSjFq0/SQ==", 864 | "dependencies": { 865 | "@aws-sdk/types": "3.310.0", 866 | "tslib": "^2.5.0" 867 | }, 868 | "engines": { 869 | "node": ">=14.0.0" 870 | } 871 | }, 872 | "node_modules/@aws-sdk/util-hex-encoding": { 873 | "version": "3.310.0", 874 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.310.0.tgz", 875 | "integrity": "sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==", 876 | "dependencies": { 877 | "tslib": "^2.5.0" 878 | }, 879 | "engines": { 880 | "node": ">=14.0.0" 881 | } 882 | }, 883 | "node_modules/@aws-sdk/util-locate-window": { 884 | "version": "3.310.0", 885 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", 886 | "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", 887 | "dependencies": { 888 | "tslib": "^2.5.0" 889 | }, 890 | "engines": { 891 | "node": ">=14.0.0" 892 | } 893 | }, 894 | "node_modules/@aws-sdk/util-middleware": { 895 | "version": "3.310.0", 896 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.310.0.tgz", 897 | "integrity": "sha512-FTSUKL/eRb9X6uEZClrTe27QFXUNNp7fxYrPndZwk1hlaOP5ix+MIHBcI7pIiiY/JPfOUmPyZOu+HetlFXjWog==", 898 | "dependencies": { 899 | "tslib": "^2.5.0" 900 | }, 901 | "engines": { 902 | "node": ">=14.0.0" 903 | } 904 | }, 905 | "node_modules/@aws-sdk/util-retry": { 906 | "version": "3.327.0", 907 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.327.0.tgz", 908 | "integrity": "sha512-y15NLGTAT2vaLzA8klJ6Bo8NGjVAa3/njqc4iCbta/3GqKpQU0zbvw3Y5aWyHp8BhV4DSUTp088jWjaoZlSqgw==", 909 | "dependencies": { 910 | "@aws-sdk/service-error-classification": "3.327.0", 911 | "tslib": "^2.5.0" 912 | }, 913 | "engines": { 914 | "node": ">= 14.0.0" 915 | } 916 | }, 917 | "node_modules/@aws-sdk/util-uri-escape": { 918 | "version": "3.310.0", 919 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.310.0.tgz", 920 | "integrity": "sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==", 921 | "dependencies": { 922 | "tslib": "^2.5.0" 923 | }, 924 | "engines": { 925 | "node": ">=14.0.0" 926 | } 927 | }, 928 | "node_modules/@aws-sdk/util-user-agent-browser": { 929 | "version": "3.310.0", 930 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.310.0.tgz", 931 | "integrity": "sha512-yU/4QnHHuQ5z3vsUqMQVfYLbZGYwpYblPiuZx4Zo9+x0PBkNjYMqctdDcrpoH9Z2xZiDN16AmQGK1tix117ZKw==", 932 | "dependencies": { 933 | "@aws-sdk/types": "3.310.0", 934 | "bowser": "^2.11.0", 935 | "tslib": "^2.5.0" 936 | } 937 | }, 938 | "node_modules/@aws-sdk/util-user-agent-node": { 939 | "version": "3.310.0", 940 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.310.0.tgz", 941 | "integrity": "sha512-Ra3pEl+Gn2BpeE7KiDGpi4zj7WJXZA5GXnGo3mjbi9+Y3zrbuhJAbdZO3mO/o7xDgMC6ph4xCTbaSGzU6b6EDg==", 942 | "dependencies": { 943 | "@aws-sdk/node-config-provider": "3.310.0", 944 | "@aws-sdk/types": "3.310.0", 945 | "tslib": "^2.5.0" 946 | }, 947 | "engines": { 948 | "node": ">=14.0.0" 949 | }, 950 | "peerDependencies": { 951 | "aws-crt": ">=1.0.0" 952 | }, 953 | "peerDependenciesMeta": { 954 | "aws-crt": { 955 | "optional": true 956 | } 957 | } 958 | }, 959 | "node_modules/@aws-sdk/util-utf8": { 960 | "version": "3.310.0", 961 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.310.0.tgz", 962 | "integrity": "sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA==", 963 | "dependencies": { 964 | "@aws-sdk/util-buffer-from": "3.310.0", 965 | "tslib": "^2.5.0" 966 | }, 967 | "engines": { 968 | "node": ">=14.0.0" 969 | } 970 | }, 971 | "node_modules/@aws-sdk/util-utf8-browser": { 972 | "version": "3.259.0", 973 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", 974 | "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", 975 | "dependencies": { 976 | "tslib": "^2.3.1" 977 | } 978 | }, 979 | "node_modules/@aws-sdk/util-waiter": { 980 | "version": "3.310.0", 981 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-waiter/-/util-waiter-3.310.0.tgz", 982 | "integrity": "sha512-AV5j3guH/Y4REu+Qh3eXQU9igljHuU4XjX2sADAgf54C0kkhcCCkkiuzk3IsX089nyJCqIcj5idbjdvpnH88Vw==", 983 | "dependencies": { 984 | "@aws-sdk/abort-controller": "3.310.0", 985 | "@aws-sdk/types": "3.310.0", 986 | "tslib": "^2.5.0" 987 | }, 988 | "engines": { 989 | "node": ">=14.0.0" 990 | } 991 | }, 992 | "node_modules/@cspotcode/source-map-support": { 993 | "version": "0.8.1", 994 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 995 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 996 | "dev": true, 997 | "dependencies": { 998 | "@jridgewell/trace-mapping": "0.3.9" 999 | }, 1000 | "engines": { 1001 | "node": ">=12" 1002 | } 1003 | }, 1004 | "node_modules/@jridgewell/resolve-uri": { 1005 | "version": "3.1.1", 1006 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 1007 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 1008 | "dev": true, 1009 | "engines": { 1010 | "node": ">=6.0.0" 1011 | } 1012 | }, 1013 | "node_modules/@jridgewell/sourcemap-codec": { 1014 | "version": "1.4.15", 1015 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 1016 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 1017 | "dev": true 1018 | }, 1019 | "node_modules/@jridgewell/trace-mapping": { 1020 | "version": "0.3.9", 1021 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 1022 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 1023 | "dev": true, 1024 | "dependencies": { 1025 | "@jridgewell/resolve-uri": "^3.0.3", 1026 | "@jridgewell/sourcemap-codec": "^1.4.10" 1027 | } 1028 | }, 1029 | "node_modules/@prisma/client": { 1030 | "version": "4.13.0", 1031 | "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.13.0.tgz", 1032 | "integrity": "sha512-YaiiICcRB2hatxsbnfB66uWXjcRw3jsZdlAVxmx0cFcTc/Ad/sKdHCcWSnqyDX47vAewkjRFwiLwrOUjswVvmA==", 1033 | "hasInstallScript": true, 1034 | "dependencies": { 1035 | "@prisma/engines-version": "4.13.0-50.1e7af066ee9cb95cf3a403c78d9aab3e6b04f37a" 1036 | }, 1037 | "engines": { 1038 | "node": ">=14.17" 1039 | }, 1040 | "peerDependencies": { 1041 | "prisma": "*" 1042 | }, 1043 | "peerDependenciesMeta": { 1044 | "prisma": { 1045 | "optional": true 1046 | } 1047 | } 1048 | }, 1049 | "node_modules/@prisma/engines": { 1050 | "version": "4.13.0", 1051 | "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.13.0.tgz", 1052 | "integrity": "sha512-HrniowHRZXHuGT9XRgoXEaP2gJLXM5RMoItaY2PkjvuZ+iHc0Zjbm/302MB8YsPdWozAPHHn+jpFEcEn71OgPw==", 1053 | "devOptional": true, 1054 | "hasInstallScript": true 1055 | }, 1056 | "node_modules/@prisma/engines-version": { 1057 | "version": "4.13.0-50.1e7af066ee9cb95cf3a403c78d9aab3e6b04f37a", 1058 | "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.13.0-50.1e7af066ee9cb95cf3a403c78d9aab3e6b04f37a.tgz", 1059 | "integrity": "sha512-fsQlbkhPJf08JOzKoyoD9atdUijuGBekwoOPZC3YOygXEml1MTtgXVpnUNchQlRSY82OQ6pSGQ9PxUe4arcSLQ==" 1060 | }, 1061 | "node_modules/@tsconfig/node10": { 1062 | "version": "1.0.9", 1063 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 1064 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", 1065 | "dev": true 1066 | }, 1067 | "node_modules/@tsconfig/node12": { 1068 | "version": "1.0.11", 1069 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 1070 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 1071 | "dev": true 1072 | }, 1073 | "node_modules/@tsconfig/node14": { 1074 | "version": "1.0.3", 1075 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 1076 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 1077 | "dev": true 1078 | }, 1079 | "node_modules/@tsconfig/node16": { 1080 | "version": "1.0.3", 1081 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", 1082 | "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", 1083 | "dev": true 1084 | }, 1085 | "node_modules/@types/body-parser": { 1086 | "version": "1.19.2", 1087 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", 1088 | "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", 1089 | "dev": true, 1090 | "dependencies": { 1091 | "@types/connect": "*", 1092 | "@types/node": "*" 1093 | } 1094 | }, 1095 | "node_modules/@types/connect": { 1096 | "version": "3.4.35", 1097 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", 1098 | "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", 1099 | "dev": true, 1100 | "dependencies": { 1101 | "@types/node": "*" 1102 | } 1103 | }, 1104 | "node_modules/@types/express": { 1105 | "version": "4.17.17", 1106 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", 1107 | "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", 1108 | "dev": true, 1109 | "dependencies": { 1110 | "@types/body-parser": "*", 1111 | "@types/express-serve-static-core": "^4.17.33", 1112 | "@types/qs": "*", 1113 | "@types/serve-static": "*" 1114 | } 1115 | }, 1116 | "node_modules/@types/express-serve-static-core": { 1117 | "version": "4.17.34", 1118 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz", 1119 | "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==", 1120 | "dev": true, 1121 | "dependencies": { 1122 | "@types/node": "*", 1123 | "@types/qs": "*", 1124 | "@types/range-parser": "*", 1125 | "@types/send": "*" 1126 | } 1127 | }, 1128 | "node_modules/@types/jsonwebtoken": { 1129 | "version": "9.0.2", 1130 | "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", 1131 | "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==", 1132 | "dev": true, 1133 | "dependencies": { 1134 | "@types/node": "*" 1135 | } 1136 | }, 1137 | "node_modules/@types/mime": { 1138 | "version": "1.3.2", 1139 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", 1140 | "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", 1141 | "dev": true 1142 | }, 1143 | "node_modules/@types/node": { 1144 | "version": "20.0.0", 1145 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.0.0.tgz", 1146 | "integrity": "sha512-cD2uPTDnQQCVpmRefonO98/PPijuOnnEy5oytWJFPY1N9aJCz2wJ5kSGWO+zJoed2cY2JxQh6yBuUq4vIn61hw==", 1147 | "dev": true 1148 | }, 1149 | "node_modules/@types/qs": { 1150 | "version": "6.9.7", 1151 | "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", 1152 | "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", 1153 | "dev": true 1154 | }, 1155 | "node_modules/@types/range-parser": { 1156 | "version": "1.2.4", 1157 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", 1158 | "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", 1159 | "dev": true 1160 | }, 1161 | "node_modules/@types/send": { 1162 | "version": "0.17.1", 1163 | "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", 1164 | "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", 1165 | "dev": true, 1166 | "dependencies": { 1167 | "@types/mime": "^1", 1168 | "@types/node": "*" 1169 | } 1170 | }, 1171 | "node_modules/@types/serve-static": { 1172 | "version": "1.15.1", 1173 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", 1174 | "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", 1175 | "dev": true, 1176 | "dependencies": { 1177 | "@types/mime": "*", 1178 | "@types/node": "*" 1179 | } 1180 | }, 1181 | "node_modules/abbrev": { 1182 | "version": "1.1.1", 1183 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 1184 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 1185 | "dev": true 1186 | }, 1187 | "node_modules/accepts": { 1188 | "version": "1.3.8", 1189 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 1190 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 1191 | "dependencies": { 1192 | "mime-types": "~2.1.34", 1193 | "negotiator": "0.6.3" 1194 | }, 1195 | "engines": { 1196 | "node": ">= 0.6" 1197 | } 1198 | }, 1199 | "node_modules/acorn": { 1200 | "version": "8.8.2", 1201 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", 1202 | "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", 1203 | "dev": true, 1204 | "bin": { 1205 | "acorn": "bin/acorn" 1206 | }, 1207 | "engines": { 1208 | "node": ">=0.4.0" 1209 | } 1210 | }, 1211 | "node_modules/acorn-walk": { 1212 | "version": "8.2.0", 1213 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 1214 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 1215 | "dev": true, 1216 | "engines": { 1217 | "node": ">=0.4.0" 1218 | } 1219 | }, 1220 | "node_modules/anymatch": { 1221 | "version": "3.1.3", 1222 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 1223 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 1224 | "dev": true, 1225 | "dependencies": { 1226 | "normalize-path": "^3.0.0", 1227 | "picomatch": "^2.0.4" 1228 | }, 1229 | "engines": { 1230 | "node": ">= 8" 1231 | } 1232 | }, 1233 | "node_modules/arg": { 1234 | "version": "4.1.3", 1235 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 1236 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 1237 | "dev": true 1238 | }, 1239 | "node_modules/array-flatten": { 1240 | "version": "1.1.1", 1241 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 1242 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 1243 | }, 1244 | "node_modules/balanced-match": { 1245 | "version": "1.0.2", 1246 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1247 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1248 | "dev": true 1249 | }, 1250 | "node_modules/binary-extensions": { 1251 | "version": "2.2.0", 1252 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 1253 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 1254 | "dev": true, 1255 | "engines": { 1256 | "node": ">=8" 1257 | } 1258 | }, 1259 | "node_modules/body-parser": { 1260 | "version": "1.20.1", 1261 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 1262 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 1263 | "dependencies": { 1264 | "bytes": "3.1.2", 1265 | "content-type": "~1.0.4", 1266 | "debug": "2.6.9", 1267 | "depd": "2.0.0", 1268 | "destroy": "1.2.0", 1269 | "http-errors": "2.0.0", 1270 | "iconv-lite": "0.4.24", 1271 | "on-finished": "2.4.1", 1272 | "qs": "6.11.0", 1273 | "raw-body": "2.5.1", 1274 | "type-is": "~1.6.18", 1275 | "unpipe": "1.0.0" 1276 | }, 1277 | "engines": { 1278 | "node": ">= 0.8", 1279 | "npm": "1.2.8000 || >= 1.4.16" 1280 | } 1281 | }, 1282 | "node_modules/bowser": { 1283 | "version": "2.11.0", 1284 | "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", 1285 | "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" 1286 | }, 1287 | "node_modules/brace-expansion": { 1288 | "version": "1.1.11", 1289 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1290 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1291 | "dev": true, 1292 | "dependencies": { 1293 | "balanced-match": "^1.0.0", 1294 | "concat-map": "0.0.1" 1295 | } 1296 | }, 1297 | "node_modules/braces": { 1298 | "version": "3.0.2", 1299 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 1300 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 1301 | "dev": true, 1302 | "dependencies": { 1303 | "fill-range": "^7.0.1" 1304 | }, 1305 | "engines": { 1306 | "node": ">=8" 1307 | } 1308 | }, 1309 | "node_modules/buffer-equal-constant-time": { 1310 | "version": "1.0.1", 1311 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 1312 | "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" 1313 | }, 1314 | "node_modules/bytes": { 1315 | "version": "3.1.2", 1316 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 1317 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 1318 | "engines": { 1319 | "node": ">= 0.8" 1320 | } 1321 | }, 1322 | "node_modules/call-bind": { 1323 | "version": "1.0.2", 1324 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 1325 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 1326 | "dependencies": { 1327 | "function-bind": "^1.1.1", 1328 | "get-intrinsic": "^1.0.2" 1329 | }, 1330 | "funding": { 1331 | "url": "https://github.com/sponsors/ljharb" 1332 | } 1333 | }, 1334 | "node_modules/chokidar": { 1335 | "version": "3.5.3", 1336 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 1337 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 1338 | "dev": true, 1339 | "funding": [ 1340 | { 1341 | "type": "individual", 1342 | "url": "https://paulmillr.com/funding/" 1343 | } 1344 | ], 1345 | "dependencies": { 1346 | "anymatch": "~3.1.2", 1347 | "braces": "~3.0.2", 1348 | "glob-parent": "~5.1.2", 1349 | "is-binary-path": "~2.1.0", 1350 | "is-glob": "~4.0.1", 1351 | "normalize-path": "~3.0.0", 1352 | "readdirp": "~3.6.0" 1353 | }, 1354 | "engines": { 1355 | "node": ">= 8.10.0" 1356 | }, 1357 | "optionalDependencies": { 1358 | "fsevents": "~2.3.2" 1359 | } 1360 | }, 1361 | "node_modules/concat-map": { 1362 | "version": "0.0.1", 1363 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1364 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 1365 | "dev": true 1366 | }, 1367 | "node_modules/content-disposition": { 1368 | "version": "0.5.4", 1369 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 1370 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 1371 | "dependencies": { 1372 | "safe-buffer": "5.2.1" 1373 | }, 1374 | "engines": { 1375 | "node": ">= 0.6" 1376 | } 1377 | }, 1378 | "node_modules/content-type": { 1379 | "version": "1.0.5", 1380 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 1381 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 1382 | "engines": { 1383 | "node": ">= 0.6" 1384 | } 1385 | }, 1386 | "node_modules/cookie": { 1387 | "version": "0.5.0", 1388 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 1389 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 1390 | "engines": { 1391 | "node": ">= 0.6" 1392 | } 1393 | }, 1394 | "node_modules/cookie-signature": { 1395 | "version": "1.0.6", 1396 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 1397 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 1398 | }, 1399 | "node_modules/create-require": { 1400 | "version": "1.1.1", 1401 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 1402 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 1403 | "dev": true 1404 | }, 1405 | "node_modules/debug": { 1406 | "version": "2.6.9", 1407 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 1408 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 1409 | "dependencies": { 1410 | "ms": "2.0.0" 1411 | } 1412 | }, 1413 | "node_modules/depd": { 1414 | "version": "2.0.0", 1415 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 1416 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 1417 | "engines": { 1418 | "node": ">= 0.8" 1419 | } 1420 | }, 1421 | "node_modules/destroy": { 1422 | "version": "1.2.0", 1423 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 1424 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 1425 | "engines": { 1426 | "node": ">= 0.8", 1427 | "npm": "1.2.8000 || >= 1.4.16" 1428 | } 1429 | }, 1430 | "node_modules/diff": { 1431 | "version": "4.0.2", 1432 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 1433 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 1434 | "dev": true, 1435 | "engines": { 1436 | "node": ">=0.3.1" 1437 | } 1438 | }, 1439 | "node_modules/dotenv": { 1440 | "version": "16.0.3", 1441 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", 1442 | "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", 1443 | "engines": { 1444 | "node": ">=12" 1445 | } 1446 | }, 1447 | "node_modules/ecdsa-sig-formatter": { 1448 | "version": "1.0.11", 1449 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", 1450 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", 1451 | "dependencies": { 1452 | "safe-buffer": "^5.0.1" 1453 | } 1454 | }, 1455 | "node_modules/ee-first": { 1456 | "version": "1.1.1", 1457 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 1458 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 1459 | }, 1460 | "node_modules/encodeurl": { 1461 | "version": "1.0.2", 1462 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 1463 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 1464 | "engines": { 1465 | "node": ">= 0.8" 1466 | } 1467 | }, 1468 | "node_modules/escape-html": { 1469 | "version": "1.0.3", 1470 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 1471 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 1472 | }, 1473 | "node_modules/etag": { 1474 | "version": "1.8.1", 1475 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 1476 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 1477 | "engines": { 1478 | "node": ">= 0.6" 1479 | } 1480 | }, 1481 | "node_modules/express": { 1482 | "version": "4.18.2", 1483 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 1484 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 1485 | "dependencies": { 1486 | "accepts": "~1.3.8", 1487 | "array-flatten": "1.1.1", 1488 | "body-parser": "1.20.1", 1489 | "content-disposition": "0.5.4", 1490 | "content-type": "~1.0.4", 1491 | "cookie": "0.5.0", 1492 | "cookie-signature": "1.0.6", 1493 | "debug": "2.6.9", 1494 | "depd": "2.0.0", 1495 | "encodeurl": "~1.0.2", 1496 | "escape-html": "~1.0.3", 1497 | "etag": "~1.8.1", 1498 | "finalhandler": "1.2.0", 1499 | "fresh": "0.5.2", 1500 | "http-errors": "2.0.0", 1501 | "merge-descriptors": "1.0.1", 1502 | "methods": "~1.1.2", 1503 | "on-finished": "2.4.1", 1504 | "parseurl": "~1.3.3", 1505 | "path-to-regexp": "0.1.7", 1506 | "proxy-addr": "~2.0.7", 1507 | "qs": "6.11.0", 1508 | "range-parser": "~1.2.1", 1509 | "safe-buffer": "5.2.1", 1510 | "send": "0.18.0", 1511 | "serve-static": "1.15.0", 1512 | "setprototypeof": "1.2.0", 1513 | "statuses": "2.0.1", 1514 | "type-is": "~1.6.18", 1515 | "utils-merge": "1.0.1", 1516 | "vary": "~1.1.2" 1517 | }, 1518 | "engines": { 1519 | "node": ">= 0.10.0" 1520 | } 1521 | }, 1522 | "node_modules/fast-xml-parser": { 1523 | "version": "4.1.2", 1524 | "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.2.tgz", 1525 | "integrity": "sha512-CDYeykkle1LiA/uqQyNwYpFbyF6Axec6YapmpUP+/RHWIoR1zKjocdvNaTsxCxZzQ6v9MLXaSYm9Qq0thv0DHg==", 1526 | "dependencies": { 1527 | "strnum": "^1.0.5" 1528 | }, 1529 | "bin": { 1530 | "fxparser": "src/cli/cli.js" 1531 | }, 1532 | "funding": { 1533 | "type": "paypal", 1534 | "url": "https://paypal.me/naturalintelligence" 1535 | } 1536 | }, 1537 | "node_modules/fill-range": { 1538 | "version": "7.0.1", 1539 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1540 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1541 | "dev": true, 1542 | "dependencies": { 1543 | "to-regex-range": "^5.0.1" 1544 | }, 1545 | "engines": { 1546 | "node": ">=8" 1547 | } 1548 | }, 1549 | "node_modules/finalhandler": { 1550 | "version": "1.2.0", 1551 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 1552 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 1553 | "dependencies": { 1554 | "debug": "2.6.9", 1555 | "encodeurl": "~1.0.2", 1556 | "escape-html": "~1.0.3", 1557 | "on-finished": "2.4.1", 1558 | "parseurl": "~1.3.3", 1559 | "statuses": "2.0.1", 1560 | "unpipe": "~1.0.0" 1561 | }, 1562 | "engines": { 1563 | "node": ">= 0.8" 1564 | } 1565 | }, 1566 | "node_modules/forwarded": { 1567 | "version": "0.2.0", 1568 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 1569 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 1570 | "engines": { 1571 | "node": ">= 0.6" 1572 | } 1573 | }, 1574 | "node_modules/fresh": { 1575 | "version": "0.5.2", 1576 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 1577 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 1578 | "engines": { 1579 | "node": ">= 0.6" 1580 | } 1581 | }, 1582 | "node_modules/fsevents": { 1583 | "version": "2.3.2", 1584 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1585 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1586 | "dev": true, 1587 | "hasInstallScript": true, 1588 | "optional": true, 1589 | "os": [ 1590 | "darwin" 1591 | ], 1592 | "engines": { 1593 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1594 | } 1595 | }, 1596 | "node_modules/function-bind": { 1597 | "version": "1.1.1", 1598 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1599 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 1600 | }, 1601 | "node_modules/get-intrinsic": { 1602 | "version": "1.2.0", 1603 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", 1604 | "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", 1605 | "dependencies": { 1606 | "function-bind": "^1.1.1", 1607 | "has": "^1.0.3", 1608 | "has-symbols": "^1.0.3" 1609 | }, 1610 | "funding": { 1611 | "url": "https://github.com/sponsors/ljharb" 1612 | } 1613 | }, 1614 | "node_modules/glob-parent": { 1615 | "version": "5.1.2", 1616 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1617 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1618 | "dev": true, 1619 | "dependencies": { 1620 | "is-glob": "^4.0.1" 1621 | }, 1622 | "engines": { 1623 | "node": ">= 6" 1624 | } 1625 | }, 1626 | "node_modules/has": { 1627 | "version": "1.0.3", 1628 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1629 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1630 | "dependencies": { 1631 | "function-bind": "^1.1.1" 1632 | }, 1633 | "engines": { 1634 | "node": ">= 0.4.0" 1635 | } 1636 | }, 1637 | "node_modules/has-flag": { 1638 | "version": "3.0.0", 1639 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1640 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 1641 | "dev": true, 1642 | "engines": { 1643 | "node": ">=4" 1644 | } 1645 | }, 1646 | "node_modules/has-symbols": { 1647 | "version": "1.0.3", 1648 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 1649 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 1650 | "engines": { 1651 | "node": ">= 0.4" 1652 | }, 1653 | "funding": { 1654 | "url": "https://github.com/sponsors/ljharb" 1655 | } 1656 | }, 1657 | "node_modules/http-errors": { 1658 | "version": "2.0.0", 1659 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 1660 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 1661 | "dependencies": { 1662 | "depd": "2.0.0", 1663 | "inherits": "2.0.4", 1664 | "setprototypeof": "1.2.0", 1665 | "statuses": "2.0.1", 1666 | "toidentifier": "1.0.1" 1667 | }, 1668 | "engines": { 1669 | "node": ">= 0.8" 1670 | } 1671 | }, 1672 | "node_modules/iconv-lite": { 1673 | "version": "0.4.24", 1674 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1675 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1676 | "dependencies": { 1677 | "safer-buffer": ">= 2.1.2 < 3" 1678 | }, 1679 | "engines": { 1680 | "node": ">=0.10.0" 1681 | } 1682 | }, 1683 | "node_modules/ignore-by-default": { 1684 | "version": "1.0.1", 1685 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 1686 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", 1687 | "dev": true 1688 | }, 1689 | "node_modules/inherits": { 1690 | "version": "2.0.4", 1691 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1692 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1693 | }, 1694 | "node_modules/ipaddr.js": { 1695 | "version": "1.9.1", 1696 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 1697 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 1698 | "engines": { 1699 | "node": ">= 0.10" 1700 | } 1701 | }, 1702 | "node_modules/is-binary-path": { 1703 | "version": "2.1.0", 1704 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1705 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1706 | "dev": true, 1707 | "dependencies": { 1708 | "binary-extensions": "^2.0.0" 1709 | }, 1710 | "engines": { 1711 | "node": ">=8" 1712 | } 1713 | }, 1714 | "node_modules/is-extglob": { 1715 | "version": "2.1.1", 1716 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1717 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1718 | "dev": true, 1719 | "engines": { 1720 | "node": ">=0.10.0" 1721 | } 1722 | }, 1723 | "node_modules/is-glob": { 1724 | "version": "4.0.3", 1725 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1726 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1727 | "dev": true, 1728 | "dependencies": { 1729 | "is-extglob": "^2.1.1" 1730 | }, 1731 | "engines": { 1732 | "node": ">=0.10.0" 1733 | } 1734 | }, 1735 | "node_modules/is-number": { 1736 | "version": "7.0.0", 1737 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1738 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1739 | "dev": true, 1740 | "engines": { 1741 | "node": ">=0.12.0" 1742 | } 1743 | }, 1744 | "node_modules/jsonwebtoken": { 1745 | "version": "9.0.0", 1746 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", 1747 | "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", 1748 | "dependencies": { 1749 | "jws": "^3.2.2", 1750 | "lodash": "^4.17.21", 1751 | "ms": "^2.1.1", 1752 | "semver": "^7.3.8" 1753 | }, 1754 | "engines": { 1755 | "node": ">=12", 1756 | "npm": ">=6" 1757 | } 1758 | }, 1759 | "node_modules/jsonwebtoken/node_modules/ms": { 1760 | "version": "2.1.3", 1761 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1762 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 1763 | }, 1764 | "node_modules/jsonwebtoken/node_modules/semver": { 1765 | "version": "7.5.0", 1766 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", 1767 | "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", 1768 | "dependencies": { 1769 | "lru-cache": "^6.0.0" 1770 | }, 1771 | "bin": { 1772 | "semver": "bin/semver.js" 1773 | }, 1774 | "engines": { 1775 | "node": ">=10" 1776 | } 1777 | }, 1778 | "node_modules/jwa": { 1779 | "version": "1.4.1", 1780 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", 1781 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", 1782 | "dependencies": { 1783 | "buffer-equal-constant-time": "1.0.1", 1784 | "ecdsa-sig-formatter": "1.0.11", 1785 | "safe-buffer": "^5.0.1" 1786 | } 1787 | }, 1788 | "node_modules/jws": { 1789 | "version": "3.2.2", 1790 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", 1791 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", 1792 | "dependencies": { 1793 | "jwa": "^1.4.1", 1794 | "safe-buffer": "^5.0.1" 1795 | } 1796 | }, 1797 | "node_modules/lodash": { 1798 | "version": "4.17.21", 1799 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 1800 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 1801 | }, 1802 | "node_modules/lru-cache": { 1803 | "version": "6.0.0", 1804 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1805 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1806 | "dependencies": { 1807 | "yallist": "^4.0.0" 1808 | }, 1809 | "engines": { 1810 | "node": ">=10" 1811 | } 1812 | }, 1813 | "node_modules/make-error": { 1814 | "version": "1.3.6", 1815 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 1816 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 1817 | "dev": true 1818 | }, 1819 | "node_modules/media-typer": { 1820 | "version": "0.3.0", 1821 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 1822 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 1823 | "engines": { 1824 | "node": ">= 0.6" 1825 | } 1826 | }, 1827 | "node_modules/merge-descriptors": { 1828 | "version": "1.0.1", 1829 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 1830 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 1831 | }, 1832 | "node_modules/methods": { 1833 | "version": "1.1.2", 1834 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1835 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 1836 | "engines": { 1837 | "node": ">= 0.6" 1838 | } 1839 | }, 1840 | "node_modules/mime": { 1841 | "version": "1.6.0", 1842 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 1843 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 1844 | "bin": { 1845 | "mime": "cli.js" 1846 | }, 1847 | "engines": { 1848 | "node": ">=4" 1849 | } 1850 | }, 1851 | "node_modules/mime-db": { 1852 | "version": "1.52.0", 1853 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1854 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 1855 | "engines": { 1856 | "node": ">= 0.6" 1857 | } 1858 | }, 1859 | "node_modules/mime-types": { 1860 | "version": "2.1.35", 1861 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1862 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1863 | "dependencies": { 1864 | "mime-db": "1.52.0" 1865 | }, 1866 | "engines": { 1867 | "node": ">= 0.6" 1868 | } 1869 | }, 1870 | "node_modules/minimatch": { 1871 | "version": "3.1.2", 1872 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1873 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1874 | "dev": true, 1875 | "dependencies": { 1876 | "brace-expansion": "^1.1.7" 1877 | }, 1878 | "engines": { 1879 | "node": "*" 1880 | } 1881 | }, 1882 | "node_modules/ms": { 1883 | "version": "2.0.0", 1884 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1885 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 1886 | }, 1887 | "node_modules/negotiator": { 1888 | "version": "0.6.3", 1889 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 1890 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 1891 | "engines": { 1892 | "node": ">= 0.6" 1893 | } 1894 | }, 1895 | "node_modules/nodemon": { 1896 | "version": "2.0.22", 1897 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", 1898 | "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", 1899 | "dev": true, 1900 | "dependencies": { 1901 | "chokidar": "^3.5.2", 1902 | "debug": "^3.2.7", 1903 | "ignore-by-default": "^1.0.1", 1904 | "minimatch": "^3.1.2", 1905 | "pstree.remy": "^1.1.8", 1906 | "semver": "^5.7.1", 1907 | "simple-update-notifier": "^1.0.7", 1908 | "supports-color": "^5.5.0", 1909 | "touch": "^3.1.0", 1910 | "undefsafe": "^2.0.5" 1911 | }, 1912 | "bin": { 1913 | "nodemon": "bin/nodemon.js" 1914 | }, 1915 | "engines": { 1916 | "node": ">=8.10.0" 1917 | }, 1918 | "funding": { 1919 | "type": "opencollective", 1920 | "url": "https://opencollective.com/nodemon" 1921 | } 1922 | }, 1923 | "node_modules/nodemon/node_modules/debug": { 1924 | "version": "3.2.7", 1925 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 1926 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 1927 | "dev": true, 1928 | "dependencies": { 1929 | "ms": "^2.1.1" 1930 | } 1931 | }, 1932 | "node_modules/nodemon/node_modules/ms": { 1933 | "version": "2.1.3", 1934 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1935 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1936 | "dev": true 1937 | }, 1938 | "node_modules/nopt": { 1939 | "version": "1.0.10", 1940 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", 1941 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", 1942 | "dev": true, 1943 | "dependencies": { 1944 | "abbrev": "1" 1945 | }, 1946 | "bin": { 1947 | "nopt": "bin/nopt.js" 1948 | }, 1949 | "engines": { 1950 | "node": "*" 1951 | } 1952 | }, 1953 | "node_modules/normalize-path": { 1954 | "version": "3.0.0", 1955 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1956 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1957 | "dev": true, 1958 | "engines": { 1959 | "node": ">=0.10.0" 1960 | } 1961 | }, 1962 | "node_modules/object-inspect": { 1963 | "version": "1.12.3", 1964 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", 1965 | "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", 1966 | "funding": { 1967 | "url": "https://github.com/sponsors/ljharb" 1968 | } 1969 | }, 1970 | "node_modules/on-finished": { 1971 | "version": "2.4.1", 1972 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 1973 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 1974 | "dependencies": { 1975 | "ee-first": "1.1.1" 1976 | }, 1977 | "engines": { 1978 | "node": ">= 0.8" 1979 | } 1980 | }, 1981 | "node_modules/parseurl": { 1982 | "version": "1.3.3", 1983 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 1984 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 1985 | "engines": { 1986 | "node": ">= 0.8" 1987 | } 1988 | }, 1989 | "node_modules/path-to-regexp": { 1990 | "version": "0.1.7", 1991 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 1992 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 1993 | }, 1994 | "node_modules/picomatch": { 1995 | "version": "2.3.1", 1996 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1997 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1998 | "dev": true, 1999 | "engines": { 2000 | "node": ">=8.6" 2001 | }, 2002 | "funding": { 2003 | "url": "https://github.com/sponsors/jonschlinkert" 2004 | } 2005 | }, 2006 | "node_modules/prisma": { 2007 | "version": "4.13.0", 2008 | "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.13.0.tgz", 2009 | "integrity": "sha512-L9mqjnSmvWIRCYJ9mQkwCtj4+JDYYTdhoyo8hlsHNDXaZLh/b4hR0IoKIBbTKxZuyHQzLopb/+0Rvb69uGV7uA==", 2010 | "devOptional": true, 2011 | "hasInstallScript": true, 2012 | "dependencies": { 2013 | "@prisma/engines": "4.13.0" 2014 | }, 2015 | "bin": { 2016 | "prisma": "build/index.js", 2017 | "prisma2": "build/index.js" 2018 | }, 2019 | "engines": { 2020 | "node": ">=14.17" 2021 | } 2022 | }, 2023 | "node_modules/proxy-addr": { 2024 | "version": "2.0.7", 2025 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 2026 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 2027 | "dependencies": { 2028 | "forwarded": "0.2.0", 2029 | "ipaddr.js": "1.9.1" 2030 | }, 2031 | "engines": { 2032 | "node": ">= 0.10" 2033 | } 2034 | }, 2035 | "node_modules/pstree.remy": { 2036 | "version": "1.1.8", 2037 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", 2038 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", 2039 | "dev": true 2040 | }, 2041 | "node_modules/qs": { 2042 | "version": "6.11.0", 2043 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 2044 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 2045 | "dependencies": { 2046 | "side-channel": "^1.0.4" 2047 | }, 2048 | "engines": { 2049 | "node": ">=0.6" 2050 | }, 2051 | "funding": { 2052 | "url": "https://github.com/sponsors/ljharb" 2053 | } 2054 | }, 2055 | "node_modules/range-parser": { 2056 | "version": "1.2.1", 2057 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 2058 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 2059 | "engines": { 2060 | "node": ">= 0.6" 2061 | } 2062 | }, 2063 | "node_modules/raw-body": { 2064 | "version": "2.5.1", 2065 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 2066 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 2067 | "dependencies": { 2068 | "bytes": "3.1.2", 2069 | "http-errors": "2.0.0", 2070 | "iconv-lite": "0.4.24", 2071 | "unpipe": "1.0.0" 2072 | }, 2073 | "engines": { 2074 | "node": ">= 0.8" 2075 | } 2076 | }, 2077 | "node_modules/readdirp": { 2078 | "version": "3.6.0", 2079 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 2080 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 2081 | "dev": true, 2082 | "dependencies": { 2083 | "picomatch": "^2.2.1" 2084 | }, 2085 | "engines": { 2086 | "node": ">=8.10.0" 2087 | } 2088 | }, 2089 | "node_modules/safe-buffer": { 2090 | "version": "5.2.1", 2091 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 2092 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 2093 | "funding": [ 2094 | { 2095 | "type": "github", 2096 | "url": "https://github.com/sponsors/feross" 2097 | }, 2098 | { 2099 | "type": "patreon", 2100 | "url": "https://www.patreon.com/feross" 2101 | }, 2102 | { 2103 | "type": "consulting", 2104 | "url": "https://feross.org/support" 2105 | } 2106 | ] 2107 | }, 2108 | "node_modules/safer-buffer": { 2109 | "version": "2.1.2", 2110 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 2111 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 2112 | }, 2113 | "node_modules/semver": { 2114 | "version": "5.7.1", 2115 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 2116 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 2117 | "dev": true, 2118 | "bin": { 2119 | "semver": "bin/semver" 2120 | } 2121 | }, 2122 | "node_modules/send": { 2123 | "version": "0.18.0", 2124 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 2125 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 2126 | "dependencies": { 2127 | "debug": "2.6.9", 2128 | "depd": "2.0.0", 2129 | "destroy": "1.2.0", 2130 | "encodeurl": "~1.0.2", 2131 | "escape-html": "~1.0.3", 2132 | "etag": "~1.8.1", 2133 | "fresh": "0.5.2", 2134 | "http-errors": "2.0.0", 2135 | "mime": "1.6.0", 2136 | "ms": "2.1.3", 2137 | "on-finished": "2.4.1", 2138 | "range-parser": "~1.2.1", 2139 | "statuses": "2.0.1" 2140 | }, 2141 | "engines": { 2142 | "node": ">= 0.8.0" 2143 | } 2144 | }, 2145 | "node_modules/send/node_modules/ms": { 2146 | "version": "2.1.3", 2147 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 2148 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 2149 | }, 2150 | "node_modules/serve-static": { 2151 | "version": "1.15.0", 2152 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 2153 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 2154 | "dependencies": { 2155 | "encodeurl": "~1.0.2", 2156 | "escape-html": "~1.0.3", 2157 | "parseurl": "~1.3.3", 2158 | "send": "0.18.0" 2159 | }, 2160 | "engines": { 2161 | "node": ">= 0.8.0" 2162 | } 2163 | }, 2164 | "node_modules/setprototypeof": { 2165 | "version": "1.2.0", 2166 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 2167 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 2168 | }, 2169 | "node_modules/side-channel": { 2170 | "version": "1.0.4", 2171 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 2172 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 2173 | "dependencies": { 2174 | "call-bind": "^1.0.0", 2175 | "get-intrinsic": "^1.0.2", 2176 | "object-inspect": "^1.9.0" 2177 | }, 2178 | "funding": { 2179 | "url": "https://github.com/sponsors/ljharb" 2180 | } 2181 | }, 2182 | "node_modules/simple-update-notifier": { 2183 | "version": "1.1.0", 2184 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", 2185 | "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", 2186 | "dev": true, 2187 | "dependencies": { 2188 | "semver": "~7.0.0" 2189 | }, 2190 | "engines": { 2191 | "node": ">=8.10.0" 2192 | } 2193 | }, 2194 | "node_modules/simple-update-notifier/node_modules/semver": { 2195 | "version": "7.0.0", 2196 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", 2197 | "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", 2198 | "dev": true, 2199 | "bin": { 2200 | "semver": "bin/semver.js" 2201 | } 2202 | }, 2203 | "node_modules/statuses": { 2204 | "version": "2.0.1", 2205 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 2206 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 2207 | "engines": { 2208 | "node": ">= 0.8" 2209 | } 2210 | }, 2211 | "node_modules/strnum": { 2212 | "version": "1.0.5", 2213 | "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", 2214 | "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" 2215 | }, 2216 | "node_modules/supports-color": { 2217 | "version": "5.5.0", 2218 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 2219 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 2220 | "dev": true, 2221 | "dependencies": { 2222 | "has-flag": "^3.0.0" 2223 | }, 2224 | "engines": { 2225 | "node": ">=4" 2226 | } 2227 | }, 2228 | "node_modules/to-regex-range": { 2229 | "version": "5.0.1", 2230 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 2231 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 2232 | "dev": true, 2233 | "dependencies": { 2234 | "is-number": "^7.0.0" 2235 | }, 2236 | "engines": { 2237 | "node": ">=8.0" 2238 | } 2239 | }, 2240 | "node_modules/toidentifier": { 2241 | "version": "1.0.1", 2242 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 2243 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 2244 | "engines": { 2245 | "node": ">=0.6" 2246 | } 2247 | }, 2248 | "node_modules/touch": { 2249 | "version": "3.1.0", 2250 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", 2251 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", 2252 | "dev": true, 2253 | "dependencies": { 2254 | "nopt": "~1.0.10" 2255 | }, 2256 | "bin": { 2257 | "nodetouch": "bin/nodetouch.js" 2258 | } 2259 | }, 2260 | "node_modules/ts-node": { 2261 | "version": "10.9.1", 2262 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", 2263 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", 2264 | "dev": true, 2265 | "dependencies": { 2266 | "@cspotcode/source-map-support": "^0.8.0", 2267 | "@tsconfig/node10": "^1.0.7", 2268 | "@tsconfig/node12": "^1.0.7", 2269 | "@tsconfig/node14": "^1.0.0", 2270 | "@tsconfig/node16": "^1.0.2", 2271 | "acorn": "^8.4.1", 2272 | "acorn-walk": "^8.1.1", 2273 | "arg": "^4.1.0", 2274 | "create-require": "^1.1.0", 2275 | "diff": "^4.0.1", 2276 | "make-error": "^1.1.1", 2277 | "v8-compile-cache-lib": "^3.0.1", 2278 | "yn": "3.1.1" 2279 | }, 2280 | "bin": { 2281 | "ts-node": "dist/bin.js", 2282 | "ts-node-cwd": "dist/bin-cwd.js", 2283 | "ts-node-esm": "dist/bin-esm.js", 2284 | "ts-node-script": "dist/bin-script.js", 2285 | "ts-node-transpile-only": "dist/bin-transpile.js", 2286 | "ts-script": "dist/bin-script-deprecated.js" 2287 | }, 2288 | "peerDependencies": { 2289 | "@swc/core": ">=1.2.50", 2290 | "@swc/wasm": ">=1.2.50", 2291 | "@types/node": "*", 2292 | "typescript": ">=2.7" 2293 | }, 2294 | "peerDependenciesMeta": { 2295 | "@swc/core": { 2296 | "optional": true 2297 | }, 2298 | "@swc/wasm": { 2299 | "optional": true 2300 | } 2301 | } 2302 | }, 2303 | "node_modules/tslib": { 2304 | "version": "2.5.0", 2305 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", 2306 | "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" 2307 | }, 2308 | "node_modules/type-is": { 2309 | "version": "1.6.18", 2310 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 2311 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 2312 | "dependencies": { 2313 | "media-typer": "0.3.0", 2314 | "mime-types": "~2.1.24" 2315 | }, 2316 | "engines": { 2317 | "node": ">= 0.6" 2318 | } 2319 | }, 2320 | "node_modules/typescript": { 2321 | "version": "5.0.4", 2322 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", 2323 | "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", 2324 | "dev": true, 2325 | "bin": { 2326 | "tsc": "bin/tsc", 2327 | "tsserver": "bin/tsserver" 2328 | }, 2329 | "engines": { 2330 | "node": ">=12.20" 2331 | } 2332 | }, 2333 | "node_modules/undefsafe": { 2334 | "version": "2.0.5", 2335 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", 2336 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", 2337 | "dev": true 2338 | }, 2339 | "node_modules/unpipe": { 2340 | "version": "1.0.0", 2341 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 2342 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 2343 | "engines": { 2344 | "node": ">= 0.8" 2345 | } 2346 | }, 2347 | "node_modules/utils-merge": { 2348 | "version": "1.0.1", 2349 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 2350 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 2351 | "engines": { 2352 | "node": ">= 0.4.0" 2353 | } 2354 | }, 2355 | "node_modules/uuid": { 2356 | "version": "8.3.2", 2357 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 2358 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", 2359 | "bin": { 2360 | "uuid": "dist/bin/uuid" 2361 | } 2362 | }, 2363 | "node_modules/v8-compile-cache-lib": { 2364 | "version": "3.0.1", 2365 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 2366 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 2367 | "dev": true 2368 | }, 2369 | "node_modules/vary": { 2370 | "version": "1.1.2", 2371 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 2372 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 2373 | "engines": { 2374 | "node": ">= 0.8" 2375 | } 2376 | }, 2377 | "node_modules/yallist": { 2378 | "version": "4.0.0", 2379 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 2380 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 2381 | }, 2382 | "node_modules/yn": { 2383 | "version": "3.1.1", 2384 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 2385 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 2386 | "dev": true, 2387 | "engines": { 2388 | "node": ">=6" 2389 | } 2390 | } 2391 | } 2392 | } 2393 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twitterbackend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "dev": "nodemon src/index.ts", 9 | "build": "tsc", 10 | "start": "npm run build && node build/index.js" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@aws-sdk/client-ses": "^3.327.0", 17 | "@prisma/client": "^4.13.0", 18 | "dotenv": "^16.0.3", 19 | "express": "^4.18.2", 20 | "jsonwebtoken": "^9.0.0" 21 | }, 22 | "devDependencies": { 23 | "@types/express": "^4.17.17", 24 | "@types/jsonwebtoken": "^9.0.2", 25 | "@types/node": "^20.0.0", 26 | "nodemon": "^2.0.22", 27 | "prisma": "^4.13.0", 28 | "ts-node": "^10.9.1", 29 | "typescript": "^5.0.4" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /prisma/dev.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notJust-dev/TwitterBackend/3737aa45972784b5574e2f6eebc9f92e1548dbfc/prisma/dev.db -------------------------------------------------------------------------------- /prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | generator client { 5 | provider = "prisma-client-js" 6 | } 7 | 8 | datasource db { 9 | provider = "postgresql" 10 | url = env("DATABASE_URL") 11 | } 12 | 13 | model User { 14 | id Int @id @default(autoincrement()) 15 | createdAt DateTime @default(now()) 16 | updatedAt DateTime @updatedAt 17 | 18 | email String @unique 19 | 20 | name String? 21 | username String? @unique 22 | image String? 23 | bio String? 24 | isVerified Boolean @default(false) 25 | 26 | tweets Tweet[] 27 | tokens Token[] 28 | } 29 | 30 | model Token { 31 | id Int @id @default(autoincrement()) 32 | createdAt DateTime @default(now()) 33 | updatedAt DateTime @updatedAt 34 | 35 | type String // EMAIL|API 36 | emailToken String? @unique 37 | 38 | valid Boolean @default(true) 39 | expiration DateTime 40 | 41 | userId Int 42 | user User @relation(fields: [userId], references: [id]) 43 | } 44 | 45 | // enum TokenType { 46 | // EMAIL 47 | // API 48 | // } 49 | 50 | model Tweet { 51 | id Int @id @default(autoincrement()) 52 | createdAt DateTime @default(now()) 53 | updatedAt DateTime @updatedAt 54 | 55 | content String 56 | image String? 57 | 58 | impression Int @default(0) 59 | 60 | userId Int 61 | user User @relation(fields: [userId], references: [id]) 62 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Twitter Backend Application 2 | 3 | This project is a Twitter backend application built using Node.js, Prisma, SQLite, JWT authentication, passwordless authentication, various middlewares, user management functionalities, and Docker containerization. 4 | 5 | ## Features 6 | 7 | - **Node.js:** Backend server using Node.js for handling HTTP requests. 8 | - **Prisma:** Database ORM for interfacing with an SQLite database. 9 | - **SQLite:** Embedded database for storing application data. 10 | - **JWT Authentication:** JSON Web Token-based authentication for secure API access. 11 | - **Passwordless Authentication:** Authentication method without using passwords. 12 | - **Middlewares:** Implemented for authentication, error handling, and more. 13 | - **User Management:** Functionalities for managing users, their profiles, and tweets. 14 | - **Docker Containerization:** Docker setup for containerizing the application. 15 | 16 | ## Setup 17 | 18 | 1. **Clone the repository:** 19 | ```bash 20 | git clone 21 | cd twitter-backend 22 | 23 | 2. **Run Project:** 24 | ```bash 25 | npm install 26 | npx prisma migrate dev 27 | npm start 28 | ``` 29 | 30 | 31 | # Endpoints 32 | 33 | ## Authentication Endpoints 34 | 35 | - `POST /auth/login`: User login endpoint. 36 | - `POST auth/logout`: User logout endpoint. 37 | - `POST /auth/reset-password`: Reset password endpoint (passwordless). 38 | 39 | ## Other Endpoints 40 | 41 | There are various other endpoints for user management, tweets, and additional functionalities. 42 | - Users : POST,GET - /users. 43 | - Tweets : POST,GET - /tweets. 44 | 45 | # Middlewares 46 | 47 | ## Implemented Middlewares 48 | 49 | - `authMiddleware`: Middleware for JWT authentication. 50 | - `errorHandlingMiddleware`: Error handling middleware. 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import userRoutes from './routes/userRoutes'; 3 | import tweetRoutes from './routes/tweetRoutes'; 4 | import authRoutes from './routes/authRoutes'; 5 | import { authenticateToken } from './middlewares/authMiddleware'; 6 | 7 | const app = express(); 8 | app.use(express.json()); 9 | app.use('/user', authenticateToken, userRoutes); 10 | app.use('/tweet', authenticateToken, tweetRoutes); 11 | app.use('/auth', authRoutes); 12 | 13 | app.get('/', (req, res) => { 14 | res.send('Hello "updated" world!'); 15 | }); 16 | 17 | app.listen(3000, () => { 18 | console.log('Server ready at localhost:3000'); 19 | }); 20 | -------------------------------------------------------------------------------- /src/middlewares/authMiddleware.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from 'express'; 2 | import jwt from 'jsonwebtoken'; 3 | import { PrismaClient, User } from '@prisma/client'; 4 | 5 | const JWT_SECRET = process.env.JWT_SECRET || 'SUPER SECRET'; 6 | 7 | const prisma = new PrismaClient(); 8 | 9 | type AuthRequest = Request & { user?: User }; 10 | 11 | export async function authenticateToken( 12 | req: AuthRequest, 13 | res: Response, 14 | next: NextFunction 15 | ) { 16 | // Authentication 17 | const authHeader = req.headers['authorization']; 18 | const jwtToken = authHeader?.split(' ')[1]; 19 | if (!jwtToken) { 20 | return res.sendStatus(401); 21 | } 22 | // decode the jwt token 23 | try { 24 | const payload = (await jwt.verify(jwtToken, JWT_SECRET)) as { 25 | tokenId: number; 26 | }; 27 | const dbToken = await prisma.token.findUnique({ 28 | where: { id: payload.tokenId }, 29 | include: { user: true }, 30 | }); 31 | 32 | if (!dbToken?.valid || dbToken.expiration < new Date()) { 33 | return res.status(401).json({ error: 'API token expired' }); 34 | } 35 | 36 | req.user = dbToken.user; 37 | } catch (e) { 38 | return res.sendStatus(401); 39 | } 40 | 41 | next(); 42 | } 43 | -------------------------------------------------------------------------------- /src/routes/authRoutes.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import { PrismaClient } from '@prisma/client'; 3 | import jwt from 'jsonwebtoken'; 4 | import { sendEmailToken } from '../services/emailService'; 5 | 6 | const EMAIL_TOKEN_EXPIRATION_MINUTES = 10; 7 | const AUTHENTICATION_EXPIRATION_HOURS = 12; 8 | const JWT_SECRET = process.env.JWT_SECRET || 'SUPER SECRET'; 9 | 10 | const router = Router(); 11 | const prisma = new PrismaClient(); 12 | 13 | // Generate a random 8 digit number as the email token 14 | function generateEmailToken(): string { 15 | return Math.floor(10000000 + Math.random() * 90000000).toString(); 16 | } 17 | 18 | function generateAuthToken(tokenId: number): string { 19 | const jwtPayload = { tokenId }; 20 | 21 | return jwt.sign(jwtPayload, JWT_SECRET, { 22 | algorithm: 'HS256', 23 | noTimestamp: true, 24 | }); 25 | } 26 | 27 | // Create a user, if it doesn't exist, 28 | // generate the emailToken and send it to their email 29 | router.post('/login', async (req, res) => { 30 | const { email } = req.body; 31 | 32 | // generate token 33 | const emailToken = generateEmailToken(); 34 | const expiration = new Date( 35 | new Date().getTime() + EMAIL_TOKEN_EXPIRATION_MINUTES * 60 * 1000 36 | ); 37 | 38 | try { 39 | const createdToken = await prisma.token.create({ 40 | data: { 41 | type: 'EMAIL', 42 | emailToken, 43 | expiration, 44 | user: { 45 | connectOrCreate: { 46 | where: { email }, 47 | create: { email }, 48 | }, 49 | }, 50 | }, 51 | }); 52 | 53 | console.log(createdToken); 54 | // TODO send emailToken to user's email 55 | await sendEmailToken(email, emailToken); 56 | res.sendStatus(200); 57 | } catch (e) { 58 | console.log(e); 59 | res 60 | .status(400) 61 | .json({ error: "Couldn't start the authentication process" }); 62 | } 63 | }); 64 | 65 | // Validate the emailToken 66 | // Generate a long-lived JWT token 67 | router.post('/authenticate', async (req, res) => { 68 | const { email, emailToken } = req.body; 69 | 70 | const dbEmailToken = await prisma.token.findUnique({ 71 | where: { 72 | emailToken, 73 | }, 74 | include: { 75 | user: true, 76 | }, 77 | }); 78 | 79 | if (!dbEmailToken || !dbEmailToken.valid) { 80 | return res.sendStatus(401); 81 | } 82 | 83 | if (dbEmailToken.expiration < new Date()) { 84 | return res.status(401).json({ error: 'Token expired!' }); 85 | } 86 | 87 | if (dbEmailToken?.user?.email !== email) { 88 | return res.sendStatus(401); 89 | } 90 | 91 | // Here we validated that the user is the owner of the email 92 | 93 | // generate an API token 94 | const expiration = new Date( 95 | new Date().getTime() + AUTHENTICATION_EXPIRATION_HOURS * 60 * 60 * 1000 96 | ); 97 | const apiToken = await prisma.token.create({ 98 | data: { 99 | type: 'API', 100 | expiration, 101 | user: { 102 | connect: { 103 | email, 104 | }, 105 | }, 106 | }, 107 | }); 108 | 109 | // Invalidate the email 110 | await prisma.token.update({ 111 | where: { id: dbEmailToken.id }, 112 | data: { valid: false }, 113 | }); 114 | 115 | // generate the JWT token 116 | const authToken = generateAuthToken(apiToken.id); 117 | 118 | res.json({ authToken }); 119 | }); 120 | 121 | export default router; 122 | -------------------------------------------------------------------------------- /src/routes/tweetRoutes.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import { PrismaClient } from '@prisma/client'; 3 | 4 | const router = Router(); 5 | const prisma = new PrismaClient(); 6 | 7 | // Tweet CRUD 8 | 9 | // Create Tweet 10 | router.post('/', async (req, res) => { 11 | const { content, image } = req.body; 12 | // @ts-ignore 13 | const user = req.user; 14 | 15 | try { 16 | const result = await prisma.tweet.create({ 17 | data: { 18 | content, 19 | image, 20 | userId: user.id, 21 | }, 22 | include: { user: true }, 23 | }); 24 | 25 | res.json(result); 26 | } catch (e) { 27 | res.status(400).json({ error: 'Username and email should be unique' }); 28 | } 29 | }); 30 | 31 | // list Tweet 32 | router.get('/', async (req, res) => { 33 | const allTweets = await prisma.tweet.findMany({ 34 | include: { 35 | user: { 36 | select: { 37 | id: true, 38 | name: true, 39 | username: true, 40 | image: true, 41 | }, 42 | }, 43 | }, 44 | }); 45 | res.json(allTweets); 46 | }); 47 | 48 | // get one Tweet 49 | router.get('/:id', async (req, res) => { 50 | const { id } = req.params; 51 | console.log('Query tweet with id: ', id); 52 | 53 | const tweet = await prisma.tweet.findUnique({ 54 | where: { id: Number(id) }, 55 | include: { user: true }, 56 | }); 57 | if (!tweet) { 58 | return res.status(404).json({ error: 'Tweet not found!' }); 59 | } 60 | 61 | res.json(tweet); 62 | }); 63 | 64 | // update Tweet 65 | router.put('/:id', (req, res) => { 66 | const { id } = req.params; 67 | res.status(501).json({ error: `Not Implemented: ${id}` }); 68 | }); 69 | 70 | // delete Tweet 71 | router.delete('/:id', async (req, res) => { 72 | const { id } = req.params; 73 | await prisma.tweet.delete({ where: { id: Number(id) } }); 74 | res.sendStatus(200); 75 | }); 76 | 77 | export default router; 78 | -------------------------------------------------------------------------------- /src/routes/userRoutes.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import { PrismaClient } from '@prisma/client'; 3 | 4 | const router = Router(); 5 | const prisma = new PrismaClient(); 6 | 7 | // User CRUD 8 | 9 | /* 10 | Test with curl: 11 | 12 | curl -X POST -H "Content-Type: application/json" \ 13 | -d '{"name": "Elon Musk", "email": "doge@twitter.com", "username": "elon"}' \ 14 | http://localhost:3000/user/ 15 | 16 | */ 17 | // Create user 18 | router.post('/', async (req, res) => { 19 | const { email, name, username } = req.body; 20 | 21 | try { 22 | const result = await prisma.user.create({ 23 | data: { 24 | email, 25 | name, 26 | username, 27 | bio: "Hello, I'm new on Twitter", 28 | }, 29 | }); 30 | 31 | res.json(result); 32 | } catch (e) { 33 | res.status(400).json({ error: 'Username and email should be unique' }); 34 | } 35 | }); 36 | 37 | // list users 38 | router.get('/', async (req, res) => { 39 | const allUser = await prisma.user.findMany({ 40 | // select: { 41 | // id: true, 42 | // name: true, 43 | // image: true, 44 | // bio: true, 45 | // }, 46 | }); 47 | 48 | res.json(allUser); 49 | }); 50 | 51 | // get one user 52 | router.get('/:id', async (req, res) => { 53 | const { id } = req.params; 54 | const user = await prisma.user.findUnique({ 55 | where: { id: Number(id) }, 56 | include: { tweets: true }, 57 | }); 58 | 59 | res.json(user); 60 | }); 61 | 62 | /* 63 | Test with curl: 64 | 65 | curl -X PUT -H "Content-Type: application/json" \ 66 | -d '{"name": "Vadim", "bio": "Hello there!"}' \ 67 | http://localhost:3000/user/1 68 | 69 | */ 70 | // update user 71 | router.put('/:id', async (req, res) => { 72 | const { id } = req.params; 73 | const { bio, name, image } = req.body; 74 | 75 | try { 76 | const result = await prisma.user.update({ 77 | where: { id: Number(id) }, 78 | data: { bio, name, image }, 79 | }); 80 | res.json(result); 81 | } catch (e) { 82 | res.status(400).json({ error: `Failed to update the user` }); 83 | } 84 | }); 85 | 86 | // curl -X DELETE http://localhost:3000/user/6 87 | // delete user 88 | router.delete('/:id', async (req, res) => { 89 | const { id } = req.params; 90 | await prisma.user.delete({ where: { id: Number(id) } }); 91 | res.sendStatus(200); 92 | }); 93 | 94 | export default router; 95 | -------------------------------------------------------------------------------- /src/services/emailService.ts: -------------------------------------------------------------------------------- 1 | import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses'; 2 | import { error } from 'console'; 3 | require('dotenv').config() 4 | 5 | const ses = new SESClient({}); 6 | 7 | function createSendEmailCommand( 8 | toAddress: string, 9 | fromAddress: string, 10 | message: string 11 | ) { 12 | return new SendEmailCommand({ 13 | Destination: { 14 | ToAddresses: [toAddress], 15 | }, 16 | Source: fromAddress, 17 | Message: { 18 | Subject: { 19 | Charset: 'UTF-8', 20 | Data: 'Your one-time password', 21 | }, 22 | Body: { 23 | Text: { 24 | Charset: 'UTF-8', 25 | Data: message, 26 | }, 27 | }, 28 | }, 29 | }); 30 | } 31 | 32 | export async function sendEmailToken(email: string, token: string) { 33 | console.log('email: ', email, token); 34 | 35 | const message = `Your one time password: ${token}`; 36 | const command = createSendEmailCommand( 37 | email, 38 | 'savinvadim1312@gmail.com', 39 | message 40 | ); 41 | 42 | try { 43 | return await ses.send(command); 44 | } catch (e) { 45 | console.log('Error sending email', e); 46 | return error; 47 | } 48 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "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. */ 58 | "outDir": "./build", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 68 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "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. */ 79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 83 | 84 | /* Type Checking */ 85 | "strict": true, /* Enable all strict type-checking options. */ 86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 104 | 105 | /* Completeness */ 106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 108 | } 109 | } 110 | --------------------------------------------------------------------------------