From 5a16efb525e67050ba53d77cbd80420aa1c23799 Mon Sep 17 00:00:00 2001 From: hadongwoo02 Date: Sun, 18 Jan 2026 21:59:55 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=EB=A6=AC=EB=B7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 4 + .gitignore | 10 + .prettierrc | 9 + dist/controllers/articlesController.d.ts | 11 + dist/controllers/articlesController.d.ts.map | 1 + dist/controllers/articlesController.js | 198 + dist/controllers/articlesController.js.map | 1 + dist/controllers/authController.d.ts | 6 + dist/controllers/authController.d.ts.map | 1 + dist/controllers/authController.js | 80 + dist/controllers/authController.js.map | 1 + dist/controllers/commentsController.d.ts | 4 + dist/controllers/commentsController.d.ts.map | 1 + dist/controllers/commentsController.js | 47 + dist/controllers/commentsController.js.map | 1 + dist/controllers/errorController.d.ts | 4 + dist/controllers/errorController.d.ts.map | 1 + dist/controllers/errorController.js | 43 + dist/controllers/errorController.js.map | 1 + dist/controllers/imagesController.d.ts | 5 + dist/controllers/imagesController.d.ts.map | 1 + dist/controllers/imagesController.js | 43 + dist/controllers/imagesController.js.map | 1 + dist/controllers/productsController.d.ts | 11 + dist/controllers/productsController.d.ts.map | 1 + dist/controllers/productsController.js | 194 + dist/controllers/productsController.js.map | 1 + dist/controllers/usersController.d.ts | 7 + dist/controllers/usersController.d.ts.map | 1 + dist/controllers/usersController.js | 151 + dist/controllers/usersController.js.map | 1 + dist/lib/constants.d.ts | 10 + dist/lib/constants.d.ts.map | 1 + dist/lib/constants.js | 18 + dist/lib/constants.js.map | 1 + dist/lib/errors/BadRequestError.d.ts | 5 + dist/lib/errors/BadRequestError.d.ts.map | 1 + dist/lib/errors/BadRequestError.js | 10 + dist/lib/errors/BadRequestError.js.map | 1 + dist/lib/errors/ForbiddenError.d.ts | 5 + dist/lib/errors/ForbiddenError.d.ts.map | 1 + dist/lib/errors/ForbiddenError.js | 10 + dist/lib/errors/ForbiddenError.js.map | 1 + dist/lib/errors/NotFoundError.d.ts | 5 + dist/lib/errors/NotFoundError.d.ts.map | 1 + dist/lib/errors/NotFoundError.js | 10 + dist/lib/errors/NotFoundError.js.map | 1 + dist/lib/errors/UnauthorizedError.d.ts | 5 + dist/lib/errors/UnauthorizedError.d.ts.map | 1 + dist/lib/errors/UnauthorizedError.js | 10 + dist/lib/errors/UnauthorizedError.js.map | 1 + dist/lib/prismaClient.d.ts | 3 + dist/lib/prismaClient.d.ts.map | 1 + dist/lib/prismaClient.js | 6 + dist/lib/prismaClient.js.map | 1 + dist/lib/token.d.ts | 12 + dist/lib/token.d.ts.map | 1 + dist/lib/token.js | 30 + dist/lib/token.js.map | 1 + dist/lib/withAsync.d.ts | 5 + dist/lib/withAsync.d.ts.map | 1 + dist/lib/withAsync.js | 14 + dist/lib/withAsync.js.map | 1 + dist/main.d.ts | 2 + dist/main.d.ts.map | 1 + dist/main.js | 34 + dist/main.js.map | 1 + dist/middlewares/authenticate.d.ts | 6 + dist/middlewares/authenticate.d.ts.map | 1 + dist/middlewares/authenticate.js | 30 + dist/middlewares/authenticate.js.map | 1 + dist/routers/articlesRouter.d.ts | 3 + dist/routers/articlesRouter.d.ts.map | 1 + dist/routers/articlesRouter.js | 21 + dist/routers/articlesRouter.js.map | 1 + dist/routers/authRouter.d.ts | 3 + dist/routers/authRouter.d.ts.map | 1 + dist/routers/authRouter.js | 15 + dist/routers/authRouter.js.map | 1 + dist/routers/commentsRouter.d.ts | 3 + dist/routers/commentsRouter.d.ts.map | 1 + dist/routers/commentsRouter.js | 14 + dist/routers/commentsRouter.js.map | 1 + dist/routers/imagesRouter.d.ts | 3 + dist/routers/imagesRouter.d.ts.map | 1 + dist/routers/imagesRouter.js | 12 + dist/routers/imagesRouter.js.map | 1 + dist/routers/productsRouter.d.ts | 3 + dist/routers/productsRouter.d.ts.map | 1 + dist/routers/productsRouter.js | 21 + dist/routers/productsRouter.js.map | 1 + dist/routers/usersRouter.d.ts | 3 + dist/routers/usersRouter.d.ts.map | 1 + dist/routers/usersRouter.js | 17 + dist/routers/usersRouter.js.map | 1 + dist/structs/articlesStructs.d.ts | 32 + dist/structs/articlesStructs.d.ts.map | 1 + dist/structs/articlesStructs.js | 13 + dist/structs/articlesStructs.js.map | 1 + dist/structs/authStructs.d.ts | 17 + dist/structs/authStructs.d.ts.map | 1 + dist/structs/authStructs.js | 14 + dist/structs/authStructs.js.map | 1 + dist/structs/commentsStruct.d.ts | 24 + dist/structs/commentsStruct.d.ts.map | 1 + dist/structs/commentsStruct.js | 11 + dist/structs/commentsStruct.js.map | 1 + dist/structs/commonStructs.d.ts | 32 + dist/structs/commonStructs.d.ts.map | 1 + dist/structs/commonStructs.js | 22 + dist/structs/commonStructs.js.map | 1 + dist/structs/productsStruct.d.ts | 40 + dist/structs/productsStruct.d.ts.map | 1 + dist/structs/productsStruct.js | 15 + dist/structs/productsStruct.js.map | 1 + dist/structs/usersStructs.d.ts | 43 + dist/structs/usersStructs.d.ts.map | 1 + dist/structs/usersStructs.js | 17 + dist/structs/usersStructs.js.map | 1 + package-lock.json | 4067 +++++++++++++++++ package.json | 40 + .../migrations/20250111082621_/migration.sql | 43 + .../20250304075708_add_user/migration.sql | 15 + .../migration.sql | 31 + .../migration.sql | 33 + prisma/migrations/migration_lock.toml | 3 + prisma/schema.prisma | 90 + public/.gitkeep | 0 src/controllers/articlesController.ts | 231 + src/controllers/authController.ts | 91 + src/controllers/commentsController.ts | 53 + src/controllers/errorController.ts | 44 + src/controllers/imagesController.ts | 41 + src/controllers/productsController.ts | 226 + src/controllers/usersController.ts | 170 + src/lib/constants.ts | 12 + src/lib/errors/BadRequestError.ts | 8 + src/lib/errors/ForbiddenError.ts | 8 + src/lib/errors/NotFoundError.ts | 8 + src/lib/errors/UnauthorizedError.ts | 8 + src/lib/prismaClient.ts | 3 + src/lib/token.ts | 30 + src/lib/withAsync.ts | 13 + src/main.ts | 35 + src/middlewares/authenticate.ts | 30 + src/routers/articlesRouter.ts | 28 + src/routers/authRouter.ts | 12 + src/routers/commentsRouter.ts | 11 + src/routers/imagesRouter.ts | 9 + src/routers/productsRouter.ts | 28 + src/routers/usersRouter.ts | 20 + src/structs/articlesStructs.ts | 12 + src/structs/authStructs.ts | 13 + src/structs/commentsStruct.ts | 10 + src/structs/commonStructs.ts | 22 + src/structs/productsStruct.ts | 14 + src/structs/usersStructs.ts | 19 + src/type/express.d.ts | 12 + tests/test.http | 188 + tests/test.js | 68 + tests/test.png | Bin 0 -> 6066 bytes tsconfig.json | 45 + 162 files changed, 7357 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 .prettierrc create mode 100644 dist/controllers/articlesController.d.ts create mode 100644 dist/controllers/articlesController.d.ts.map create mode 100644 dist/controllers/articlesController.js create mode 100644 dist/controllers/articlesController.js.map create mode 100644 dist/controllers/authController.d.ts create mode 100644 dist/controllers/authController.d.ts.map create mode 100644 dist/controllers/authController.js create mode 100644 dist/controllers/authController.js.map create mode 100644 dist/controllers/commentsController.d.ts create mode 100644 dist/controllers/commentsController.d.ts.map create mode 100644 dist/controllers/commentsController.js create mode 100644 dist/controllers/commentsController.js.map create mode 100644 dist/controllers/errorController.d.ts create mode 100644 dist/controllers/errorController.d.ts.map create mode 100644 dist/controllers/errorController.js create mode 100644 dist/controllers/errorController.js.map create mode 100644 dist/controllers/imagesController.d.ts create mode 100644 dist/controllers/imagesController.d.ts.map create mode 100644 dist/controllers/imagesController.js create mode 100644 dist/controllers/imagesController.js.map create mode 100644 dist/controllers/productsController.d.ts create mode 100644 dist/controllers/productsController.d.ts.map create mode 100644 dist/controllers/productsController.js create mode 100644 dist/controllers/productsController.js.map create mode 100644 dist/controllers/usersController.d.ts create mode 100644 dist/controllers/usersController.d.ts.map create mode 100644 dist/controllers/usersController.js create mode 100644 dist/controllers/usersController.js.map create mode 100644 dist/lib/constants.d.ts create mode 100644 dist/lib/constants.d.ts.map create mode 100644 dist/lib/constants.js create mode 100644 dist/lib/constants.js.map create mode 100644 dist/lib/errors/BadRequestError.d.ts create mode 100644 dist/lib/errors/BadRequestError.d.ts.map create mode 100644 dist/lib/errors/BadRequestError.js create mode 100644 dist/lib/errors/BadRequestError.js.map create mode 100644 dist/lib/errors/ForbiddenError.d.ts create mode 100644 dist/lib/errors/ForbiddenError.d.ts.map create mode 100644 dist/lib/errors/ForbiddenError.js create mode 100644 dist/lib/errors/ForbiddenError.js.map create mode 100644 dist/lib/errors/NotFoundError.d.ts create mode 100644 dist/lib/errors/NotFoundError.d.ts.map create mode 100644 dist/lib/errors/NotFoundError.js create mode 100644 dist/lib/errors/NotFoundError.js.map create mode 100644 dist/lib/errors/UnauthorizedError.d.ts create mode 100644 dist/lib/errors/UnauthorizedError.d.ts.map create mode 100644 dist/lib/errors/UnauthorizedError.js create mode 100644 dist/lib/errors/UnauthorizedError.js.map create mode 100644 dist/lib/prismaClient.d.ts create mode 100644 dist/lib/prismaClient.d.ts.map create mode 100644 dist/lib/prismaClient.js create mode 100644 dist/lib/prismaClient.js.map create mode 100644 dist/lib/token.d.ts create mode 100644 dist/lib/token.d.ts.map create mode 100644 dist/lib/token.js create mode 100644 dist/lib/token.js.map create mode 100644 dist/lib/withAsync.d.ts create mode 100644 dist/lib/withAsync.d.ts.map create mode 100644 dist/lib/withAsync.js create mode 100644 dist/lib/withAsync.js.map create mode 100644 dist/main.d.ts create mode 100644 dist/main.d.ts.map create mode 100644 dist/main.js create mode 100644 dist/main.js.map create mode 100644 dist/middlewares/authenticate.d.ts create mode 100644 dist/middlewares/authenticate.d.ts.map create mode 100644 dist/middlewares/authenticate.js create mode 100644 dist/middlewares/authenticate.js.map create mode 100644 dist/routers/articlesRouter.d.ts create mode 100644 dist/routers/articlesRouter.d.ts.map create mode 100644 dist/routers/articlesRouter.js create mode 100644 dist/routers/articlesRouter.js.map create mode 100644 dist/routers/authRouter.d.ts create mode 100644 dist/routers/authRouter.d.ts.map create mode 100644 dist/routers/authRouter.js create mode 100644 dist/routers/authRouter.js.map create mode 100644 dist/routers/commentsRouter.d.ts create mode 100644 dist/routers/commentsRouter.d.ts.map create mode 100644 dist/routers/commentsRouter.js create mode 100644 dist/routers/commentsRouter.js.map create mode 100644 dist/routers/imagesRouter.d.ts create mode 100644 dist/routers/imagesRouter.d.ts.map create mode 100644 dist/routers/imagesRouter.js create mode 100644 dist/routers/imagesRouter.js.map create mode 100644 dist/routers/productsRouter.d.ts create mode 100644 dist/routers/productsRouter.d.ts.map create mode 100644 dist/routers/productsRouter.js create mode 100644 dist/routers/productsRouter.js.map create mode 100644 dist/routers/usersRouter.d.ts create mode 100644 dist/routers/usersRouter.d.ts.map create mode 100644 dist/routers/usersRouter.js create mode 100644 dist/routers/usersRouter.js.map create mode 100644 dist/structs/articlesStructs.d.ts create mode 100644 dist/structs/articlesStructs.d.ts.map create mode 100644 dist/structs/articlesStructs.js create mode 100644 dist/structs/articlesStructs.js.map create mode 100644 dist/structs/authStructs.d.ts create mode 100644 dist/structs/authStructs.d.ts.map create mode 100644 dist/structs/authStructs.js create mode 100644 dist/structs/authStructs.js.map create mode 100644 dist/structs/commentsStruct.d.ts create mode 100644 dist/structs/commentsStruct.d.ts.map create mode 100644 dist/structs/commentsStruct.js create mode 100644 dist/structs/commentsStruct.js.map create mode 100644 dist/structs/commonStructs.d.ts create mode 100644 dist/structs/commonStructs.d.ts.map create mode 100644 dist/structs/commonStructs.js create mode 100644 dist/structs/commonStructs.js.map create mode 100644 dist/structs/productsStruct.d.ts create mode 100644 dist/structs/productsStruct.d.ts.map create mode 100644 dist/structs/productsStruct.js create mode 100644 dist/structs/productsStruct.js.map create mode 100644 dist/structs/usersStructs.d.ts create mode 100644 dist/structs/usersStructs.d.ts.map create mode 100644 dist/structs/usersStructs.js create mode 100644 dist/structs/usersStructs.js.map create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 prisma/migrations/20250111082621_/migration.sql create mode 100644 prisma/migrations/20250304075708_add_user/migration.sql create mode 100644 prisma/migrations/20250304082334_authorization/migration.sql create mode 100644 prisma/migrations/20250304094902_add_favorite_like/migration.sql create mode 100644 prisma/migrations/migration_lock.toml create mode 100644 prisma/schema.prisma create mode 100644 public/.gitkeep create mode 100644 src/controllers/articlesController.ts create mode 100644 src/controllers/authController.ts create mode 100644 src/controllers/commentsController.ts create mode 100644 src/controllers/errorController.ts create mode 100644 src/controllers/imagesController.ts create mode 100644 src/controllers/productsController.ts create mode 100644 src/controllers/usersController.ts create mode 100644 src/lib/constants.ts create mode 100644 src/lib/errors/BadRequestError.ts create mode 100644 src/lib/errors/ForbiddenError.ts create mode 100644 src/lib/errors/NotFoundError.ts create mode 100644 src/lib/errors/UnauthorizedError.ts create mode 100644 src/lib/prismaClient.ts create mode 100644 src/lib/token.ts create mode 100644 src/lib/withAsync.ts create mode 100644 src/main.ts create mode 100644 src/middlewares/authenticate.ts create mode 100644 src/routers/articlesRouter.ts create mode 100644 src/routers/authRouter.ts create mode 100644 src/routers/commentsRouter.ts create mode 100644 src/routers/imagesRouter.ts create mode 100644 src/routers/productsRouter.ts create mode 100644 src/routers/usersRouter.ts create mode 100644 src/structs/articlesStructs.ts create mode 100644 src/structs/authStructs.ts create mode 100644 src/structs/commentsStruct.ts create mode 100644 src/structs/commonStructs.ts create mode 100644 src/structs/productsStruct.ts create mode 100644 src/structs/usersStructs.ts create mode 100644 src/type/express.d.ts create mode 100644 tests/test.http create mode 100644 tests/test.js create mode 100644 tests/test.png create mode 100644 tsconfig.json diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..2ea82462 --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +DATABASE_URL=postgresql://postgres:postgres@localhost:5432/panda-market +PORT=3000 +JWT_ACCESS_TOKEN_SECRET=your-secret-key +JWT_REFRESH_TOKEN_SECRET=your-refresh-secret-key diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b0fc192f --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Local files +.vscode/ +node_modules/ +.env* +!.env.example + +# Uploaded files +public/* +!public/.gitkeep + diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..503a5da4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "semi": true, + "printWidth": 100, + "endOfLine": "auto", + "arrowParens": "always", + "tabWidth": 2 +} diff --git a/dist/controllers/articlesController.d.ts b/dist/controllers/articlesController.d.ts new file mode 100644 index 00000000..05b668d3 --- /dev/null +++ b/dist/controllers/articlesController.d.ts @@ -0,0 +1,11 @@ +import { Request, Response } from "express"; +export declare function createArticle(req: Request, res: Response): Promise>>; +export declare function getArticle(req: Request, res: Response): Promise>>; +export declare function updateArticle(req: Request, res: Response): Promise>>; +export declare function deleteArticle(req: Request, res: Response): Promise>>; +export declare function getArticleList(req: Request, res: Response): Promise>>; +export declare function createComment(req: Request, res: Response): Promise>>; +export declare function getCommentList(req: Request, res: Response): Promise>>; +export declare function createLike(req: Request, res: Response): Promise>>; +export declare function deleteLike(req: Request, res: Response): Promise>>; +//# sourceMappingURL=articlesController.d.ts.map \ No newline at end of file diff --git a/dist/controllers/articlesController.d.ts.map b/dist/controllers/articlesController.d.ts.map new file mode 100644 index 00000000..62309773 --- /dev/null +++ b/dist/controllers/articlesController.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"articlesController.d.ts","sourceRoot":"","sources":["../../src/controllers/articlesController.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAgB,MAAM,SAAS,CAAC;AAG1D,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAe9D;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAqB3D;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAuB9D;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAkB9D;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAkC/D;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAsB9D;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAuB/D;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAqB3D;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAqB3D"} \ No newline at end of file diff --git a/dist/controllers/articlesController.js b/dist/controllers/articlesController.js new file mode 100644 index 00000000..61fee3d9 --- /dev/null +++ b/dist/controllers/articlesController.js @@ -0,0 +1,198 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createArticle = createArticle; +exports.getArticle = getArticle; +exports.updateArticle = updateArticle; +exports.deleteArticle = deleteArticle; +exports.getArticleList = getArticleList; +exports.createComment = createComment; +exports.getCommentList = getCommentList; +exports.createLike = createLike; +exports.deleteLike = deleteLike; +const superstruct_1 = require("superstruct"); +const prismaClient_1 = require("../lib/prismaClient"); +const NotFoundError_1 = __importDefault(require("../lib/errors/NotFoundError")); +const commonStructs_1 = require("../structs/commonStructs"); +const articlesStructs_1 = require("../structs/articlesStructs"); +const commentsStruct_1 = require("../structs/commentsStruct"); +const UnauthorizedError_1 = __importDefault(require("../lib/errors/UnauthorizedError")); +const ForbiddenError_1 = __importDefault(require("../lib/errors/ForbiddenError")); +const BadRequestError_1 = __importDefault(require("../lib/errors/BadRequestError")); +async function createArticle(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const data = (0, superstruct_1.create)(req.body, articlesStructs_1.CreateArticleBodyStruct); + const article = await prismaClient_1.prismaClient.article.create({ + data: { + ...data, + userId: req.user.id, + }, + }); + return res.status(201).send(article); +} +async function getArticle(req, res) { + const { id } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const article = await prismaClient_1.prismaClient.article.findUnique({ + where: { id }, + include: { + likes: true, + }, + }); + if (!article) { + throw new NotFoundError_1.default('article', id); + } + const articleWithLikes = { + ...article, + likes: undefined, + likeCount: article.likes.length, + isLiked: req.user ? article.likes.some((like) => like.userId === req.user.id) : undefined, + }; + return res.send(articleWithLikes); +} +async function updateArticle(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const { id } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const data = (0, superstruct_1.create)(req.body, articlesStructs_1.UpdateArticleBodyStruct); + const existingArticle = await prismaClient_1.prismaClient.article.findUnique({ where: { id } }); + if (!existingArticle) { + throw new NotFoundError_1.default('article', id); + } + if (existingArticle.userId !== req.user.id) { + throw new ForbiddenError_1.default('Should be the owner of the article'); + } + const updatedArticle = await prismaClient_1.prismaClient.article.update({ where: { id }, data: { + ...(title !== undefined && { title }), + ...(content !== undefined && { content }), + ...(image !== undefined && { image }), + }, }); + return res.send(updatedArticle); +} +async function deleteArticle(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const { id } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const existingArticle = await prismaClient_1.prismaClient.article.findUnique({ where: { id } }); + if (!existingArticle) { + throw new NotFoundError_1.default('article', id); + } + if (existingArticle.userId !== req.user.id) { + throw new ForbiddenError_1.default('Should be the owner of the article'); + } + await prismaClient_1.prismaClient.article.delete({ where: { id } }); + return res.status(204).send(); +} +async function getArticleList(req, res) { + const { page, pageSize, orderBy, keyword } = (0, superstruct_1.create)(req.query, articlesStructs_1.GetArticleListParamsStruct); + const where = keyword + ? { + OR: [ + { title: { contains: keyword } }, + { content: { contains: keyword } }, + ], + } + : {}; + const totalCount = await prismaClient_1.prismaClient.article.count({ where }); + const articles = await prismaClient_1.prismaClient.article.findMany({ + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: orderBy === 'recent' ? { createdAt: 'desc' } : { id: 'asc' }, + where, + include: { + likes: true, + }, + }); + const articlesWithLikes = articles.map((article) => ({ + ...article, + likes: undefined, + likeCount: article.likes.length, + isLiked: req.user ? article.likes.some((like) => like.userId === req.user.id) : undefined, + })); + return res.send({ + list: articlesWithLikes, + totalCount, + }); +} +async function createComment(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const { id: articleId } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const { content } = (0, superstruct_1.create)(req.body, commentsStruct_1.CreateCommentBodyStruct); + const existingArticle = await prismaClient_1.prismaClient.article.findUnique({ where: { id: articleId } }); + if (!existingArticle) { + throw new NotFoundError_1.default('article', articleId); + } + const createdComment = await prismaClient_1.prismaClient.comment.create({ + data: { + articleId, + content, + userId: req.user.id, + }, + }); + return res.status(201).send(createdComment); +} +async function getCommentList(req, res) { + const { id: articleId } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const { cursor, limit } = (0, superstruct_1.create)(req.query, commentsStruct_1.GetCommentListParamsStruct); + const article = await prismaClient_1.prismaClient.article.findUnique({ where: { id: articleId } }); + if (!article) { + throw new NotFoundError_1.default('article', articleId); + } + const commentsWithCursor = await prismaClient_1.prismaClient.comment.findMany({ + cursor: cursor ? { id: cursor } : undefined, + take: limit + 1, + where: { articleId }, + orderBy: { createdAt: 'desc' }, + }); + const comments = commentsWithCursor.slice(0, limit); + const cursorComment = commentsWithCursor[commentsWithCursor.length - 1]; + const nextCursor = cursorComment ? cursorComment.id : null; + return res.send({ + list: comments, + nextCursor, + }); +} +async function createLike(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const { id: articleId } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const existingArticle = await prismaClient_1.prismaClient.article.findUnique({ where: { id: articleId } }); + if (!existingArticle) { + throw new NotFoundError_1.default('article', articleId); + } + const existingLike = await prismaClient_1.prismaClient.like.findFirst({ + where: { articleId, userId: req.user.id }, + }); + if (existingLike) { + throw new BadRequestError_1.default('Already liked'); + } + await prismaClient_1.prismaClient.like.create({ data: { articleId, userId: req.user.id } }); + return res.status(201).send(); +} +async function deleteLike(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const { id: articleId } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const existingArticle = await prismaClient_1.prismaClient.article.findUnique({ where: { id: articleId } }); + if (!existingArticle) { + throw new NotFoundError_1.default('article', articleId); + } + const existingLike = await prismaClient_1.prismaClient.like.findFirst({ + where: { articleId, userId: req.user.id }, + }); + if (!existingLike) { + throw new BadRequestError_1.default('Not liked'); + } + await prismaClient_1.prismaClient.like.delete({ where: { id: existingLike.id } }); + return res.status(204).send(); +} +//# sourceMappingURL=articlesController.js.map \ No newline at end of file diff --git a/dist/controllers/articlesController.js.map b/dist/controllers/articlesController.js.map new file mode 100644 index 00000000..b651bfef --- /dev/null +++ b/dist/controllers/articlesController.js.map @@ -0,0 +1 @@ +{"version":3,"file":"articlesController.js","sourceRoot":"","sources":["../../src/controllers/articlesController.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/controllers/authController.d.ts b/dist/controllers/authController.d.ts new file mode 100644 index 00000000..ac527c00 --- /dev/null +++ b/dist/controllers/authController.d.ts @@ -0,0 +1,6 @@ +import { Request, Response } from 'express'; +export declare function register(req: Request, res: Response): Promise; +export declare function login(req: Request, res: Response): Promise; +export declare function logout(req: Request, res: Response): Promise; +export declare function refreshToken(req: Request, res: Response): Promise; +//# sourceMappingURL=authController.d.ts.map \ No newline at end of file diff --git a/dist/controllers/authController.d.ts.map b/dist/controllers/authController.d.ts.map new file mode 100644 index 00000000..1b993b4c --- /dev/null +++ b/dist/controllers/authController.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"authController.d.ts","sourceRoot":"","sources":["../../src/controllers/authController.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAgB,MAAM,SAAS,CAAC;AAE1D,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAiBzD;AAED,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAgBtD;AAED,wBAAsB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAGvD;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAgB7D"} \ No newline at end of file diff --git a/dist/controllers/authController.js b/dist/controllers/authController.js new file mode 100644 index 00000000..e72014dc --- /dev/null +++ b/dist/controllers/authController.js @@ -0,0 +1,80 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.register = register; +exports.login = login; +exports.logout = logout; +exports.refreshToken = refreshToken; +const superstruct_1 = require("superstruct"); +const bcrypt_1 = __importDefault(require("bcrypt")); +const prismaClient_js_1 = require("../lib/prismaClient.js"); +const token_js_1 = require("../lib/token.js"); +const constants_js_1 = require("../lib/constants.js"); +const authStructs_js_1 = require("../structs/authStructs.js"); +const BadRequestError_js_1 = __importDefault(require("../lib/errors/BadRequestError.js")); +async function register(req, res) { + const { email, nickname, password } = (0, superstruct_1.create)(req.body, authStructs_js_1.RegisterBodyStruct); + const salt = await bcrypt_1.default.genSalt(10); + const hashedPassword = await bcrypt_1.default.hash(password, salt); + const isExist = await prismaClient_js_1.prismaClient.user.findUnique({ where: { email } }); + if (isExist) { + throw new BadRequestError_js_1.default('User already exists'); + } + const user = await prismaClient_js_1.prismaClient.user.create({ + data: { email, nickname, password: hashedPassword }, + }); + const { password: _, ...userWithoutPassword } = user; + res.status(201).json(userWithoutPassword); +} +async function login(req, res) { + const { email, password } = (0, superstruct_1.create)(req.body, authStructs_js_1.LoginBodyStruct); + const user = await prismaClient_js_1.prismaClient.user.findUnique({ where: { email } }); + if (!user) { + throw new BadRequestError_js_1.default('Invalid credentials'); + } + const isPasswordValid = await bcrypt_1.default.compare(password, user.password); + if (!isPasswordValid) { + throw new BadRequestError_js_1.default('Invalid credentials'); + } + const { accessToken, refreshToken } = (0, token_js_1.generateTokens)(String(user?.id)); + setTokenCookies(res, accessToken, refreshToken); + res.status(200).send(); +} +async function logout(req, res) { + clearTokenCookies(res); + res.status(200).send(); +} +async function refreshToken(req, res) { + const refreshToken = req.cookies[constants_js_1.REFRESH_TOKEN_COOKIE_NAME]; + if (!refreshToken) { + throw new BadRequestError_js_1.default('Invalid refresh token'); + } + const { userId } = (0, token_js_1.verifyRefreshToken)(refreshToken); + const user = await prismaClient_js_1.prismaClient.user.findUnique({ where: { id: Number(userId) } }); + if (!user) { + throw new BadRequestError_js_1.default('Invalid refresh token'); + } + const { accessToken, refreshToken: newRefreshToken } = (0, token_js_1.generateTokens)(userId); + setTokenCookies(res, accessToken, newRefreshToken); + res.status(200).send(); +} +function setTokenCookies(res, accessToken, refreshToken) { + res.cookie(constants_js_1.ACCESS_TOKEN_COOKIE_NAME, accessToken, { + httpOnly: true, + secure: constants_js_1.NODE_ENV === 'production', + maxAge: 1 * 60 * 60 * 1000, // 1 hour + }); + res.cookie(constants_js_1.REFRESH_TOKEN_COOKIE_NAME, refreshToken, { + httpOnly: true, + secure: constants_js_1.NODE_ENV === 'production', + maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days + path: '/auth/refresh', + }); +} +function clearTokenCookies(res) { + res.clearCookie(constants_js_1.ACCESS_TOKEN_COOKIE_NAME); + res.clearCookie(constants_js_1.REFRESH_TOKEN_COOKIE_NAME); +} +//# sourceMappingURL=authController.js.map \ No newline at end of file diff --git a/dist/controllers/authController.js.map b/dist/controllers/authController.js.map new file mode 100644 index 00000000..3fffa200 --- /dev/null +++ b/dist/controllers/authController.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authController.js","sourceRoot":"","sources":["../../src/controllers/authController.ts"],"names":[],"mappings":";;;;;AAaA,4BAiBC;AAED,sBAgBC;AAED,wBAGC;AAED,oCAgBC;AAvED,6CAAqC;AACrC,oDAA4B;AAC5B,4DAAsD;AACtD,8CAAqE;AACrE,sDAI6B;AAC7B,8DAAgF;AAChF,0FAA+D;AAGxD,KAAK,UAAU,QAAQ,CAAC,GAAY,EAAE,GAAa;IACxD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,IAAA,oBAAM,EAAC,GAAG,CAAC,IAAI,EAAE,mCAAkB,CAAC,CAAC;IAE3E,MAAM,IAAI,GAAG,MAAM,gBAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACtC,MAAM,cAAc,GAAG,MAAM,gBAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAEzD,MAAM,OAAO,GAAG,MAAM,8BAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IACzE,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,IAAI,4BAAe,CAAC,qBAAqB,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,8BAAY,CAAC,IAAI,CAAC,MAAM,CAAC;QAC1C,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE;KACpD,CAAC,CAAC;IAEH,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,mBAAmB,EAAE,GAAG,IAAI,CAAC;IACrD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;AAC5C,CAAC;AAEM,KAAK,UAAU,KAAK,CAAC,GAAY,EAAE,GAAa;IACrD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAA,oBAAM,EAAC,GAAG,CAAC,IAAI,EAAE,gCAAe,CAAC,CAAC;IAE9D,MAAM,IAAI,GAAG,MAAM,8BAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IACtE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,4BAAe,CAAC,qBAAqB,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,eAAe,GAAG,MAAM,gBAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtE,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,IAAI,4BAAe,CAAC,qBAAqB,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,IAAA,yBAAc,EAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACvE,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;IAChD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAEM,KAAK,UAAU,MAAM,CAAC,GAAY,EAAE,GAAa;IACtD,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACvB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,GAAY,EAAE,GAAa;IAC5D,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,wCAAyB,CAAC,CAAC;IAC5D,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,4BAAe,CAAC,uBAAuB,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,6BAAkB,EAAC,YAAY,CAAC,CAAC;IAEpD,MAAM,IAAI,GAAG,MAAM,8BAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;IACnF,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,4BAAe,CAAC,uBAAuB,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,GAAG,IAAA,yBAAc,EAAC,MAAM,CAAC,CAAC;IAC9E,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC;IACnD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,SAAS,eAAe,CAAC,GAAa,EAAE,WAAmB,EAAE,YAAoB;IAC/E,GAAG,CAAC,MAAM,CAAC,uCAAwB,EAAE,WAAW,EAAE;QAChD,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,uBAAQ,KAAK,YAAY;QACjC,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,SAAS;KACtC,CAAC,CAAC;IACH,GAAG,CAAC,MAAM,CAAC,wCAAyB,EAAE,YAAY,EAAE;QAClD,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,uBAAQ,KAAK,YAAY;QACjC,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,SAAS;QAC1C,IAAI,EAAE,eAAe;KACtB,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAa;IACtC,GAAG,CAAC,WAAW,CAAC,uCAAwB,CAAC,CAAC;IAC1C,GAAG,CAAC,WAAW,CAAC,wCAAyB,CAAC,CAAC;AAC7C,CAAC"} \ No newline at end of file diff --git a/dist/controllers/commentsController.d.ts b/dist/controllers/commentsController.d.ts new file mode 100644 index 00000000..62b4ebcd --- /dev/null +++ b/dist/controllers/commentsController.d.ts @@ -0,0 +1,4 @@ +import { Request, Response } from 'express'; +export declare function updateComment(req: Request, res: Response): Promise; +export declare function deleteComment(req: Request, res: Response): Promise; +//# sourceMappingURL=commentsController.d.ts.map \ No newline at end of file diff --git a/dist/controllers/commentsController.d.ts.map b/dist/controllers/commentsController.d.ts.map new file mode 100644 index 00000000..5f4968c1 --- /dev/null +++ b/dist/controllers/commentsController.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"commentsController.d.ts","sourceRoot":"","sources":["../../src/controllers/commentsController.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAe,MAAM,SAAS,CAAA;AAExD,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAuB9D;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAkB9D"} \ No newline at end of file diff --git a/dist/controllers/commentsController.js b/dist/controllers/commentsController.js new file mode 100644 index 00000000..23338760 --- /dev/null +++ b/dist/controllers/commentsController.js @@ -0,0 +1,47 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.updateComment = updateComment; +exports.deleteComment = deleteComment; +const superstruct_1 = require("superstruct"); +const prismaClient_js_1 = require("../lib/prismaClient.js"); +const commentsStruct_js_1 = require("../structs/commentsStruct.js"); +const NotFoundError_js_1 = __importDefault(require("../lib/errors/NotFoundError.js")); +const commonStructs_js_1 = require("../structs/commonStructs.js"); +const UnauthorizedError_js_1 = __importDefault(require("../lib/errors/UnauthorizedError.js")); +const ForbiddenError_js_1 = __importDefault(require("../lib/errors/ForbiddenError.js")); +async function updateComment(req, res) { + if (!req.user) { + throw new UnauthorizedError_js_1.default('Unauthorized'); + } + const { id } = (0, superstruct_1.create)(req.params, commonStructs_js_1.IdParamsStruct); + const { content } = (0, superstruct_1.create)(req.body, commentsStruct_js_1.UpdateCommentBodyStruct); + const existingComment = await prismaClient_js_1.prismaClient.comment.findUnique({ where: { id } }); + if (!existingComment) { + throw new NotFoundError_js_1.default('comment', id); + } + if (existingComment.userId !== req.user.id) { + throw new ForbiddenError_js_1.default('Should be the owner of the comment'); + } + const updatedComment = await prismaClient_js_1.prismaClient.comment.update({ + where: { id }, + data: { content }, + }); +} +async function deleteComment(req, res) { + if (!req.user) { + throw new UnauthorizedError_js_1.default('Unauthorized'); + } + const { id } = (0, superstruct_1.create)(req.params, commonStructs_js_1.IdParamsStruct); + const existingComment = await prismaClient_js_1.prismaClient.comment.findUnique({ where: { id } }); + if (!existingComment) { + throw new NotFoundError_js_1.default('comment', id); + } + if (existingComment.userId !== req.user.id) { + throw new ForbiddenError_js_1.default('Should be the owner of the comment'); + } + await prismaClient_js_1.prismaClient.comment.delete({ where: { id } }); +} +//# sourceMappingURL=commentsController.js.map \ No newline at end of file diff --git a/dist/controllers/commentsController.js.map b/dist/controllers/commentsController.js.map new file mode 100644 index 00000000..0df5d877 --- /dev/null +++ b/dist/controllers/commentsController.js.map @@ -0,0 +1 @@ +{"version":3,"file":"commentsController.js","sourceRoot":"","sources":["../../src/controllers/commentsController.ts"],"names":[],"mappings":";;;;;AASA,sCAuBC;AAED,sCAkBC;AApDD,6CAAqC;AACrC,4DAAsD;AACtD,oEAAuE;AACvE,sFAA2D;AAC3D,kEAA6D;AAC7D,8FAAmE;AACnE,wFAA6D;AAGtD,KAAK,UAAU,aAAa,CAAC,GAAY,EAAE,GAAa;IAC7D,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,IAAI,8BAAiB,CAAC,cAAc,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,EAAE,EAAE,EAAE,GAAG,IAAA,oBAAM,EAAC,GAAG,CAAC,MAAM,EAAE,iCAAc,CAAC,CAAC;IAClD,MAAM,EAAE,OAAO,EAAE,GAAG,IAAA,oBAAM,EAAC,GAAG,CAAC,IAAI,EAAE,2CAAuB,CAAC,CAAC;IAE9D,MAAM,eAAe,GAAG,MAAM,8BAAY,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACjF,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,IAAI,0BAAa,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,eAAe,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,2BAAc,CAAC,oCAAoC,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,8BAAY,CAAC,OAAO,CAAC,MAAM,CAAC;QACvD,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI,EAAE,EAAE,OAAO,EAAE;KAClB,CAAC,CAAC;AAGL,CAAC;AAEM,KAAK,UAAU,aAAa,CAAC,GAAY,EAAE,GAAa;IAC7D,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,IAAI,8BAAiB,CAAC,cAAc,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,EAAE,EAAE,EAAE,GAAG,IAAA,oBAAM,EAAC,GAAG,CAAC,MAAM,EAAE,iCAAc,CAAC,CAAC;IAElD,MAAM,eAAe,GAAG,MAAM,8BAAY,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACjF,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,IAAI,0BAAa,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,eAAe,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,2BAAc,CAAC,oCAAoC,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,8BAAY,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAEvD,CAAC"} \ No newline at end of file diff --git a/dist/controllers/errorController.d.ts b/dist/controllers/errorController.d.ts new file mode 100644 index 00000000..d2339a2f --- /dev/null +++ b/dist/controllers/errorController.d.ts @@ -0,0 +1,4 @@ +import { Request, Response, NextFunction } from 'express'; +export declare function defaultNotFoundHandler(req: Request, res: Response, next: NextFunction): Response>; +export declare function globalErrorHandler(err: any, req: Request, res: Response, next: NextFunction): Response>; +//# sourceMappingURL=errorController.d.ts.map \ No newline at end of file diff --git a/dist/controllers/errorController.d.ts.map b/dist/controllers/errorController.d.ts.map new file mode 100644 index 00000000..8fb83cbc --- /dev/null +++ b/dist/controllers/errorController.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"errorController.d.ts","sourceRoot":"","sources":["../../src/controllers/errorController.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE1D,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,sCAErF;AAED,wBAAgB,kBAAkB,CAAC,GAAG,KAAA,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,sCAgCtF"} \ No newline at end of file diff --git a/dist/controllers/errorController.js b/dist/controllers/errorController.js new file mode 100644 index 00000000..ba531c84 --- /dev/null +++ b/dist/controllers/errorController.js @@ -0,0 +1,43 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.defaultNotFoundHandler = defaultNotFoundHandler; +exports.globalErrorHandler = globalErrorHandler; +const superstruct_1 = require("superstruct"); +const BadRequestError_1 = __importDefault(require("../lib/errors/BadRequestError")); +const NotFoundError_js_1 = __importDefault(require("../lib/errors/NotFoundError.js")); +const UnauthorizedError_1 = __importDefault(require("../lib/errors/UnauthorizedError")); +const ForbiddenError_1 = __importDefault(require("../lib/errors/ForbiddenError")); +function defaultNotFoundHandler(req, res, next) { + return res.status(404).send({ message: 'Not found' }); +} +function globalErrorHandler(err, req, res, next) { + /** From superstruct or application error */ + if (err instanceof superstruct_1.StructError || err instanceof BadRequestError_1.default) { + return res.status(400).send({ message: err.message }); + } + /** From express.json middleware */ + if (err instanceof SyntaxError && err.status === 400 && 'body' in err) { + return res.status(400).send({ message: 'Invalid JSON' }); + } + /** Prisma error codes */ + if (err.code) { + console.error(err); + return res.status(500).send({ message: 'Failed to process data' }); + } + /** Application errors */ + if (err instanceof NotFoundError_js_1.default) { + return res.status(404).send({ message: err.message }); + } + if (err instanceof UnauthorizedError_1.default) { + return res.status(401).send({ message: err.message }); + } + if (err instanceof ForbiddenError_1.default) { + return res.status(403).send({ message: err.message }); + } + console.error(err); + return res.status(500).send({ message: 'Internal server error' }); +} +//# sourceMappingURL=errorController.js.map \ No newline at end of file diff --git a/dist/controllers/errorController.js.map b/dist/controllers/errorController.js.map new file mode 100644 index 00000000..a1de7ea9 --- /dev/null +++ b/dist/controllers/errorController.js.map @@ -0,0 +1 @@ +{"version":3,"file":"errorController.js","sourceRoot":"","sources":["../../src/controllers/errorController.ts"],"names":[],"mappings":";;;;;AAOA,wDAEC;AAED,gDAgCC;AA3CD,6CAA0C;AAC1C,oFAA4D;AAC5D,sFAA2D;AAC3D,wFAAgE;AAChE,kFAA0D;AAG1D,SAAgB,sBAAsB,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IACpF,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,SAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB;IACrF,4CAA4C;IAC5C,IAAI,GAAG,YAAY,yBAAW,IAAI,GAAG,YAAY,yBAAe,EAAE,CAAC;QACjE,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,mCAAmC;IACnC,IAAI,GAAG,YAAY,WAAW,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;QACtE,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,yBAAyB;IACzB,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,yBAAyB;IACzB,IAAI,GAAG,YAAY,0BAAa,EAAE,CAAC;QACjC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,GAAG,YAAY,2BAAiB,EAAE,CAAC;QACrC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,GAAG,YAAY,wBAAc,EAAE,CAAC;QAClC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;AACpE,CAAC"} \ No newline at end of file diff --git a/dist/controllers/imagesController.d.ts b/dist/controllers/imagesController.d.ts new file mode 100644 index 00000000..6efda3d4 --- /dev/null +++ b/dist/controllers/imagesController.d.ts @@ -0,0 +1,5 @@ +import multer from 'multer'; +import { Request, Response } from 'express'; +export declare const upload: multer.Multer; +export declare function uploadImage(req: Request, res: Response): Promise>>; +//# sourceMappingURL=imagesController.d.ts.map \ No newline at end of file diff --git a/dist/controllers/imagesController.d.ts.map b/dist/controllers/imagesController.d.ts.map new file mode 100644 index 00000000..fc4c0774 --- /dev/null +++ b/dist/controllers/imagesController.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"imagesController.d.ts","sourceRoot":"","sources":["../../src/controllers/imagesController.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAK5B,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAe,MAAM,SAAS,CAAA;AAIxD,eAAO,MAAM,MAAM,eAwBjB,CAAC;AAEH,wBAAsB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAK5D"} \ No newline at end of file diff --git a/dist/controllers/imagesController.js b/dist/controllers/imagesController.js new file mode 100644 index 00000000..54e61442 --- /dev/null +++ b/dist/controllers/imagesController.js @@ -0,0 +1,43 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.upload = void 0; +exports.uploadImage = uploadImage; +const multer_1 = __importDefault(require("multer")); +const path_1 = __importDefault(require("path")); +const uuid_1 = require("uuid"); +const constants_1 = require("../lib/constants"); +const BadRequestError_1 = __importDefault(require("../lib/errors/BadRequestError")); +const ALLOWED_MIME_TYPES = ['image/png', 'image/jpeg', 'image/jpg']; +const FILE_SIZE_LIMIT = 5 * 1024 * 1024; +exports.upload = (0, multer_1.default)({ + storage: multer_1.default.diskStorage({ + destination(req, file, cb) { + cb(null, constants_1.PUBLIC_PATH); + }, + filename(req, file, cb) { + const ext = path_1.default.extname(file.originalname); + const filename = `${(0, uuid_1.v4)()}${ext}`; + cb(null, filename); + }, + }), + limits: { + fileSize: FILE_SIZE_LIMIT, + }, + fileFilter: function (req, file, cb) { + if (!ALLOWED_MIME_TYPES.includes(file.mimetype)) { + const err = new BadRequestError_1.default('Only png, jpeg, and jpg are allowed'); + return cb(err); + } + cb(null, true); + }, +}); +async function uploadImage(req, res) { + const host = req.get('host'); + const filePath = path_1.default.join(host, constants_1.STATIC_PATH, req.file.filename); + const url = `http://${filePath}`; + return res.send({ url }); +} +//# sourceMappingURL=imagesController.js.map \ No newline at end of file diff --git a/dist/controllers/imagesController.js.map b/dist/controllers/imagesController.js.map new file mode 100644 index 00000000..302381e0 --- /dev/null +++ b/dist/controllers/imagesController.js.map @@ -0,0 +1 @@ +{"version":3,"file":"imagesController.js","sourceRoot":"","sources":["../../src/controllers/imagesController.ts"],"names":[],"mappings":";;;;;;AAmCA,kCAKC;AAxCD,oDAA4B;AAC5B,gDAAwB;AACxB,+BAAoC;AACpC,gDAA4D;AAC5D,oFAA4D;AAE5D,MAAM,kBAAkB,GAAG,CAAC,WAAW,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;AACpE,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3B,QAAA,MAAM,GAAG,IAAA,gBAAM,EAAC;IAC3B,OAAO,EAAE,gBAAM,CAAC,WAAW,CAAC;QAC1B,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YACvB,EAAE,CAAC,IAAI,EAAE,uBAAW,CAAC,CAAC;QACxB,CAAC;QACD,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YACpB,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC5C,MAAM,QAAQ,GAAG,GAAG,IAAA,SAAM,GAAE,GAAG,GAAG,EAAE,CAAC;YACrC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACrB,CAAC;KACF,CAAC;IAEF,MAAM,EAAE;QACN,QAAQ,EAAE,eAAe;KAC1B;IAED,UAAU,EAAE,UAAU,GAAG,EAAE,IAAI,EAAE,EAAE;QACjC,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChD,MAAM,GAAG,GAAG,IAAI,yBAAe,CAAC,qCAAqC,CAAC,CAAC;YACvE,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC;QAED,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACjB,CAAC;CACF,CAAC,CAAC;AAEI,KAAK,UAAU,WAAW,CAAC,GAAY,EAAE,GAAa;IAC3D,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,uBAAW,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjE,MAAM,GAAG,GAAG,UAAU,QAAQ,EAAE,CAAC;IACjC,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;AAC3B,CAAC"} \ No newline at end of file diff --git a/dist/controllers/productsController.d.ts b/dist/controllers/productsController.d.ts new file mode 100644 index 00000000..05d8e6c6 --- /dev/null +++ b/dist/controllers/productsController.d.ts @@ -0,0 +1,11 @@ +import { Request, Response } from 'express'; +export declare function createProduct(req: Request, res: Response): Promise; +export declare function getProduct(req: Request, res: Response): Promise>>; +export declare function updateProduct(req: Request, res: Response): Promise>>; +export declare function deleteProduct(req: Request, res: Response): Promise>>; +export declare function getProductList(req: Request, res: Response): Promise>>; +export declare function createComment(req: Request, res: Response): Promise>>; +export declare function getCommentList(req: Request, res: Response): Promise>>; +export declare function createFavorite(req: Request, res: Response): Promise>>; +export declare function deleteFavorite(req: Request, res: Response): Promise>>; +//# sourceMappingURL=productsController.d.ts.map \ No newline at end of file diff --git a/dist/controllers/productsController.d.ts.map b/dist/controllers/productsController.d.ts.map new file mode 100644 index 00000000..a4bcfb3a --- /dev/null +++ b/dist/controllers/productsController.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"productsController.d.ts","sourceRoot":"","sources":["../../src/controllers/productsController.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAgB,MAAM,SAAS,CAAC;AAG1D,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAe9D;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAqB3D;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CA4B9D;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAkB9D;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAiC/D;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAkB9D;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAuB/D;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAqB/D;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAgB/D"} \ No newline at end of file diff --git a/dist/controllers/productsController.js b/dist/controllers/productsController.js new file mode 100644 index 00000000..c4dd9d92 --- /dev/null +++ b/dist/controllers/productsController.js @@ -0,0 +1,194 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createProduct = createProduct; +exports.getProduct = getProduct; +exports.updateProduct = updateProduct; +exports.deleteProduct = deleteProduct; +exports.getProductList = getProductList; +exports.createComment = createComment; +exports.getCommentList = getCommentList; +exports.createFavorite = createFavorite; +exports.deleteFavorite = deleteFavorite; +const superstruct_1 = require("superstruct"); +const prismaClient_1 = require("../lib/prismaClient"); +const NotFoundError_1 = __importDefault(require("../lib/errors/NotFoundError")); +const commonStructs_1 = require("../structs/commonStructs"); +const productsStruct_1 = require("../structs/productsStruct"); +const commentsStruct_js_1 = require("../structs/commentsStruct.js"); +const UnauthorizedError_1 = __importDefault(require("../lib/errors/UnauthorizedError")); +const ForbiddenError_1 = __importDefault(require("../lib/errors/ForbiddenError")); +const BadRequestError_1 = __importDefault(require("../lib/errors/BadRequestError")); +async function createProduct(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const data = (0, superstruct_1.create)(req.body, productsStruct_1.CreateProductBodyStruct); + const createdProduct = await prismaClient_1.prismaClient.product.create({ + data: { + ...data, + userId: req.user.id, + }, + }); + res.status(201).send(createdProduct); +} +async function getProduct(req, res) { + const { id } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const product = await prismaClient_1.prismaClient.product.findUnique({ + where: { id }, + include: { favorites: true }, + }); + if (!product) { + throw new NotFoundError_1.default('product', id); + } + const productWithFavorites = { + ...product, + favorites: undefined, + favoriteCount: product.favorites.length, + isFavorited: req.user + ? product.favorites.some((favorite) => favorite.userId === req.user?.id) + : undefined, + }; + return res.send(productWithFavorites); +} +async function updateProduct(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const { id } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const { name, description, price, tags, images } = (0, superstruct_1.create)(req.body, productsStruct_1.UpdateProductBodyStruct); + const existingProduct = await prismaClient_1.prismaClient.product.findUnique({ where: { id } }); + if (!existingProduct) { + throw new NotFoundError_1.default('product', id); + } + if (existingProduct.userId !== req.user.id) { + throw new ForbiddenError_1.default('Should be the owner of the product'); + } + const updatedProduct = await prismaClient_1.prismaClient.product.update({ + where: { id }, + data: { + ...(name !== undefined && { name }), + ...(description !== undefined && { description }), + ...(price !== undefined && { price }), + ...(tags !== undefined && { tags }), + ...(images !== undefined && { images }), + }, + }); + return res.send(updatedProduct); +} +async function deleteProduct(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const { id } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const existingProduct = await prismaClient_1.prismaClient.product.findUnique({ where: { id } }); + if (!existingProduct) { + throw new NotFoundError_1.default('product', id); + } + if (existingProduct.userId !== req.user.id) { + throw new ForbiddenError_1.default('Should be the owner of the product'); + } + await prismaClient_1.prismaClient.product.delete({ where: { id } }); + return res.status(204).send(); +} +async function getProductList(req, res) { + const { page, pageSize, orderBy, keyword } = (0, superstruct_1.create)(req.query, productsStruct_1.GetProductListParamsStruct); + const where = keyword + ? { + OR: [{ name: { contains: keyword } }, { description: { contains: keyword } }], + } + : {}; + const totalCount = await prismaClient_1.prismaClient.product.count({ where }); + const products = await prismaClient_1.prismaClient.product.findMany({ + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: orderBy === 'recent' ? { id: 'desc' } : { id: 'asc' }, + where, + include: { + favorites: true, + }, + }); + const productsWithFavorites = products.map((product) => ({ + ...product, + favorites: undefined, + favoriteCount: product.favorites.length, + isFavorited: req.user + ? product.favorites.some((favorite) => favorite.userId === req.user?.id) + : undefined, + })); + return res.send({ + list: productsWithFavorites, + totalCount, + }); +} +async function createComment(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const { id: productId } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const { content } = (0, superstruct_1.create)(req.body, commentsStruct_js_1.CreateCommentBodyStruct); + const existingProduct = await prismaClient_1.prismaClient.product.findUnique({ where: { id: productId } }); + if (!existingProduct) { + throw new NotFoundError_1.default('product', productId); + } + const createdComment = await prismaClient_1.prismaClient.comment.create({ + data: { productId, content, userId: req.user.id }, + }); + return res.status(201).send(createdComment); +} +async function getCommentList(req, res) { + const { id: productId } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const { cursor, limit } = (0, superstruct_1.create)(req.query, commentsStruct_js_1.GetCommentListParamsStruct); + const existingProduct = await prismaClient_1.prismaClient.product.findUnique({ where: { id: productId } }); + if (!existingProduct) { + throw new NotFoundError_1.default('product', productId); + } + const commentsWithCursorComment = await prismaClient_1.prismaClient.comment.findMany({ + where: { productId }, + take: limit + 1, + ...(cursor ? { cursor: { id: cursor }, skip: 1 } : {}), + orderBy: { id: 'asc' }, + }); + const comments = commentsWithCursorComment.slice(0, limit); + const cursorComment = commentsWithCursorComment[comments.length - 1]; + const nextCursor = cursorComment ? cursorComment.id : null; + return res.send({ + list: comments, + nextCursor, + }); +} +async function createFavorite(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const { id: productId } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const existingProduct = await prismaClient_1.prismaClient.product.findUnique({ where: { id: productId } }); + if (!existingProduct) { + throw new NotFoundError_1.default('product', productId); + } + const existingFavorite = await prismaClient_1.prismaClient.favorite.findFirst({ + where: { productId, userId: req.user.id }, + }); + if (existingFavorite) { + throw new BadRequestError_1.default('Already favorited'); + } + await prismaClient_1.prismaClient.favorite.create({ data: { productId, userId: req.user.id } }); + return res.status(201).send(); +} +async function deleteFavorite(req, res) { + if (!req.user) { + throw new UnauthorizedError_1.default('Unauthorized'); + } + const { id: productId } = (0, superstruct_1.create)(req.params, commonStructs_1.IdParamsStruct); + const existingFavorite = await prismaClient_1.prismaClient.favorite.findFirst({ + where: { productId, userId: req.user.id }, + }); + if (!existingFavorite) { + throw new BadRequestError_1.default('Not favorited'); + } + await prismaClient_1.prismaClient.favorite.delete({ where: { id: existingFavorite.id } }); + return res.status(204).send(); +} +//# sourceMappingURL=productsController.js.map \ No newline at end of file diff --git a/dist/controllers/productsController.js.map b/dist/controllers/productsController.js.map new file mode 100644 index 00000000..453513b9 --- /dev/null +++ b/dist/controllers/productsController.js.map @@ -0,0 +1 @@ +{"version":3,"file":"productsController.js","sourceRoot":"","sources":["../../src/controllers/productsController.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/controllers/usersController.d.ts b/dist/controllers/usersController.d.ts new file mode 100644 index 00000000..cb03a888 --- /dev/null +++ b/dist/controllers/usersController.d.ts @@ -0,0 +1,7 @@ +import { Request, Response } from 'express'; +export declare function getMe(req: Request, res: Response): Promise>>; +export declare function updateMe(req: Request, res: Response): Promise>>; +export declare function updateMyPassword(req: Request, res: Response): Promise>>; +export declare function getMyProductList(req: Request, res: Response): Promise>>; +export declare function getMyFavoriteList(req: Request, res: Response): Promise>>; +//# sourceMappingURL=usersController.d.ts.map \ No newline at end of file diff --git a/dist/controllers/usersController.d.ts.map b/dist/controllers/usersController.d.ts.map new file mode 100644 index 00000000..1d540ca3 --- /dev/null +++ b/dist/controllers/usersController.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"usersController.d.ts","sourceRoot":"","sources":["../../src/controllers/usersController.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAe,MAAM,SAAS,CAAA;AAExD,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAYtD;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAkBzD;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CA0BjE;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CA0CjE;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAkDlE"} \ No newline at end of file diff --git a/dist/controllers/usersController.js b/dist/controllers/usersController.js new file mode 100644 index 00000000..b3704f1d --- /dev/null +++ b/dist/controllers/usersController.js @@ -0,0 +1,151 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getMe = getMe; +exports.updateMe = updateMe; +exports.updateMyPassword = updateMyPassword; +exports.getMyProductList = getMyProductList; +exports.getMyFavoriteList = getMyFavoriteList; +const superstruct_1 = require("superstruct"); +const bcrypt_1 = __importDefault(require("bcrypt")); +const prismaClient_js_1 = require("../lib/prismaClient.js"); +const usersStructs_js_1 = require("../structs/usersStructs.js"); +const NotFoundError_js_1 = __importDefault(require("../lib/errors/NotFoundError.js")); +const UnauthorizedError_js_1 = __importDefault(require("../lib/errors/UnauthorizedError.js")); +async function getMe(req, res) { + if (!req.user) { + throw new UnauthorizedError_js_1.default('Unauthorized'); + } + const user = await prismaClient_js_1.prismaClient.user.findUnique({ where: { id: req.user.id } }); + if (!user) { + throw new NotFoundError_js_1.default('user', req.user.id); + } + const { password: _, ...userWithoutPassword } = user; + return res.send(userWithoutPassword); +} +async function updateMe(req, res) { + if (!req.user) { + throw new UnauthorizedError_js_1.default('Unauthorized'); + } + const data = (0, superstruct_1.create)(req.body, usersStructs_js_1.UpdateMeBodyStruct); + const updatedUser = await prismaClient_js_1.prismaClient.user.update({ + where: { id: req.user.id }, + data: { + ...(data.email !== undefined && { email: data.email }), + ...(data.nickname !== undefined && { nickname: data.nickname }), + ...(data.image !== undefined && { image: data.image }), + }, + }); + const { password: _, ...userWithoutPassword } = updatedUser; + return res.status(200).send(userWithoutPassword); +} +async function updateMyPassword(req, res) { + if (!req.user) { + throw new UnauthorizedError_js_1.default('Unauthorized'); + } + const { password, newPassword } = (0, superstruct_1.create)(req.body, usersStructs_js_1.UpdatePasswordBodyStruct); + const user = await prismaClient_js_1.prismaClient.user.findUnique({ where: { id: req.user.id } }); + if (!user) { + throw new NotFoundError_js_1.default('user', req.user.id); + } + const isPasswordValid = await bcrypt_1.default.compare(password, user.password); + if (!isPasswordValid) { + throw new UnauthorizedError_js_1.default('Invalid credentials'); + } + const salt = await bcrypt_1.default.genSalt(10); + const hashedPassword = await bcrypt_1.default.hash(newPassword, salt); + await prismaClient_js_1.prismaClient.user.update({ + where: { id: req.user.id }, + data: { password: hashedPassword }, + }); + return res.status(200).send(); +} +async function getMyProductList(req, res) { + if (!req.user) { + throw new UnauthorizedError_js_1.default('Unauthorized'); + } + const { page, pageSize, orderBy, keyword } = (0, superstruct_1.create)(req.query, usersStructs_js_1.GetMyProductListParamsStruct); + const where = keyword + ? { + OR: [{ name: { contains: keyword } }, { description: { contains: keyword } }], + } + : {}; + const totalCount = await prismaClient_js_1.prismaClient.product.count({ + where: { + ...where, + userId: req.user.id, + }, + }); + const products = await prismaClient_js_1.prismaClient.product.findMany({ + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: orderBy === 'recent' ? { id: 'desc' } : { id: 'asc' }, + where: { + ...where, + userId: req.user.id, + }, + include: { + favorites: true, + }, + }); + const productsWithFavorites = products.map((product) => ({ + ...product, + favorites: undefined, + favoriteCount: product.favorites.length, + isFavorited: product.favorites.some((favorite) => favorite.userId === req.user.id), + })); + return res.send({ + list: productsWithFavorites, + totalCount, + }); +} +async function getMyFavoriteList(req, res) { + if (!req.user) { + throw new UnauthorizedError_js_1.default('Unauthorized'); + } + const { page, pageSize, orderBy, keyword } = (0, superstruct_1.create)(req.query, usersStructs_js_1.GetMyFavoriteListParamsStruct); + const where = keyword + ? { + OR: [{ name: { contains: keyword } }, { description: { contains: keyword } }], + } + : {}; + const totalCount = await prismaClient_js_1.prismaClient.product.count({ + where: { + ...where, + favorites: { + some: { + userId: req.user.id, + }, + }, + }, + }); + const products = await prismaClient_js_1.prismaClient.product.findMany({ + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: orderBy === 'recent' ? { id: 'desc' } : { id: 'asc' }, + where: { + ...where, + favorites: { + some: { + userId: req.user.id, + }, + }, + }, + include: { + favorites: true, + }, + }); + const productsWithFavorites = products.map((product) => ({ + ...product, + favorites: undefined, + favoriteCount: product.favorites.length, + isFavorited: true, + })); + return res.send({ + list: productsWithFavorites, + totalCount, + }); +} +//# sourceMappingURL=usersController.js.map \ No newline at end of file diff --git a/dist/controllers/usersController.js.map b/dist/controllers/usersController.js.map new file mode 100644 index 00000000..ad6bdfd1 --- /dev/null +++ b/dist/controllers/usersController.js.map @@ -0,0 +1 @@ +{"version":3,"file":"usersController.js","sourceRoot":"","sources":["../../src/controllers/usersController.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/lib/constants.d.ts b/dist/lib/constants.d.ts new file mode 100644 index 00000000..5bb3b202 --- /dev/null +++ b/dist/lib/constants.d.ts @@ -0,0 +1,10 @@ +export declare const ACCESS_TOKEN_COOKIE_NAME = "access-token"; +export declare const REFRESH_TOKEN_COOKIE_NAME = "refresh-token"; +export declare const DATABASE_URL: string | undefined; +export declare const JWT_ACCESS_TOKEN_SECRET: string | undefined; +export declare const JWT_REFRESH_TOKEN_SECRET: string | undefined; +export declare const NODE_ENV: string; +export declare const PORT: string | number; +export declare const PUBLIC_PATH = "./public"; +export declare const STATIC_PATH = "/public"; +//# sourceMappingURL=constants.d.ts.map \ No newline at end of file diff --git a/dist/lib/constants.d.ts.map b/dist/lib/constants.d.ts.map new file mode 100644 index 00000000..a63fc8bd --- /dev/null +++ b/dist/lib/constants.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AACvD,eAAO,MAAM,yBAAyB,kBAAkB,CAAC;AACzD,eAAO,MAAM,YAAY,oBAA2B,CAAC;AACrD,eAAO,MAAM,uBAAuB,oBAAsC,CAAC;AAC3E,eAAO,MAAM,wBAAwB,oBAAuC,CAAC;AAC7E,eAAO,MAAM,QAAQ,QAAwC,CAAC;AAC9D,eAAO,MAAM,IAAI,iBAA2B,CAAC;AAC7C,eAAO,MAAM,WAAW,aAAa,CAAC;AACtC,eAAO,MAAM,WAAW,YAAY,CAAC"} \ No newline at end of file diff --git a/dist/lib/constants.js b/dist/lib/constants.js new file mode 100644 index 00000000..bafda800 --- /dev/null +++ b/dist/lib/constants.js @@ -0,0 +1,18 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.STATIC_PATH = exports.PUBLIC_PATH = exports.PORT = exports.NODE_ENV = exports.JWT_REFRESH_TOKEN_SECRET = exports.JWT_ACCESS_TOKEN_SECRET = exports.DATABASE_URL = exports.REFRESH_TOKEN_COOKIE_NAME = exports.ACCESS_TOKEN_COOKIE_NAME = void 0; +const dotenv_1 = __importDefault(require("dotenv")); +dotenv_1.default.config(); +exports.ACCESS_TOKEN_COOKIE_NAME = 'access-token'; +exports.REFRESH_TOKEN_COOKIE_NAME = 'refresh-token'; +exports.DATABASE_URL = process.env.DATABASE_URL; +exports.JWT_ACCESS_TOKEN_SECRET = process.env.JWT_ACCESS_TOKEN_SECRET; +exports.JWT_REFRESH_TOKEN_SECRET = process.env.JWT_REFRESH_TOKEN_SECRET; +exports.NODE_ENV = process.env.NODE_ENV || 'development'; +exports.PORT = process.env.PORT || 3000; +exports.PUBLIC_PATH = './public'; +exports.STATIC_PATH = '/public'; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/dist/lib/constants.js.map b/dist/lib/constants.js.map new file mode 100644 index 00000000..01dbbda4 --- /dev/null +++ b/dist/lib/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAC5B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEH,QAAA,wBAAwB,GAAG,cAAc,CAAC;AAC1C,QAAA,yBAAyB,GAAG,eAAe,CAAC;AAC5C,QAAA,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AACxC,QAAA,uBAAuB,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;AAC9D,QAAA,wBAAwB,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;AAChE,QAAA,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAC;AACjD,QAAA,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC;AAChC,QAAA,WAAW,GAAG,UAAU,CAAC;AACzB,QAAA,WAAW,GAAG,SAAS,CAAC"} \ No newline at end of file diff --git a/dist/lib/errors/BadRequestError.d.ts b/dist/lib/errors/BadRequestError.d.ts new file mode 100644 index 00000000..d3f9ec84 --- /dev/null +++ b/dist/lib/errors/BadRequestError.d.ts @@ -0,0 +1,5 @@ +declare class BadRequestError extends Error { + constructor(message: string); +} +export default BadRequestError; +//# sourceMappingURL=BadRequestError.d.ts.map \ No newline at end of file diff --git a/dist/lib/errors/BadRequestError.d.ts.map b/dist/lib/errors/BadRequestError.d.ts.map new file mode 100644 index 00000000..2528cf21 --- /dev/null +++ b/dist/lib/errors/BadRequestError.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"BadRequestError.d.ts","sourceRoot":"","sources":["../../../src/lib/errors/BadRequestError.ts"],"names":[],"mappings":"AAAA,cAAM,eAAgB,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM;CAI5B;AAED,eAAe,eAAe,CAAC"} \ No newline at end of file diff --git a/dist/lib/errors/BadRequestError.js b/dist/lib/errors/BadRequestError.js new file mode 100644 index 00000000..72fb1765 --- /dev/null +++ b/dist/lib/errors/BadRequestError.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +class BadRequestError extends Error { + constructor(message) { + super(message); + this.name = 'BadRequestError'; + } +} +exports.default = BadRequestError; +//# sourceMappingURL=BadRequestError.js.map \ No newline at end of file diff --git a/dist/lib/errors/BadRequestError.js.map b/dist/lib/errors/BadRequestError.js.map new file mode 100644 index 00000000..ee732854 --- /dev/null +++ b/dist/lib/errors/BadRequestError.js.map @@ -0,0 +1 @@ +{"version":3,"file":"BadRequestError.js","sourceRoot":"","sources":["../../../src/lib/errors/BadRequestError.ts"],"names":[],"mappings":";;AAAA,MAAM,eAAgB,SAAQ,KAAK;IACjC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,kBAAe,eAAe,CAAC"} \ No newline at end of file diff --git a/dist/lib/errors/ForbiddenError.d.ts b/dist/lib/errors/ForbiddenError.d.ts new file mode 100644 index 00000000..3cdf8219 --- /dev/null +++ b/dist/lib/errors/ForbiddenError.d.ts @@ -0,0 +1,5 @@ +declare class ForbiddenError extends Error { + constructor(message: string); +} +export default ForbiddenError; +//# sourceMappingURL=ForbiddenError.d.ts.map \ No newline at end of file diff --git a/dist/lib/errors/ForbiddenError.d.ts.map b/dist/lib/errors/ForbiddenError.d.ts.map new file mode 100644 index 00000000..72743b13 --- /dev/null +++ b/dist/lib/errors/ForbiddenError.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ForbiddenError.d.ts","sourceRoot":"","sources":["../../../src/lib/errors/ForbiddenError.ts"],"names":[],"mappings":"AAAA,cAAM,cAAe,SAAQ,KAAK;gBACpB,OAAO,EAAE,MAAM;CAI5B;AAED,eAAe,cAAc,CAAC"} \ No newline at end of file diff --git a/dist/lib/errors/ForbiddenError.js b/dist/lib/errors/ForbiddenError.js new file mode 100644 index 00000000..80964ac5 --- /dev/null +++ b/dist/lib/errors/ForbiddenError.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +class ForbiddenError extends Error { + constructor(message) { + super(message); + this.name = 'ForbiddenError'; + } +} +exports.default = ForbiddenError; +//# sourceMappingURL=ForbiddenError.js.map \ No newline at end of file diff --git a/dist/lib/errors/ForbiddenError.js.map b/dist/lib/errors/ForbiddenError.js.map new file mode 100644 index 00000000..9e942e97 --- /dev/null +++ b/dist/lib/errors/ForbiddenError.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ForbiddenError.js","sourceRoot":"","sources":["../../../src/lib/errors/ForbiddenError.ts"],"names":[],"mappings":";;AAAA,MAAM,cAAe,SAAQ,KAAK;IAChC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,kBAAe,cAAc,CAAC"} \ No newline at end of file diff --git a/dist/lib/errors/NotFoundError.d.ts b/dist/lib/errors/NotFoundError.d.ts new file mode 100644 index 00000000..a54572c5 --- /dev/null +++ b/dist/lib/errors/NotFoundError.d.ts @@ -0,0 +1,5 @@ +declare class NotFoundError extends Error { + constructor(modelName: string, id: string | number); +} +export default NotFoundError; +//# sourceMappingURL=NotFoundError.d.ts.map \ No newline at end of file diff --git a/dist/lib/errors/NotFoundError.d.ts.map b/dist/lib/errors/NotFoundError.d.ts.map new file mode 100644 index 00000000..21b1afc6 --- /dev/null +++ b/dist/lib/errors/NotFoundError.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NotFoundError.d.ts","sourceRoot":"","sources":["../../../src/lib/errors/NotFoundError.ts"],"names":[],"mappings":"AAAA,cAAM,aAAc,SAAQ,KAAK;gBACnB,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM;CAInD;AAED,eAAe,aAAa,CAAC"} \ No newline at end of file diff --git a/dist/lib/errors/NotFoundError.js b/dist/lib/errors/NotFoundError.js new file mode 100644 index 00000000..5a8c47cb --- /dev/null +++ b/dist/lib/errors/NotFoundError.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +class NotFoundError extends Error { + constructor(modelName, id) { + super(`${modelName} with id ${id} not found`); + this.name = 'NotFoundError'; + } +} +exports.default = NotFoundError; +//# sourceMappingURL=NotFoundError.js.map \ No newline at end of file diff --git a/dist/lib/errors/NotFoundError.js.map b/dist/lib/errors/NotFoundError.js.map new file mode 100644 index 00000000..309c10b7 --- /dev/null +++ b/dist/lib/errors/NotFoundError.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NotFoundError.js","sourceRoot":"","sources":["../../../src/lib/errors/NotFoundError.ts"],"names":[],"mappings":";;AAAA,MAAM,aAAc,SAAQ,KAAK;IAC/B,YAAY,SAAiB,EAAE,EAAmB;QAChD,KAAK,CAAC,GAAG,SAAS,YAAY,EAAE,YAAY,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,kBAAe,aAAa,CAAC"} \ No newline at end of file diff --git a/dist/lib/errors/UnauthorizedError.d.ts b/dist/lib/errors/UnauthorizedError.d.ts new file mode 100644 index 00000000..3db6d0b9 --- /dev/null +++ b/dist/lib/errors/UnauthorizedError.d.ts @@ -0,0 +1,5 @@ +declare class UnauthorizedError extends Error { + constructor(message: string); +} +export default UnauthorizedError; +//# sourceMappingURL=UnauthorizedError.d.ts.map \ No newline at end of file diff --git a/dist/lib/errors/UnauthorizedError.d.ts.map b/dist/lib/errors/UnauthorizedError.d.ts.map new file mode 100644 index 00000000..4003cefe --- /dev/null +++ b/dist/lib/errors/UnauthorizedError.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"UnauthorizedError.d.ts","sourceRoot":"","sources":["../../../src/lib/errors/UnauthorizedError.ts"],"names":[],"mappings":"AAAA,cAAM,iBAAkB,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B;AAED,eAAe,iBAAiB,CAAC"} \ No newline at end of file diff --git a/dist/lib/errors/UnauthorizedError.js b/dist/lib/errors/UnauthorizedError.js new file mode 100644 index 00000000..74f01eaf --- /dev/null +++ b/dist/lib/errors/UnauthorizedError.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +class UnauthorizedError extends Error { + constructor(message) { + super(message); + this.name = 'UnauthorizedError'; + } +} +exports.default = UnauthorizedError; +//# sourceMappingURL=UnauthorizedError.js.map \ No newline at end of file diff --git a/dist/lib/errors/UnauthorizedError.js.map b/dist/lib/errors/UnauthorizedError.js.map new file mode 100644 index 00000000..42a2b829 --- /dev/null +++ b/dist/lib/errors/UnauthorizedError.js.map @@ -0,0 +1 @@ +{"version":3,"file":"UnauthorizedError.js","sourceRoot":"","sources":["../../../src/lib/errors/UnauthorizedError.ts"],"names":[],"mappings":";;AAAA,MAAM,iBAAkB,SAAQ,KAAK;IACnC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,kBAAe,iBAAiB,CAAC"} \ No newline at end of file diff --git a/dist/lib/prismaClient.d.ts b/dist/lib/prismaClient.d.ts new file mode 100644 index 00000000..21b458b3 --- /dev/null +++ b/dist/lib/prismaClient.d.ts @@ -0,0 +1,3 @@ +import { PrismaClient } from '@prisma/client'; +export declare const prismaClient: PrismaClient; +//# sourceMappingURL=prismaClient.d.ts.map \ No newline at end of file diff --git a/dist/lib/prismaClient.d.ts.map b/dist/lib/prismaClient.d.ts.map new file mode 100644 index 00000000..edff73d9 --- /dev/null +++ b/dist/lib/prismaClient.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"prismaClient.d.ts","sourceRoot":"","sources":["../../src/lib/prismaClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,eAAO,MAAM,YAAY,gIAAqB,CAAC"} \ No newline at end of file diff --git a/dist/lib/prismaClient.js b/dist/lib/prismaClient.js new file mode 100644 index 00000000..08774b49 --- /dev/null +++ b/dist/lib/prismaClient.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.prismaClient = void 0; +const client_1 = require("@prisma/client"); +exports.prismaClient = new client_1.PrismaClient(); +//# sourceMappingURL=prismaClient.js.map \ No newline at end of file diff --git a/dist/lib/prismaClient.js.map b/dist/lib/prismaClient.js.map new file mode 100644 index 00000000..88b1d76d --- /dev/null +++ b/dist/lib/prismaClient.js.map @@ -0,0 +1 @@ +{"version":3,"file":"prismaClient.js","sourceRoot":"","sources":["../../src/lib/prismaClient.ts"],"names":[],"mappings":";;;AAAA,2CAA8C;AAEjC,QAAA,YAAY,GAAG,IAAI,qBAAY,EAAE,CAAC"} \ No newline at end of file diff --git a/dist/lib/token.d.ts b/dist/lib/token.d.ts new file mode 100644 index 00000000..b979c35b --- /dev/null +++ b/dist/lib/token.d.ts @@ -0,0 +1,12 @@ +import 'dotenv/config'; +export declare function generateTokens(userId: string): { + accessToken: string; + refreshToken: string; +}; +export declare function verifyAccessToken(token: string): { + userId: string; +}; +export declare function verifyRefreshToken(token: string): { + userId: string; +}; +//# sourceMappingURL=token.d.ts.map \ No newline at end of file diff --git a/dist/lib/token.d.ts.map b/dist/lib/token.d.ts.map new file mode 100644 index 00000000..72211344 --- /dev/null +++ b/dist/lib/token.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/lib/token.ts"],"names":[],"mappings":"AACA,OAAO,eAAe,CAAA;AAStB,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM;;;EAQ5C;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM;;EAG9C;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM;;EAG/C"} \ No newline at end of file diff --git a/dist/lib/token.js b/dist/lib/token.js new file mode 100644 index 00000000..c82b1798 --- /dev/null +++ b/dist/lib/token.js @@ -0,0 +1,30 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateTokens = generateTokens; +exports.verifyAccessToken = verifyAccessToken; +exports.verifyRefreshToken = verifyRefreshToken; +const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); +require("dotenv/config"); +const JWT_ACCESS_TOKEN_SECRET = process.env.JWT_ACCESS_TOKEN_SECRET; +const JWT_REFRESH_TOKEN_SECRET = process.env.JWT_REFRESH_TOKEN_SECRET; +function generateTokens(userId) { + const accessToken = jsonwebtoken_1.default.sign({ id: userId }, JWT_ACCESS_TOKEN_SECRET, { + expiresIn: '1h', + }); + const refreshToken = jsonwebtoken_1.default.sign({ id: userId }, JWT_REFRESH_TOKEN_SECRET, { + expiresIn: '7d', + }); + return { accessToken, refreshToken }; +} +function verifyAccessToken(token) { + const decoded = jsonwebtoken_1.default.verify(token, JWT_ACCESS_TOKEN_SECRET); + return { userId: decoded.id }; +} +function verifyRefreshToken(token) { + const decoded = jsonwebtoken_1.default.verify(token, JWT_REFRESH_TOKEN_SECRET); + return { userId: decoded.id }; +} +//# sourceMappingURL=token.js.map \ No newline at end of file diff --git a/dist/lib/token.js.map b/dist/lib/token.js.map new file mode 100644 index 00000000..913923c3 --- /dev/null +++ b/dist/lib/token.js.map @@ -0,0 +1 @@ +{"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/lib/token.ts"],"names":[],"mappings":";;;;;AAUA,wCAQC;AAED,8CAGC;AAED,gDAGC;AA5BD,gEAA+C;AAC/C,yBAAsB;AAEtB,MAAM,uBAAuB,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAiC,CAAC;AAC9E,MAAM,wBAAwB,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAkC,CAAC;AAMhF,SAAgB,cAAc,CAAC,MAAc;IAC3C,MAAM,WAAW,GAAG,sBAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,uBAAuB,EAAE;QACpE,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,sBAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,wBAAwB,EAAE;QACtE,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;IACH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;AACvC,CAAC;AAED,SAAgB,iBAAiB,CAAC,KAAa;IAC7C,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,uBAAuB,CAAoB,CAAC;IAC9E,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC;AAChC,CAAC;AAED,SAAgB,kBAAkB,CAAC,KAAa;IAC9C,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,wBAAwB,CAAqB,CAAC;IAChF,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC;AAChC,CAAC"} \ No newline at end of file diff --git a/dist/lib/withAsync.d.ts b/dist/lib/withAsync.d.ts new file mode 100644 index 00000000..9f8dc681 --- /dev/null +++ b/dist/lib/withAsync.d.ts @@ -0,0 +1,5 @@ +import { Request, Response, NextFunction } from "express"; +type asyncHandler = (req: Request, res: Response) => Promise; +export declare function withAsync(handler: asyncHandler): (req: Request, res: Response, next: NextFunction) => Promise; +export {}; +//# sourceMappingURL=withAsync.d.ts.map \ No newline at end of file diff --git a/dist/lib/withAsync.d.ts.map b/dist/lib/withAsync.d.ts.map new file mode 100644 index 00000000..9028a029 --- /dev/null +++ b/dist/lib/withAsync.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"withAsync.d.ts","sourceRoot":"","sources":["../../src/lib/withAsync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE1D,KAAK,YAAY,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAI,OAAO,CAAC,IAAI,CAAC,CAAC;AAElE,wBAAgB,SAAS,CAAC,OAAO,EAAE,YAAY,IACtB,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,mBAOvE"} \ No newline at end of file diff --git a/dist/lib/withAsync.js b/dist/lib/withAsync.js new file mode 100644 index 00000000..50c543f9 --- /dev/null +++ b/dist/lib/withAsync.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.withAsync = withAsync; +function withAsync(handler) { + return async function (req, res, next) { + try { + await handler(req, res); + } + catch (e) { + next(e); + } + }; +} +//# sourceMappingURL=withAsync.js.map \ No newline at end of file diff --git a/dist/lib/withAsync.js.map b/dist/lib/withAsync.js.map new file mode 100644 index 00000000..d83581ae --- /dev/null +++ b/dist/lib/withAsync.js.map @@ -0,0 +1 @@ +{"version":3,"file":"withAsync.js","sourceRoot":"","sources":["../../src/lib/withAsync.ts"],"names":[],"mappings":";;AAIA,8BAQC;AARD,SAAgB,SAAS,CAAC,OAAqB;IAC7C,OAAO,KAAK,WAAW,GAAY,EAAE,GAAa,EAAE,IAAkB;QACpE,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,CAAC,CAAC,CAAC;QACV,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/dist/main.d.ts b/dist/main.d.ts new file mode 100644 index 00000000..371115b3 --- /dev/null +++ b/dist/main.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=main.d.ts.map \ No newline at end of file diff --git a/dist/main.d.ts.map b/dist/main.d.ts.map new file mode 100644 index 00000000..28b87d89 --- /dev/null +++ b/dist/main.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/main.js b/dist/main.js new file mode 100644 index 00000000..e9fc3f7e --- /dev/null +++ b/dist/main.js @@ -0,0 +1,34 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const cors_1 = __importDefault(require("cors")); +const path_1 = __importDefault(require("path")); +const cookie_parser_1 = __importDefault(require("cookie-parser")); +const constants_1 = require("./lib/constants"); +const articlesRouter_1 = __importDefault(require("./routers/articlesRouter")); +const productsRouter_1 = __importDefault(require("./routers/productsRouter")); +const commentsRouter_1 = __importDefault(require("./routers/commentsRouter")); +const imagesRouter_1 = __importDefault(require("./routers/imagesRouter")); +const authRouter_1 = __importDefault(require("./routers/authRouter")); +const usersRouter_1 = __importDefault(require("./routers/usersRouter")); +const errorController_1 = require("./controllers/errorController"); +const app = (0, express_1.default)(); +app.use((0, cors_1.default)()); +app.use(express_1.default.json()); +app.use((0, cookie_parser_1.default)()); +app.use(constants_1.STATIC_PATH, express_1.default.static(path_1.default.resolve(process.cwd(), constants_1.PUBLIC_PATH))); +app.use('/articles', articlesRouter_1.default); +app.use('/products', productsRouter_1.default); +app.use('/comments', commentsRouter_1.default); +app.use('/images', imagesRouter_1.default); +app.use('/auth', authRouter_1.default); +app.use('/users', usersRouter_1.default); +app.use(errorController_1.defaultNotFoundHandler); +app.use(errorController_1.globalErrorHandler); +app.listen(constants_1.PORT, () => { + console.log(`Server started on port ${constants_1.PORT}`); +}); +//# sourceMappingURL=main.js.map \ No newline at end of file diff --git a/dist/main.js.map b/dist/main.js.map new file mode 100644 index 00000000..cf9f6648 --- /dev/null +++ b/dist/main.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAC9B,gDAAwB;AACxB,gDAAwB;AACxB,kEAAyC;AACzC,+CAAiE;AACjE,8EAAsD;AACtD,8EAAsD;AACtD,8EAAsD;AACtD,0EAAkD;AAClD,sEAA8C;AAC9C,wEAAgD;AAChD,mEAA2F;AAE3F,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;AAEtB,GAAG,CAAC,GAAG,CAAC,IAAA,cAAI,GAAE,CAAC,CAAC;AAChB,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AACxB,GAAG,CAAC,GAAG,CAAC,IAAA,uBAAY,GAAE,CAAC,CAAC;AACxB,GAAG,CAAC,GAAG,CAAC,uBAAW,EAAE,iBAAO,CAAC,MAAM,CAAC,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,uBAAW,CAAC,CAAC,CAAC,CAAC;AAE/E,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,wBAAc,CAAC,CAAC;AACrC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,wBAAc,CAAC,CAAC;AACrC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,wBAAc,CAAC,CAAC;AACrC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,sBAAY,CAAC,CAAC;AACjC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,oBAAU,CAAC,CAAC;AAC7B,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,qBAAW,CAAC,CAAC;AAE/B,GAAG,CAAC,GAAG,CAAC,wCAAsB,CAAC,CAAC;AAChC,GAAG,CAAC,GAAG,CAAC,oCAAkB,CAAC,CAAC;AAE5B,GAAG,CAAC,MAAM,CAAC,gBAAI,EAAE,GAAG,EAAE;IACpB,OAAO,CAAC,GAAG,CAAC,0BAA0B,gBAAI,EAAE,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/middlewares/authenticate.d.ts b/dist/middlewares/authenticate.d.ts new file mode 100644 index 00000000..0636dcc8 --- /dev/null +++ b/dist/middlewares/authenticate.d.ts @@ -0,0 +1,6 @@ +import { Request, Response, NextFunction } from 'express'; +declare function authenticate(options?: { + optional: boolean; +}): (req: Request, res: Response, next: NextFunction) => Promise>>; +export default authenticate; +//# sourceMappingURL=authenticate.d.ts.map \ No newline at end of file diff --git a/dist/middlewares/authenticate.d.ts.map b/dist/middlewares/authenticate.d.ts.map new file mode 100644 index 00000000..3b0e7c76 --- /dev/null +++ b/dist/middlewares/authenticate.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"authenticate.d.ts","sourceRoot":"","sources":["../../src/middlewares/authenticate.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE1D,iBAAS,YAAY,CAAC,OAAO;;CAAsB,IACnC,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,wDAqB9D;AAED,eAAe,YAAY,CAAC"} \ No newline at end of file diff --git a/dist/middlewares/authenticate.js b/dist/middlewares/authenticate.js new file mode 100644 index 00000000..48f87b86 --- /dev/null +++ b/dist/middlewares/authenticate.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const prismaClient_1 = require("../lib/prismaClient"); +const token_1 = require("../lib/token"); +const constants_1 = require("../lib/constants"); +function authenticate(options = { optional: false }) { + return async (req, res, next) => { + const accessToken = req.cookies[constants_1.ACCESS_TOKEN_COOKIE_NAME]; + if (!accessToken) { + if (options.optional) { + return next(); + } + return res.status(401).json({ message: 'Unauthorized' }); + } + try { + const { userId } = (0, token_1.verifyAccessToken)(accessToken); + const user = await prismaClient_1.prismaClient.user.findUnique({ where: { id: userId } }); + req.user = user; + } + catch (error) { + if (options.optional) { + return next(); + } + return res.status(401).json({ message: 'Unauthorized' }); + } + next(); + }; +} +exports.default = authenticate; +//# sourceMappingURL=authenticate.js.map \ No newline at end of file diff --git a/dist/middlewares/authenticate.js.map b/dist/middlewares/authenticate.js.map new file mode 100644 index 00000000..fd9af3c3 --- /dev/null +++ b/dist/middlewares/authenticate.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../../src/middlewares/authenticate.ts"],"names":[],"mappings":";;AAAA,sDAAmD;AACnD,wCAAiD;AACjD,gDAA4D;AAG5D,SAAS,YAAY,CAAC,OAAO,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE;IACjD,OAAO,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QAC/D,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,oCAAwB,CAAC,CAAC;QAC1D,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,OAAO,IAAI,EAAE,CAAC;YAChB,CAAC;YACD,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;QAC3D,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,yBAAiB,EAAC,WAAW,CAAC,CAAC;YAClD,MAAM,IAAI,GAAG,MAAM,2BAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YAC3E,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,OAAO,IAAI,EAAE,CAAC;YAChB,CAAC;YACD,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAED,kBAAe,YAAY,CAAC"} \ No newline at end of file diff --git a/dist/routers/articlesRouter.d.ts b/dist/routers/articlesRouter.d.ts new file mode 100644 index 00000000..ee33925c --- /dev/null +++ b/dist/routers/articlesRouter.d.ts @@ -0,0 +1,3 @@ +declare const articlesRouter: import("express-serve-static-core").Router; +export default articlesRouter; +//# sourceMappingURL=articlesRouter.d.ts.map \ No newline at end of file diff --git a/dist/routers/articlesRouter.d.ts.map b/dist/routers/articlesRouter.d.ts.map new file mode 100644 index 00000000..dbe62a31 --- /dev/null +++ b/dist/routers/articlesRouter.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"articlesRouter.d.ts","sourceRoot":"","sources":["../../src/routers/articlesRouter.ts"],"names":[],"mappings":"AAeA,QAAA,MAAM,cAAc,4CAAmB,CAAC;AAYxC,eAAe,cAAc,CAAC"} \ No newline at end of file diff --git a/dist/routers/articlesRouter.js b/dist/routers/articlesRouter.js new file mode 100644 index 00000000..7a4bf1aa --- /dev/null +++ b/dist/routers/articlesRouter.js @@ -0,0 +1,21 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const withAsync_1 = require("../lib/withAsync"); +const articlesController_1 = require("../controllers/articlesController"); +const authenticate_1 = __importDefault(require("../middlewares/authenticate")); +const articlesRouter = express_1.default.Router(); +articlesRouter.post('/', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(articlesController_1.createArticle)); +articlesRouter.get('/', (0, authenticate_1.default)({ optional: true }), (0, withAsync_1.withAsync)(articlesController_1.getArticleList)); +articlesRouter.get('/:id', (0, authenticate_1.default)({ optional: true }), (0, withAsync_1.withAsync)(articlesController_1.getArticle)); +articlesRouter.patch('/:id', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(articlesController_1.updateArticle)); +articlesRouter.delete('/:id', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(articlesController_1.deleteArticle)); +articlesRouter.post('/:id/comments', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(articlesController_1.createComment)); +articlesRouter.get('/:id/comments', (0, withAsync_1.withAsync)(articlesController_1.getCommentList)); +articlesRouter.post('/:id/likes', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(articlesController_1.createLike)); +articlesRouter.delete('/:id/likes', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(articlesController_1.deleteLike)); +exports.default = articlesRouter; +//# sourceMappingURL=articlesRouter.js.map \ No newline at end of file diff --git a/dist/routers/articlesRouter.js.map b/dist/routers/articlesRouter.js.map new file mode 100644 index 00000000..a916a100 --- /dev/null +++ b/dist/routers/articlesRouter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"articlesRouter.js","sourceRoot":"","sources":["../../src/routers/articlesRouter.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAC9B,gDAA6C;AAC7C,0EAU2C;AAC3C,+EAAuD;AAEvD,MAAM,cAAc,GAAG,iBAAO,CAAC,MAAM,EAAE,CAAC;AAExC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,kCAAa,CAAC,CAAC,CAAC;AACnE,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,IAAA,sBAAY,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,IAAA,qBAAS,EAAC,mCAAc,CAAC,CAAC,CAAC;AACrF,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,IAAA,sBAAY,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,IAAA,qBAAS,EAAC,+BAAU,CAAC,CAAC,CAAC;AACpF,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,kCAAa,CAAC,CAAC,CAAC;AACvE,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,kCAAa,CAAC,CAAC,CAAC;AACxE,cAAc,CAAC,IAAI,CAAC,eAAe,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,kCAAa,CAAC,CAAC,CAAC;AAC/E,cAAc,CAAC,GAAG,CAAC,eAAe,EAAE,IAAA,qBAAS,EAAC,mCAAc,CAAC,CAAC,CAAC;AAC/D,cAAc,CAAC,IAAI,CAAC,YAAY,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,+BAAU,CAAC,CAAC,CAAC;AACzE,cAAc,CAAC,MAAM,CAAC,YAAY,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,+BAAU,CAAC,CAAC,CAAC;AAE3E,kBAAe,cAAc,CAAC"} \ No newline at end of file diff --git a/dist/routers/authRouter.d.ts b/dist/routers/authRouter.d.ts new file mode 100644 index 00000000..3a228145 --- /dev/null +++ b/dist/routers/authRouter.d.ts @@ -0,0 +1,3 @@ +declare const authRouter: import("express-serve-static-core").Router; +export default authRouter; +//# sourceMappingURL=authRouter.d.ts.map \ No newline at end of file diff --git a/dist/routers/authRouter.d.ts.map b/dist/routers/authRouter.d.ts.map new file mode 100644 index 00000000..3d90c35a --- /dev/null +++ b/dist/routers/authRouter.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"authRouter.d.ts","sourceRoot":"","sources":["../../src/routers/authRouter.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,UAAU,4CAAmB,CAAC;AAOpC,eAAe,UAAU,CAAC"} \ No newline at end of file diff --git a/dist/routers/authRouter.js b/dist/routers/authRouter.js new file mode 100644 index 00000000..e05d3de9 --- /dev/null +++ b/dist/routers/authRouter.js @@ -0,0 +1,15 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const authController_1 = require("../controllers/authController"); +const withAsync_1 = require("../lib/withAsync"); +const authRouter = express_1.default.Router(); +authRouter.post('/register', (0, withAsync_1.withAsync)(authController_1.register)); +authRouter.post('/login', (0, withAsync_1.withAsync)(authController_1.login)); +authRouter.post('/logout', (0, withAsync_1.withAsync)(authController_1.logout)); +authRouter.post('/refresh', (0, withAsync_1.withAsync)(authController_1.refreshToken)); +exports.default = authRouter; +//# sourceMappingURL=authRouter.js.map \ No newline at end of file diff --git a/dist/routers/authRouter.js.map b/dist/routers/authRouter.js.map new file mode 100644 index 00000000..ecb40613 --- /dev/null +++ b/dist/routers/authRouter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authRouter.js","sourceRoot":"","sources":["../../src/routers/authRouter.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAC9B,kEAAsF;AACtF,gDAA6C;AAE7C,MAAM,UAAU,GAAG,iBAAO,CAAC,MAAM,EAAE,CAAC;AAEpC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,IAAA,qBAAS,EAAC,yBAAQ,CAAC,CAAC,CAAC;AAClD,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAA,qBAAS,EAAC,sBAAK,CAAC,CAAC,CAAC;AAC5C,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,IAAA,qBAAS,EAAC,uBAAM,CAAC,CAAC,CAAC;AAC9C,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,IAAA,qBAAS,EAAC,6BAAY,CAAC,CAAC,CAAC;AAErD,kBAAe,UAAU,CAAC"} \ No newline at end of file diff --git a/dist/routers/commentsRouter.d.ts b/dist/routers/commentsRouter.d.ts new file mode 100644 index 00000000..91f59cd9 --- /dev/null +++ b/dist/routers/commentsRouter.d.ts @@ -0,0 +1,3 @@ +declare const commentsRouter: import("express-serve-static-core").Router; +export default commentsRouter; +//# sourceMappingURL=commentsRouter.d.ts.map \ No newline at end of file diff --git a/dist/routers/commentsRouter.d.ts.map b/dist/routers/commentsRouter.d.ts.map new file mode 100644 index 00000000..43e026ec --- /dev/null +++ b/dist/routers/commentsRouter.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"commentsRouter.d.ts","sourceRoot":"","sources":["../../src/routers/commentsRouter.ts"],"names":[],"mappings":"AAKA,QAAA,MAAM,cAAc,4CAAmB,CAAC;AAKxC,eAAe,cAAc,CAAC"} \ No newline at end of file diff --git a/dist/routers/commentsRouter.js b/dist/routers/commentsRouter.js new file mode 100644 index 00000000..54f223cd --- /dev/null +++ b/dist/routers/commentsRouter.js @@ -0,0 +1,14 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const withAsync_1 = require("../lib/withAsync"); +const commentsController_1 = require("../controllers/commentsController"); +const authenticate_1 = __importDefault(require("../middlewares/authenticate")); +const commentsRouter = express_1.default.Router(); +commentsRouter.patch('/:id', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(commentsController_1.updateComment)); +commentsRouter.delete('/:id', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(commentsController_1.deleteComment)); +exports.default = commentsRouter; +//# sourceMappingURL=commentsRouter.js.map \ No newline at end of file diff --git a/dist/routers/commentsRouter.js.map b/dist/routers/commentsRouter.js.map new file mode 100644 index 00000000..6162f7b1 --- /dev/null +++ b/dist/routers/commentsRouter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"commentsRouter.js","sourceRoot":"","sources":["../../src/routers/commentsRouter.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAC9B,gDAA6C;AAC7C,0EAAiF;AACjF,+EAAuD;AAEvD,MAAM,cAAc,GAAG,iBAAO,CAAC,MAAM,EAAE,CAAC;AAExC,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,kCAAa,CAAC,CAAC,CAAC;AACvE,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,kCAAa,CAAC,CAAC,CAAC;AAExE,kBAAe,cAAc,CAAC"} \ No newline at end of file diff --git a/dist/routers/imagesRouter.d.ts b/dist/routers/imagesRouter.d.ts new file mode 100644 index 00000000..86d6f9ee --- /dev/null +++ b/dist/routers/imagesRouter.d.ts @@ -0,0 +1,3 @@ +declare const imagesRouter: import("express-serve-static-core").Router; +export default imagesRouter; +//# sourceMappingURL=imagesRouter.d.ts.map \ No newline at end of file diff --git a/dist/routers/imagesRouter.d.ts.map b/dist/routers/imagesRouter.d.ts.map new file mode 100644 index 00000000..3a3191ae --- /dev/null +++ b/dist/routers/imagesRouter.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"imagesRouter.d.ts","sourceRoot":"","sources":["../../src/routers/imagesRouter.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,YAAY,4CAAmB,CAAC;AAItC,eAAe,YAAY,CAAC"} \ No newline at end of file diff --git a/dist/routers/imagesRouter.js b/dist/routers/imagesRouter.js new file mode 100644 index 00000000..e2d470a1 --- /dev/null +++ b/dist/routers/imagesRouter.js @@ -0,0 +1,12 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const withAsync_js_1 = require("../lib/withAsync.js"); +const imagesController_js_1 = require("../controllers/imagesController.js"); +const imagesRouter = express_1.default.Router(); +imagesRouter.post('/upload', imagesController_js_1.upload.single('image'), (0, withAsync_js_1.withAsync)(imagesController_js_1.uploadImage)); +exports.default = imagesRouter; +//# sourceMappingURL=imagesRouter.js.map \ No newline at end of file diff --git a/dist/routers/imagesRouter.js.map b/dist/routers/imagesRouter.js.map new file mode 100644 index 00000000..f258a892 --- /dev/null +++ b/dist/routers/imagesRouter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"imagesRouter.js","sourceRoot":"","sources":["../../src/routers/imagesRouter.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAC9B,sDAAgD;AAChD,4EAAyE;AAEzE,MAAM,YAAY,GAAG,iBAAO,CAAC,MAAM,EAAE,CAAC;AAEtC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,4BAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAA,wBAAS,EAAC,iCAAW,CAAC,CAAC,CAAC;AAE7E,kBAAe,YAAY,CAAC"} \ No newline at end of file diff --git a/dist/routers/productsRouter.d.ts b/dist/routers/productsRouter.d.ts new file mode 100644 index 00000000..1f243267 --- /dev/null +++ b/dist/routers/productsRouter.d.ts @@ -0,0 +1,3 @@ +declare const productsRouter: import("express-serve-static-core").Router; +export default productsRouter; +//# sourceMappingURL=productsRouter.d.ts.map \ No newline at end of file diff --git a/dist/routers/productsRouter.d.ts.map b/dist/routers/productsRouter.d.ts.map new file mode 100644 index 00000000..c60d07ac --- /dev/null +++ b/dist/routers/productsRouter.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"productsRouter.d.ts","sourceRoot":"","sources":["../../src/routers/productsRouter.ts"],"names":[],"mappings":"AAeA,QAAA,MAAM,cAAc,4CAAmB,CAAC;AAYxC,eAAe,cAAc,CAAC"} \ No newline at end of file diff --git a/dist/routers/productsRouter.js b/dist/routers/productsRouter.js new file mode 100644 index 00000000..2420508e --- /dev/null +++ b/dist/routers/productsRouter.js @@ -0,0 +1,21 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const withAsync_1 = require("../lib/withAsync"); +const productsController_1 = require("../controllers/productsController"); +const authenticate_1 = __importDefault(require("../middlewares/authenticate")); +const productsRouter = express_1.default.Router(); +productsRouter.post('/', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(productsController_1.createProduct)); +productsRouter.get('/:id', (0, authenticate_1.default)({ optional: true }), (0, withAsync_1.withAsync)(productsController_1.getProduct)); +productsRouter.patch('/:id', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(productsController_1.updateProduct)); +productsRouter.delete('/:id', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(productsController_1.deleteProduct)); +productsRouter.get('/', (0, authenticate_1.default)({ optional: true }), (0, withAsync_1.withAsync)(productsController_1.getProductList)); +productsRouter.post('/:id/comments', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(productsController_1.createComment)); +productsRouter.get('/:id/comments', (0, withAsync_1.withAsync)(productsController_1.getCommentList)); +productsRouter.post('/:id/favorites', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(productsController_1.createFavorite)); +productsRouter.delete('/:id/favorites', (0, authenticate_1.default)(), (0, withAsync_1.withAsync)(productsController_1.deleteFavorite)); +exports.default = productsRouter; +//# sourceMappingURL=productsRouter.js.map \ No newline at end of file diff --git a/dist/routers/productsRouter.js.map b/dist/routers/productsRouter.js.map new file mode 100644 index 00000000..738a6364 --- /dev/null +++ b/dist/routers/productsRouter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"productsRouter.js","sourceRoot":"","sources":["../../src/routers/productsRouter.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAC9B,gDAA6C;AAC7C,0EAU2C;AAC3C,+EAAuD;AAEvD,MAAM,cAAc,GAAG,iBAAO,CAAC,MAAM,EAAE,CAAC;AAExC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,kCAAa,CAAC,CAAC,CAAC;AACnE,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,IAAA,sBAAY,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,IAAA,qBAAS,EAAC,+BAAU,CAAC,CAAC,CAAC;AACpF,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,kCAAa,CAAC,CAAC,CAAC;AACvE,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,kCAAa,CAAC,CAAC,CAAC;AACxE,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,IAAA,sBAAY,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,IAAA,qBAAS,EAAC,mCAAc,CAAC,CAAC,CAAC;AACrF,cAAc,CAAC,IAAI,CAAC,eAAe,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,kCAAa,CAAC,CAAC,CAAC;AAC/E,cAAc,CAAC,GAAG,CAAC,eAAe,EAAE,IAAA,qBAAS,EAAC,mCAAc,CAAC,CAAC,CAAC;AAC/D,cAAc,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,mCAAc,CAAC,CAAC,CAAC;AACjF,cAAc,CAAC,MAAM,CAAC,gBAAgB,EAAE,IAAA,sBAAY,GAAE,EAAE,IAAA,qBAAS,EAAC,mCAAc,CAAC,CAAC,CAAC;AAEnF,kBAAe,cAAc,CAAC"} \ No newline at end of file diff --git a/dist/routers/usersRouter.d.ts b/dist/routers/usersRouter.d.ts new file mode 100644 index 00000000..34c4a2cb --- /dev/null +++ b/dist/routers/usersRouter.d.ts @@ -0,0 +1,3 @@ +declare const usersRouter: import("express-serve-static-core").Router; +export default usersRouter; +//# sourceMappingURL=usersRouter.d.ts.map \ No newline at end of file diff --git a/dist/routers/usersRouter.d.ts.map b/dist/routers/usersRouter.d.ts.map new file mode 100644 index 00000000..261e95a0 --- /dev/null +++ b/dist/routers/usersRouter.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"usersRouter.d.ts","sourceRoot":"","sources":["../../src/routers/usersRouter.ts"],"names":[],"mappings":"AAWA,QAAA,MAAM,WAAW,4CAAmB,CAAC;AAQrC,eAAe,WAAW,CAAC"} \ No newline at end of file diff --git a/dist/routers/usersRouter.js b/dist/routers/usersRouter.js new file mode 100644 index 00000000..d0d56b84 --- /dev/null +++ b/dist/routers/usersRouter.js @@ -0,0 +1,17 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const withAsync_js_1 = require("../lib/withAsync.js"); +const usersController_js_1 = require("../controllers/usersController.js"); +const authenticate_js_1 = __importDefault(require("../middlewares/authenticate.js")); +const usersRouter = express_1.default.Router(); +usersRouter.get('/me', (0, authenticate_js_1.default)(), (0, withAsync_js_1.withAsync)(usersController_js_1.getMe)); +usersRouter.patch('/me', (0, authenticate_js_1.default)(), (0, withAsync_js_1.withAsync)(usersController_js_1.updateMe)); +usersRouter.patch('/me/password', (0, authenticate_js_1.default)(), (0, withAsync_js_1.withAsync)(usersController_js_1.updateMyPassword)); +usersRouter.get('/me/products', (0, authenticate_js_1.default)(), (0, withAsync_js_1.withAsync)(usersController_js_1.getMyProductList)); +usersRouter.get('/me/favorites', (0, authenticate_js_1.default)(), (0, withAsync_js_1.withAsync)(usersController_js_1.getMyFavoriteList)); +exports.default = usersRouter; +//# sourceMappingURL=usersRouter.js.map \ No newline at end of file diff --git a/dist/routers/usersRouter.js.map b/dist/routers/usersRouter.js.map new file mode 100644 index 00000000..dbc81f61 --- /dev/null +++ b/dist/routers/usersRouter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"usersRouter.js","sourceRoot":"","sources":["../../src/routers/usersRouter.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAC9B,sDAAgD;AAChD,0EAM2C;AAC3C,qFAA0D;AAE1D,MAAM,WAAW,GAAG,iBAAO,CAAC,MAAM,EAAE,CAAC;AAErC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,IAAA,yBAAY,GAAE,EAAE,IAAA,wBAAS,EAAC,0BAAK,CAAC,CAAC,CAAC;AACzD,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,IAAA,yBAAY,GAAE,EAAE,IAAA,wBAAS,EAAC,6BAAQ,CAAC,CAAC,CAAC;AAC9D,WAAW,CAAC,KAAK,CAAC,cAAc,EAAE,IAAA,yBAAY,GAAE,EAAE,IAAA,wBAAS,EAAC,qCAAgB,CAAC,CAAC,CAAC;AAC/E,WAAW,CAAC,GAAG,CAAC,cAAc,EAAE,IAAA,yBAAY,GAAE,EAAE,IAAA,wBAAS,EAAC,qCAAgB,CAAC,CAAC,CAAC;AAC7E,WAAW,CAAC,GAAG,CAAC,eAAe,EAAE,IAAA,yBAAY,GAAE,EAAE,IAAA,wBAAS,EAAC,sCAAiB,CAAC,CAAC,CAAC;AAE/E,kBAAe,WAAW,CAAC"} \ No newline at end of file diff --git a/dist/structs/articlesStructs.d.ts b/dist/structs/articlesStructs.d.ts new file mode 100644 index 00000000..06a6a077 --- /dev/null +++ b/dist/structs/articlesStructs.d.ts @@ -0,0 +1,32 @@ +export declare const GetArticleListParamsStruct: import("superstruct").Struct<{ + page: number; + pageSize: number; + orderBy?: "recent" | undefined; + keyword?: string | undefined; +}, { + page: import("superstruct").Struct; + pageSize: import("superstruct").Struct; + orderBy: import("superstruct").Struct<"recent" | undefined, { + recent: "recent"; + }>; + keyword: import("superstruct").Struct; +}>; +export declare const CreateArticleBodyStruct: import("superstruct").Struct<{ + title: string; + content: string; + image: string | null; +}, { + title: import("superstruct").Struct; + content: import("superstruct").Struct; + image: import("superstruct").Struct; +}>; +export declare const UpdateArticleBodyStruct: import("superstruct").Struct<{ + title?: string | undefined; + content?: string | undefined; + image?: string | null | undefined; +}, import("superstruct/dist/utils.js").PartialObjectSchema<{ + title: import("superstruct").Struct; + content: import("superstruct").Struct; + image: import("superstruct").Struct; +}>>; +//# sourceMappingURL=articlesStructs.d.ts.map \ No newline at end of file diff --git a/dist/structs/articlesStructs.d.ts.map b/dist/structs/articlesStructs.d.ts.map new file mode 100644 index 00000000..4c5e4afb --- /dev/null +++ b/dist/structs/articlesStructs.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"articlesStructs.d.ts","sourceRoot":"","sources":["../../src/structs/articlesStructs.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,0BAA0B;;;;;;;;;;;;EAAmB,CAAC;AAE3D,eAAO,MAAM,uBAAuB;;;;;;;;EAIlC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;GAAmC,CAAC"} \ No newline at end of file diff --git a/dist/structs/articlesStructs.js b/dist/structs/articlesStructs.js new file mode 100644 index 00000000..4926a108 --- /dev/null +++ b/dist/structs/articlesStructs.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UpdateArticleBodyStruct = exports.CreateArticleBodyStruct = exports.GetArticleListParamsStruct = void 0; +const superstruct_1 = require("superstruct"); +const commonStructs_js_1 = require("./commonStructs.js"); +exports.GetArticleListParamsStruct = commonStructs_js_1.PageParamsStruct; +exports.CreateArticleBodyStruct = (0, superstruct_1.object)({ + title: (0, superstruct_1.coerce)((0, superstruct_1.nonempty)((0, superstruct_1.string)()), (0, superstruct_1.string)(), (value) => value.trim()), + content: (0, superstruct_1.nonempty)((0, superstruct_1.string)()), + image: (0, superstruct_1.nullable)((0, superstruct_1.string)()), +}); +exports.UpdateArticleBodyStruct = (0, superstruct_1.partial)(exports.CreateArticleBodyStruct); +//# sourceMappingURL=articlesStructs.js.map \ No newline at end of file diff --git a/dist/structs/articlesStructs.js.map b/dist/structs/articlesStructs.js.map new file mode 100644 index 00000000..b78bea93 --- /dev/null +++ b/dist/structs/articlesStructs.js.map @@ -0,0 +1 @@ +{"version":3,"file":"articlesStructs.js","sourceRoot":"","sources":["../../src/structs/articlesStructs.ts"],"names":[],"mappings":";;;AAAA,6CAAkF;AAClF,yDAAsD;AAEzC,QAAA,0BAA0B,GAAG,mCAAgB,CAAC;AAE9C,QAAA,uBAAuB,GAAG,IAAA,oBAAM,EAAC;IAC5C,KAAK,EAAE,IAAA,oBAAM,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,EAAE,IAAA,oBAAM,GAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACpE,OAAO,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC;IAC3B,KAAK,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC;CAC1B,CAAC,CAAC;AAEU,QAAA,uBAAuB,GAAG,IAAA,qBAAO,EAAC,+BAAuB,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/structs/authStructs.d.ts b/dist/structs/authStructs.d.ts new file mode 100644 index 00000000..3d8c720b --- /dev/null +++ b/dist/structs/authStructs.d.ts @@ -0,0 +1,17 @@ +export declare const RegisterBodyStruct: import("superstruct").Struct<{ + password: string; + email: string; + nickname: string; +}, { + email: import("superstruct").Struct; + nickname: import("superstruct").Struct; + password: import("superstruct").Struct; +}>; +export declare const LoginBodyStruct: import("superstruct").Struct<{ + password: string; + email: string; +}, { + email: import("superstruct").Struct; + password: import("superstruct").Struct; +}>; +//# sourceMappingURL=authStructs.d.ts.map \ No newline at end of file diff --git a/dist/structs/authStructs.d.ts.map b/dist/structs/authStructs.d.ts.map new file mode 100644 index 00000000..15cbf9e4 --- /dev/null +++ b/dist/structs/authStructs.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"authStructs.d.ts","sourceRoot":"","sources":["../../src/structs/authStructs.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,kBAAkB;;;;;;;;EAI7B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;EAG1B,CAAC"} \ No newline at end of file diff --git a/dist/structs/authStructs.js b/dist/structs/authStructs.js new file mode 100644 index 00000000..1b9b22ee --- /dev/null +++ b/dist/structs/authStructs.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.LoginBodyStruct = exports.RegisterBodyStruct = void 0; +const superstruct_1 = require("superstruct"); +exports.RegisterBodyStruct = (0, superstruct_1.object)({ + email: (0, superstruct_1.nonempty)((0, superstruct_1.string)()), + nickname: (0, superstruct_1.nonempty)((0, superstruct_1.string)()), + password: (0, superstruct_1.nonempty)((0, superstruct_1.string)()), +}); +exports.LoginBodyStruct = (0, superstruct_1.object)({ + email: (0, superstruct_1.nonempty)((0, superstruct_1.string)()), + password: (0, superstruct_1.nonempty)((0, superstruct_1.string)()), +}); +//# sourceMappingURL=authStructs.js.map \ No newline at end of file diff --git a/dist/structs/authStructs.js.map b/dist/structs/authStructs.js.map new file mode 100644 index 00000000..4f53c005 --- /dev/null +++ b/dist/structs/authStructs.js.map @@ -0,0 +1 @@ +{"version":3,"file":"authStructs.js","sourceRoot":"","sources":["../../src/structs/authStructs.ts"],"names":[],"mappings":";;;AAAA,6CAAuD;AAE1C,QAAA,kBAAkB,GAAG,IAAA,oBAAM,EAAC;IACvC,KAAK,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC;IACzB,QAAQ,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC;IAC5B,QAAQ,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC;CAC7B,CAAC,CAAC;AAEU,QAAA,eAAe,GAAG,IAAA,oBAAM,EAAC;IACpC,KAAK,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC;IACzB,QAAQ,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC;CAC7B,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/structs/commentsStruct.d.ts b/dist/structs/commentsStruct.d.ts new file mode 100644 index 00000000..8e20c766 --- /dev/null +++ b/dist/structs/commentsStruct.d.ts @@ -0,0 +1,24 @@ +export declare const CreateCommentBodyStruct: import("superstruct").Struct<{ + content: string; +}, { + content: import("superstruct").Struct; +}>; +export declare const GetCommentListParamsStruct: import("superstruct").Struct<{ + cursor: number; + limit: number; + orderBy?: "recent" | undefined; + keyword?: string | undefined; +}, { + cursor: import("superstruct").Struct; + limit: import("superstruct").Struct; + orderBy: import("superstruct").Struct<"recent" | undefined, { + recent: "recent"; + }>; + keyword: import("superstruct").Struct; +}>; +export declare const UpdateCommentBodyStruct: import("superstruct").Struct<{ + content?: string | undefined; +}, import("superstruct/dist/utils.js").PartialObjectSchema<{ + content: import("superstruct").Struct; +}>>; +//# sourceMappingURL=commentsStruct.d.ts.map \ No newline at end of file diff --git a/dist/structs/commentsStruct.d.ts.map b/dist/structs/commentsStruct.d.ts.map new file mode 100644 index 00000000..b7fde665 --- /dev/null +++ b/dist/structs/commentsStruct.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"commentsStruct.d.ts","sourceRoot":"","sources":["../../src/structs/commentsStruct.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,uBAAuB;;;;EAElC,CAAC;AAEH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;EAAqB,CAAC;AAE7D,eAAO,MAAM,uBAAuB;;;;GAAmC,CAAC"} \ No newline at end of file diff --git a/dist/structs/commentsStruct.js b/dist/structs/commentsStruct.js new file mode 100644 index 00000000..91c95ba6 --- /dev/null +++ b/dist/structs/commentsStruct.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UpdateCommentBodyStruct = exports.GetCommentListParamsStruct = exports.CreateCommentBodyStruct = void 0; +const superstruct_1 = require("superstruct"); +const commonStructs_js_1 = require("./commonStructs.js"); +exports.CreateCommentBodyStruct = (0, superstruct_1.object)({ + content: (0, superstruct_1.nonempty)((0, superstruct_1.string)()), +}); +exports.GetCommentListParamsStruct = commonStructs_js_1.CursorParamsStruct; +exports.UpdateCommentBodyStruct = (0, superstruct_1.partial)(exports.CreateCommentBodyStruct); +//# sourceMappingURL=commentsStruct.js.map \ No newline at end of file diff --git a/dist/structs/commentsStruct.js.map b/dist/structs/commentsStruct.js.map new file mode 100644 index 00000000..b0814712 --- /dev/null +++ b/dist/structs/commentsStruct.js.map @@ -0,0 +1 @@ +{"version":3,"file":"commentsStruct.js","sourceRoot":"","sources":["../../src/structs/commentsStruct.ts"],"names":[],"mappings":";;;AAAA,6CAAgE;AAChE,yDAAwD;AAE3C,QAAA,uBAAuB,GAAG,IAAA,oBAAM,EAAC;IAC5C,OAAO,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC;CAC5B,CAAC,CAAC;AAEU,QAAA,0BAA0B,GAAG,qCAAkB,CAAC;AAEhD,QAAA,uBAAuB,GAAG,IAAA,qBAAO,EAAC,+BAAuB,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/structs/commonStructs.d.ts b/dist/structs/commonStructs.d.ts new file mode 100644 index 00000000..b72be4f3 --- /dev/null +++ b/dist/structs/commonStructs.d.ts @@ -0,0 +1,32 @@ +export declare const IdParamsStruct: import("superstruct").Struct<{ + id: number; +}, { + id: import("superstruct").Struct; +}>; +export declare const PageParamsStruct: import("superstruct").Struct<{ + page: number; + pageSize: number; + orderBy?: "recent" | undefined; + keyword?: string | undefined; +}, { + page: import("superstruct").Struct; + pageSize: import("superstruct").Struct; + orderBy: import("superstruct").Struct<"recent" | undefined, { + recent: "recent"; + }>; + keyword: import("superstruct").Struct; +}>; +export declare const CursorParamsStruct: import("superstruct").Struct<{ + cursor: number; + limit: number; + orderBy?: "recent" | undefined; + keyword?: string | undefined; +}, { + cursor: import("superstruct").Struct; + limit: import("superstruct").Struct; + orderBy: import("superstruct").Struct<"recent" | undefined, { + recent: "recent"; + }>; + keyword: import("superstruct").Struct; +}>; +//# sourceMappingURL=commonStructs.d.ts.map \ No newline at end of file diff --git a/dist/structs/commonStructs.d.ts.map b/dist/structs/commonStructs.d.ts.map new file mode 100644 index 00000000..7530b305 --- /dev/null +++ b/dist/structs/commonStructs.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"commonStructs.d.ts","sourceRoot":"","sources":["../../src/structs/commonStructs.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,cAAc;;;;EAEzB,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAK3B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;EAK7B,CAAC"} \ No newline at end of file diff --git a/dist/structs/commonStructs.js b/dist/structs/commonStructs.js new file mode 100644 index 00000000..8c73a7fb --- /dev/null +++ b/dist/structs/commonStructs.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CursorParamsStruct = exports.PageParamsStruct = exports.IdParamsStruct = void 0; +const superstruct_1 = require("superstruct"); +/** Convert string to integer then validate it */ +const integerString = (0, superstruct_1.coerce)((0, superstruct_1.integer)(), (0, superstruct_1.string)(), (value) => parseInt(value)); +exports.IdParamsStruct = (0, superstruct_1.object)({ + id: integerString, +}); +exports.PageParamsStruct = (0, superstruct_1.object)({ + page: (0, superstruct_1.defaulted)(integerString, 1), + pageSize: (0, superstruct_1.defaulted)(integerString, 10), + orderBy: (0, superstruct_1.optional)((0, superstruct_1.enums)(['recent'])), + keyword: (0, superstruct_1.optional)((0, superstruct_1.nonempty)((0, superstruct_1.string)())), +}); +exports.CursorParamsStruct = (0, superstruct_1.object)({ + cursor: (0, superstruct_1.defaulted)(integerString, 0), + limit: (0, superstruct_1.defaulted)(integerString, 10), + orderBy: (0, superstruct_1.optional)((0, superstruct_1.enums)(['recent'])), + keyword: (0, superstruct_1.optional)((0, superstruct_1.nonempty)((0, superstruct_1.string)())), +}); +//# sourceMappingURL=commonStructs.js.map \ No newline at end of file diff --git a/dist/structs/commonStructs.js.map b/dist/structs/commonStructs.js.map new file mode 100644 index 00000000..17a6445a --- /dev/null +++ b/dist/structs/commonStructs.js.map @@ -0,0 +1 @@ +{"version":3,"file":"commonStructs.js","sourceRoot":"","sources":["../../src/structs/commonStructs.ts"],"names":[],"mappings":";;;AAAA,6CAAoG;AAEpG,iDAAiD;AACjD,MAAM,aAAa,GAAG,IAAA,oBAAM,EAAC,IAAA,qBAAO,GAAE,EAAE,IAAA,oBAAM,GAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAEjE,QAAA,cAAc,GAAG,IAAA,oBAAM,EAAC;IACnC,EAAE,EAAE,aAAa;CAClB,CAAC,CAAC;AAEU,QAAA,gBAAgB,GAAG,IAAA,oBAAM,EAAC;IACrC,IAAI,EAAE,IAAA,uBAAS,EAAC,aAAa,EAAE,CAAC,CAAC;IACjC,QAAQ,EAAE,IAAA,uBAAS,EAAC,aAAa,EAAE,EAAE,CAAC;IACtC,OAAO,EAAE,IAAA,sBAAQ,EAAC,IAAA,mBAAK,EAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpC,OAAO,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;CACtC,CAAC,CAAC;AAEU,QAAA,kBAAkB,GAAG,IAAA,oBAAM,EAAC;IACvC,MAAM,EAAE,IAAA,uBAAS,EAAC,aAAa,EAAE,CAAC,CAAC;IACnC,KAAK,EAAE,IAAA,uBAAS,EAAC,aAAa,EAAE,EAAE,CAAC;IACnC,OAAO,EAAE,IAAA,sBAAQ,EAAC,IAAA,mBAAK,EAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpC,OAAO,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;CACtC,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/structs/productsStruct.d.ts b/dist/structs/productsStruct.d.ts new file mode 100644 index 00000000..e88a6e76 --- /dev/null +++ b/dist/structs/productsStruct.d.ts @@ -0,0 +1,40 @@ +export declare const CreateProductBodyStruct: import("superstruct").Struct<{ + name: string; + description: string; + price: number; + tags: string[]; + images: string[]; +}, { + name: import("superstruct").Struct; + description: import("superstruct").Struct; + price: import("superstruct").Struct; + tags: import("superstruct").Struct>; + images: import("superstruct").Struct>; +}>; +export declare const GetProductListParamsStruct: import("superstruct").Struct<{ + page: number; + pageSize: number; + orderBy?: "recent" | undefined; + keyword?: string | undefined; +}, { + page: import("superstruct").Struct; + pageSize: import("superstruct").Struct; + orderBy: import("superstruct").Struct<"recent" | undefined, { + recent: "recent"; + }>; + keyword: import("superstruct").Struct; +}>; +export declare const UpdateProductBodyStruct: import("superstruct").Struct<{ + name?: string | undefined; + description?: string | undefined; + price?: number | undefined; + tags?: string[] | undefined; + images?: string[] | undefined; +}, import("superstruct/dist/utils.js").PartialObjectSchema<{ + name: import("superstruct").Struct; + description: import("superstruct").Struct; + price: import("superstruct").Struct; + tags: import("superstruct").Struct>; + images: import("superstruct").Struct>; +}>>; +//# sourceMappingURL=productsStruct.d.ts.map \ No newline at end of file diff --git a/dist/structs/productsStruct.d.ts.map b/dist/structs/productsStruct.d.ts.map new file mode 100644 index 00000000..824098e9 --- /dev/null +++ b/dist/structs/productsStruct.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"productsStruct.d.ts","sourceRoot":"","sources":["../../src/structs/productsStruct.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,uBAAuB;;;;;;;;;;;;EAMlC,CAAC;AAEH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;EAAmB,CAAC;AAE3D,eAAO,MAAM,uBAAuB;;;;;;;;;;;;GAAmC,CAAC"} \ No newline at end of file diff --git a/dist/structs/productsStruct.js b/dist/structs/productsStruct.js new file mode 100644 index 00000000..6ce92fb0 --- /dev/null +++ b/dist/structs/productsStruct.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UpdateProductBodyStruct = exports.GetProductListParamsStruct = exports.CreateProductBodyStruct = void 0; +const superstruct_1 = require("superstruct"); +const commonStructs_js_1 = require("./commonStructs.js"); +exports.CreateProductBodyStruct = (0, superstruct_1.object)({ + name: (0, superstruct_1.coerce)((0, superstruct_1.nonempty)((0, superstruct_1.string)()), (0, superstruct_1.string)(), (value) => value.trim()), + description: (0, superstruct_1.nonempty)((0, superstruct_1.string)()), + price: (0, superstruct_1.min)((0, superstruct_1.integer)(), 0), + tags: (0, superstruct_1.array)((0, superstruct_1.nonempty)((0, superstruct_1.string)())), + images: (0, superstruct_1.array)((0, superstruct_1.nonempty)((0, superstruct_1.string)())), +}); +exports.GetProductListParamsStruct = commonStructs_js_1.PageParamsStruct; +exports.UpdateProductBodyStruct = (0, superstruct_1.partial)(exports.CreateProductBodyStruct); +//# sourceMappingURL=productsStruct.js.map \ No newline at end of file diff --git a/dist/structs/productsStruct.js.map b/dist/structs/productsStruct.js.map new file mode 100644 index 00000000..f22a9045 --- /dev/null +++ b/dist/structs/productsStruct.js.map @@ -0,0 +1 @@ +{"version":3,"file":"productsStruct.js","sourceRoot":"","sources":["../../src/structs/productsStruct.ts"],"names":[],"mappings":";;;AAAA,6CAA6F;AAC7F,yDAAsD;AAEzC,QAAA,uBAAuB,GAAG,IAAA,oBAAM,EAAC;IAC5C,IAAI,EAAE,IAAA,oBAAM,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,EAAE,IAAA,oBAAM,GAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACnE,WAAW,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC;IAC/B,KAAK,EAAE,IAAA,iBAAG,EAAC,IAAA,qBAAO,GAAE,EAAE,CAAC,CAAC;IACxB,IAAI,EAAE,IAAA,mBAAK,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IAC/B,MAAM,EAAE,IAAA,mBAAK,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;CAClC,CAAC,CAAC;AAEU,QAAA,0BAA0B,GAAG,mCAAgB,CAAC;AAE9C,QAAA,uBAAuB,GAAG,IAAA,qBAAO,EAAC,+BAAuB,CAAC,CAAC"} \ No newline at end of file diff --git a/dist/structs/usersStructs.d.ts b/dist/structs/usersStructs.d.ts new file mode 100644 index 00000000..78021314 --- /dev/null +++ b/dist/structs/usersStructs.d.ts @@ -0,0 +1,43 @@ +export declare const UpdateMeBodyStruct: import("superstruct").Struct<{ + image?: string | null | undefined; + email?: string | undefined; + nickname?: string | undefined; +}, import("superstruct/dist/utils.js").PartialObjectSchema<{ + email: import("superstruct").Struct; + nickname: import("superstruct").Struct; + image: import("superstruct").Struct; +}>>; +export declare const UpdatePasswordBodyStruct: import("superstruct").Struct<{ + password: string; + newPassword: string; +}, { + password: import("superstruct").Struct; + newPassword: import("superstruct").Struct; +}>; +export declare const GetMyProductListParamsStruct: import("superstruct").Struct<{ + page: number; + pageSize: number; + orderBy?: "recent" | undefined; + keyword?: string | undefined; +}, { + page: import("superstruct").Struct; + pageSize: import("superstruct").Struct; + orderBy: import("superstruct").Struct<"recent" | undefined, { + recent: "recent"; + }>; + keyword: import("superstruct").Struct; +}>; +export declare const GetMyFavoriteListParamsStruct: import("superstruct").Struct<{ + page: number; + pageSize: number; + orderBy?: "recent" | undefined; + keyword?: string | undefined; +}, { + page: import("superstruct").Struct; + pageSize: import("superstruct").Struct; + orderBy: import("superstruct").Struct<"recent" | undefined, { + recent: "recent"; + }>; + keyword: import("superstruct").Struct; +}>; +//# sourceMappingURL=usersStructs.d.ts.map \ No newline at end of file diff --git a/dist/structs/usersStructs.d.ts.map b/dist/structs/usersStructs.d.ts.map new file mode 100644 index 00000000..12490414 --- /dev/null +++ b/dist/structs/usersStructs.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"usersStructs.d.ts","sourceRoot":"","sources":["../../src/structs/usersStructs.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,kBAAkB;;;;;;;;GAM9B,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;EAGnC,CAAC;AAEH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;EAAmB,CAAC;AAE7D,eAAO,MAAM,6BAA6B;;;;;;;;;;;;EAAmB,CAAC"} \ No newline at end of file diff --git a/dist/structs/usersStructs.js b/dist/structs/usersStructs.js new file mode 100644 index 00000000..3c78c106 --- /dev/null +++ b/dist/structs/usersStructs.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.GetMyFavoriteListParamsStruct = exports.GetMyProductListParamsStruct = exports.UpdatePasswordBodyStruct = exports.UpdateMeBodyStruct = void 0; +const superstruct_1 = require("superstruct"); +const commonStructs_js_1 = require("./commonStructs.js"); +exports.UpdateMeBodyStruct = (0, superstruct_1.partial)((0, superstruct_1.object)({ + email: (0, superstruct_1.string)(), + nickname: (0, superstruct_1.string)(), + image: (0, superstruct_1.nullable)((0, superstruct_1.string)()), +})); +exports.UpdatePasswordBodyStruct = (0, superstruct_1.object)({ + password: (0, superstruct_1.string)(), + newPassword: (0, superstruct_1.string)(), +}); +exports.GetMyProductListParamsStruct = commonStructs_js_1.PageParamsStruct; +exports.GetMyFavoriteListParamsStruct = commonStructs_js_1.PageParamsStruct; +//# sourceMappingURL=usersStructs.js.map \ No newline at end of file diff --git a/dist/structs/usersStructs.js.map b/dist/structs/usersStructs.js.map new file mode 100644 index 00000000..7c0d0421 --- /dev/null +++ b/dist/structs/usersStructs.js.map @@ -0,0 +1 @@ +{"version":3,"file":"usersStructs.js","sourceRoot":"","sources":["../../src/structs/usersStructs.ts"],"names":[],"mappings":";;;AAAA,6CAAgE;AAChE,yDAAsD;AAEzC,QAAA,kBAAkB,GAAG,IAAA,qBAAO,EACvC,IAAA,oBAAM,EAAC;IACL,KAAK,EAAE,IAAA,oBAAM,GAAE;IACf,QAAQ,EAAE,IAAA,oBAAM,GAAE;IAClB,KAAK,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC;CAC1B,CAAC,CACH,CAAC;AAEW,QAAA,wBAAwB,GAAG,IAAA,oBAAM,EAAC;IAC7C,QAAQ,EAAE,IAAA,oBAAM,GAAE;IAClB,WAAW,EAAE,IAAA,oBAAM,GAAE;CACtB,CAAC,CAAC;AAEU,QAAA,4BAA4B,GAAG,mCAAgB,CAAC;AAEhD,QAAA,6BAA6B,GAAG,mCAAgB,CAAC"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..717fb242 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4067 @@ +{ + "name": "sprint4", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "dependencies": { + "@prisma/client": "^5.16.2", + "bcrypt": "^5.1.1", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "express": "^4.19.2", + "jsonwebtoken": "^9.0.2", + "multer": "^1.4.5-lts.1", + "superstruct": "^2.0.2", + "uuid": "^11.0.5" + }, + "devDependencies": { + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.10", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.6", + "@types/jsonwebtoken": "^9.0.10", + "@types/multer": "^2.0.0", + "nodemon": "^3.1.11", + "prettier": "^3.3.2", + "prisma": "^5.16.2", + "ts-node": "^10.9.2", + "typescript": "^5.9.3" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@prisma/client": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.16.2.tgz", + "integrity": "sha512-+1lmkhR9gHWcTC5oghm2ZKpWljyWdzfazCVlLKUWXVmwHSf52g81aZ8qb6Km5Bs025yBi7puLp3qSLEvktoUtw==", + "hasInstallScript": true, + "engines": { + "node": ">=16.13" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/debug": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.16.2.tgz", + "integrity": "sha512-ItzB4nR4O8eLzuJiuP3WwUJfoIvewMHqpGCad+64gvThcKEVOtaUza9AEJo2DPqAOa/AWkFyK54oM4WwHeew+A==", + "devOptional": true + }, + "node_modules/@prisma/engines": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.16.2.tgz", + "integrity": "sha512-qUxwMtrwoG3byd4PbX6T7EjHJ8AUhzTuwniOGkh/hIznBfcE2QQnGakyEq4VnwNuttMqvh/GgPFapHQ3lCuRHg==", + "devOptional": true, + "hasInstallScript": true, + "dependencies": { + "@prisma/debug": "5.16.2", + "@prisma/engines-version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", + "@prisma/fetch-engine": "5.16.2", + "@prisma/get-platform": "5.16.2" + } + }, + "node_modules/@prisma/engines-version": { + "version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303.tgz", + "integrity": "sha512-HkT2WbfmFZ9WUPyuJHhkiADxazHg8Y4gByrTSVeb3OikP6tjQ7txtSUGu9OBOBH0C13dPKN2qqH12xKtHu/Hiw==", + "devOptional": true + }, + "node_modules/@prisma/fetch-engine": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.16.2.tgz", + "integrity": "sha512-sq51lfHKfH2jjYSjBtMjP+AznFqOJzXpqmq6B9auWrlTJrMgZ7lPyhWUW7VU7LsQU48/TJ+DZeIz8s9bMYvcHg==", + "devOptional": true, + "dependencies": { + "@prisma/debug": "5.16.2", + "@prisma/engines-version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", + "@prisma/get-platform": "5.16.2" + } + }, + "node_modules/@prisma/get-platform": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.16.2.tgz", + "integrity": "sha512-cXiHPgNLNyj22vLouPVNegklpRL/iX2jxTeap5GRO3DmCoVyIHmJAV1CgUMUJhHlcol9yYy7EHvsnXTDJ/PKEA==", + "devOptional": true, + "dependencies": { + "@prisma/debug": "5.16.2" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie-parser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.10.tgz", + "integrity": "sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/multer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", + "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/node": { + "version": "25.0.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.8.tgz", + "integrity": "sha512-powIePYMmC3ibL0UJ2i2s0WIbq6cg6UyVFQxSCpaPxxzAaziRfimGivjdF943sSGV6RADVbk0Nvlm5P/FB44Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nodemon": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz", + "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prisma": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.16.2.tgz", + "integrity": "sha512-rFV/xoBR2hBGGlu4LPLQd4U8WVA+tSAmYyFWGPRVfj+xg7N4kiZV4lSk38htSpF+/IuHKzlrbh4SFk8Z18cI8A==", + "devOptional": true, + "hasInstallScript": true, + "dependencies": { + "@prisma/engines": "5.16.2" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=16.13" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz", + "integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + } + }, + "dependencies": { + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "requires": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + } + }, + "@prisma/client": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.16.2.tgz", + "integrity": "sha512-+1lmkhR9gHWcTC5oghm2ZKpWljyWdzfazCVlLKUWXVmwHSf52g81aZ8qb6Km5Bs025yBi7puLp3qSLEvktoUtw==", + "requires": {} + }, + "@prisma/debug": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.16.2.tgz", + "integrity": "sha512-ItzB4nR4O8eLzuJiuP3WwUJfoIvewMHqpGCad+64gvThcKEVOtaUza9AEJo2DPqAOa/AWkFyK54oM4WwHeew+A==", + "devOptional": true + }, + "@prisma/engines": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.16.2.tgz", + "integrity": "sha512-qUxwMtrwoG3byd4PbX6T7EjHJ8AUhzTuwniOGkh/hIznBfcE2QQnGakyEq4VnwNuttMqvh/GgPFapHQ3lCuRHg==", + "devOptional": true, + "requires": { + "@prisma/debug": "5.16.2", + "@prisma/engines-version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", + "@prisma/fetch-engine": "5.16.2", + "@prisma/get-platform": "5.16.2" + } + }, + "@prisma/engines-version": { + "version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303.tgz", + "integrity": "sha512-HkT2WbfmFZ9WUPyuJHhkiADxazHg8Y4gByrTSVeb3OikP6tjQ7txtSUGu9OBOBH0C13dPKN2qqH12xKtHu/Hiw==", + "devOptional": true + }, + "@prisma/fetch-engine": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.16.2.tgz", + "integrity": "sha512-sq51lfHKfH2jjYSjBtMjP+AznFqOJzXpqmq6B9auWrlTJrMgZ7lPyhWUW7VU7LsQU48/TJ+DZeIz8s9bMYvcHg==", + "devOptional": true, + "requires": { + "@prisma/debug": "5.16.2", + "@prisma/engines-version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", + "@prisma/get-platform": "5.16.2" + } + }, + "@prisma/get-platform": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.16.2.tgz", + "integrity": "sha512-cXiHPgNLNyj22vLouPVNegklpRL/iX2jxTeap5GRO3DmCoVyIHmJAV1CgUMUJhHlcol9yYy7EHvsnXTDJ/PKEA==", + "devOptional": true, + "requires": { + "@prisma/debug": "5.16.2" + } + }, + "@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cookie-parser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.10.tgz", + "integrity": "sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==", + "dev": true, + "requires": {} + }, + "@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "@types/express-serve-static-core": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true + }, + "@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "dev": true, + "requires": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true + }, + "@types/multer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", + "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/node": { + "version": "25.0.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.8.tgz", + "integrity": "sha512-powIePYMmC3ibL0UJ2i2s0WIbq6cg6UyVFQxSCpaPxxzAaziRfimGivjdF943sSGV6RADVbk0Nvlm5P/FB44Zg==", + "dev": true, + "requires": { + "undici-types": "~7.16.0" + } + }, + "@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "requires": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true + }, + "acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "requires": { + "acorn": "^8.11.0" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "requires": { + "ms": "^2.1.3" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "requires": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + } + }, + "binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true + }, + "body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "requires": { + "fill-range": "^7.1.1" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "requires": { + "streamsearch": "^1.1.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, + "chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + }, + "cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "requires": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "dependencies": { + "cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==" + } + } + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==" + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "requires": { + "ms": "^2.1.3" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==" + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + } + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "nodemon": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz", + "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true + }, + "prisma": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.16.2.tgz", + "integrity": "sha512-rFV/xoBR2hBGGlu4LPLQd4U8WVA+tSAmYyFWGPRVfj+xg7N4kiZV4lSk38htSpF+/IuHKzlrbh4SFk8Z18cI8A==", + "devOptional": true, + "requires": { + "@prisma/engines": "5.16.2" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==" + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "requires": { + "semver": "^7.5.3" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true + }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "uuid": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz", + "integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==" + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..a860e403 --- /dev/null +++ b/package.json @@ -0,0 +1,40 @@ +{ + "type": "module", + "scripts": { + "start": "node ./src/main.js", + "build": "tsc", + "dev": "nodemon --exec ts-node src/main.ts" + }, + "devDependencies": { + "@types/bcrypt": "^6.0.0", + "@types/cookie-parser": "^1.4.10", + "@types/cors": "^2.8.19", + "@types/express": "^5.0.6", + "@types/jsonwebtoken": "^9.0.10", + "@types/multer": "^2.0.0", + "nodemon": "^3.1.11", + "prettier": "^3.3.2", + "prisma": "^5.16.2", + "ts-node": "^10.9.2", + "typescript": "^5.9.3" + }, + "dependencies": { + "@prisma/client": "^5.16.2", + "bcrypt": "^5.1.1", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "express": "^4.19.2", + "jsonwebtoken": "^9.0.2", + "multer": "^1.4.5-lts.1", + "superstruct": "^2.0.2", + "uuid": "^11.0.5" + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} diff --git a/prisma/migrations/20250111082621_/migration.sql b/prisma/migrations/20250111082621_/migration.sql new file mode 100644 index 00000000..fcdea0ea --- /dev/null +++ b/prisma/migrations/20250111082621_/migration.sql @@ -0,0 +1,43 @@ +-- CreateTable +CREATE TABLE "Article" ( + "id" SERIAL NOT NULL, + "title" TEXT NOT NULL, + "content" TEXT NOT NULL, + "image" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Article_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Product" ( + "id" SERIAL NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT NOT NULL, + "price" INTEGER NOT NULL, + "tags" TEXT[], + "images" TEXT[], + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Product_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Comment" ( + "id" SERIAL NOT NULL, + "content" TEXT NOT NULL, + "productId" INTEGER, + "articleId" INTEGER, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Comment_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "Comment" ADD CONSTRAINT "Comment_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Comment" ADD CONSTRAINT "Comment_articleId_fkey" FOREIGN KEY ("articleId") REFERENCES "Article"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20250304075708_add_user/migration.sql b/prisma/migrations/20250304075708_add_user/migration.sql new file mode 100644 index 00000000..ed2457f7 --- /dev/null +++ b/prisma/migrations/20250304075708_add_user/migration.sql @@ -0,0 +1,15 @@ +-- CreateTable +CREATE TABLE "User" ( + "id" SERIAL NOT NULL, + "email" TEXT NOT NULL, + "nickname" TEXT NOT NULL, + "image" TEXT, + "password" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); diff --git a/prisma/migrations/20250304082334_authorization/migration.sql b/prisma/migrations/20250304082334_authorization/migration.sql new file mode 100644 index 00000000..9e47895b --- /dev/null +++ b/prisma/migrations/20250304082334_authorization/migration.sql @@ -0,0 +1,31 @@ +/* + Warnings: + + - Added the required column `userId` to the `Article` table without a default value. This is not possible if the table is not empty. + - Added the required column `userId` to the `Comment` table without a default value. This is not possible if the table is not empty. + - Added the required column `userId` to the `Product` table without a default value. This is not possible if the table is not empty. + +*/ + +-- Delete ALL Articles, Comments, Products +DELETE FROM "Article"; +DELETE FROM "Comment"; +DELETE FROM "Product"; + +-- AlterTable +ALTER TABLE "Article" ADD COLUMN "userId" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "Comment" ADD COLUMN "userId" INTEGER NOT NULL; + +-- AlterTable +ALTER TABLE "Product" ADD COLUMN "userId" INTEGER NOT NULL; + +-- AddForeignKey +ALTER TABLE "Article" ADD CONSTRAINT "Article_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Product" ADD CONSTRAINT "Product_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Comment" ADD CONSTRAINT "Comment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20250304094902_add_favorite_like/migration.sql b/prisma/migrations/20250304094902_add_favorite_like/migration.sql new file mode 100644 index 00000000..918a2e4b --- /dev/null +++ b/prisma/migrations/20250304094902_add_favorite_like/migration.sql @@ -0,0 +1,33 @@ +-- CreateTable +CREATE TABLE "Favorite" ( + "id" SERIAL NOT NULL, + "productId" INTEGER NOT NULL, + "userId" INTEGER NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Favorite_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Like" ( + "id" SERIAL NOT NULL, + "articleId" INTEGER NOT NULL, + "userId" INTEGER NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Like_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "Favorite" ADD CONSTRAINT "Favorite_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Favorite" ADD CONSTRAINT "Favorite_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Like" ADD CONSTRAINT "Like_articleId_fkey" FOREIGN KEY ("articleId") REFERENCES "Article"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Like" ADD CONSTRAINT "Like_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 00000000..fbffa92c --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 00000000..cb00db79 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,90 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model Article { + id Int @id @default(autoincrement()) + title String + content String + image String? + comments Comment[] + user User @relation(fields: [userId], references: [id]) + userId Int + likes Like[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model Product { + id Int @id @default(autoincrement()) + name String + description String + price Int + tags String[] + images String[] + comments Comment[] + user User @relation(fields: [userId], references: [id]) + userId Int + favorites Favorite[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model Comment { + id Int @id @default(autoincrement()) + content String + product Product? @relation(fields: [productId], references: [id], onDelete: Cascade) + productId Int? + article Article? @relation(fields: [articleId], references: [id], onDelete: Cascade) + articleId Int? + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model User { + id Int @id @default(autoincrement()) + email String @unique + nickname String + image String? + password String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + articles Article[] + products Product[] + comments Comment[] + favorites Favorite[] + likes Like[] +} + +model Favorite { + id Int @id @default(autoincrement()) + product Product @relation(fields: [productId], references: [id]) + productId Int + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model Like { + id Int @id @default(autoincrement()) + article Article @relation(fields: [articleId], references: [id]) + articleId Int + user User @relation(fields: [userId], references: [id]) + userId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} diff --git a/public/.gitkeep b/public/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/controllers/articlesController.ts b/src/controllers/articlesController.ts new file mode 100644 index 00000000..5f1353a7 --- /dev/null +++ b/src/controllers/articlesController.ts @@ -0,0 +1,231 @@ +import { create } from 'superstruct'; +import { prismaClient } from '../lib/prismaClient'; +import NotFoundError from '../lib/errors/NotFoundError'; +import { IdParamsStruct } from '../structs/commonStructs'; +import { + CreateArticleBodyStruct, + UpdateArticleBodyStruct, + GetArticleListParamsStruct, +} from '../structs/articlesStructs'; +import { CreateCommentBodyStruct, GetCommentListParamsStruct } from '../structs/commentsStruct'; +import UnauthorizedError from '../lib/errors/UnauthorizedError'; +import ForbiddenError from '../lib/errors/ForbiddenError'; +import BadRequestError from '../lib/errors/BadRequestError'; +import { Request, Response, NextFunction } from "express"; +import { Prisma } from '@prisma/client'; + +export async function createArticle(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const data = create(req.body, CreateArticleBodyStruct); + + const article = await prismaClient.article.create({ + data: { + ...data, + userId: req.user.id, + }, + }); + + return res.status(201).send(article); +} + +export async function getArticle(req: Request, res: Response) { + const { id } = create(req.params, IdParamsStruct); + + const article = await prismaClient.article.findUnique({ + where: { id }, + include: { + likes: true, + }, + }); + if (!article) { + throw new NotFoundError('article', id); + } + + const articleWithLikes = { + ...article, + likes: undefined, + likeCount: article.likes.length, + isLiked: req.user ? article.likes.some((like) => like.userId === req.user!.id) : undefined, + }; + + return res.send(articleWithLikes); +} + +export async function updateArticle(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id } = create(req.params, IdParamsStruct); + const data = create(req.body, UpdateArticleBodyStruct); + + const existingArticle = await prismaClient.article.findUnique({ where: { id } }); + if (!existingArticle) { + throw new NotFoundError('article', id); + } + + if (existingArticle.userId !== req.user.id) { + throw new ForbiddenError('Should be the owner of the article'); + } + + const updatedArticle = await prismaClient.article.update({ where: { id }, data: { + ...(title !== undefined && { title }), + ...(content !== undefined && { content }), + ...(image !== undefined && { image }), + }, }); + return res.send(updatedArticle); +} + +export async function deleteArticle(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id } = create(req.params, IdParamsStruct); + + const existingArticle = await prismaClient.article.findUnique({ where: { id } }); + if (!existingArticle) { + throw new NotFoundError('article', id); + } + + if (existingArticle.userId !== req.user.id) { + throw new ForbiddenError('Should be the owner of the article'); + } + + await prismaClient.article.delete({ where: { id } }); + return res.status(204).send(); +} + +export async function getArticleList(req: Request, res: Response) { + const { page, pageSize, orderBy, keyword } = create(req.query, GetArticleListParamsStruct); + + const where: Prisma.ArticleWhereInput = keyword + ? { + OR: [ + { title: { contains: keyword } }, + { content: { contains: keyword } }, + ], + } + : {} + + const totalCount = await prismaClient.article.count({ where }); + const articles = await prismaClient.article.findMany({ + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: orderBy === 'recent' ? { createdAt: 'desc' } : { id: 'asc' }, + where, + include: { + likes: true, + }, + }); + + const articlesWithLikes = articles.map((article) => ({ + ...article, + likes: undefined, + likeCount: article.likes.length, + isLiked: req.user ? article.likes.some((like) => like.userId === req.user!.id) : undefined, + })); + + return res.send({ + list: articlesWithLikes, + totalCount, + }); +} + +export async function createComment(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id: articleId } = create(req.params, IdParamsStruct); + const { content } = create(req.body, CreateCommentBodyStruct); + + const existingArticle = await prismaClient.article.findUnique({ where: { id: articleId } }); + if (!existingArticle) { + throw new NotFoundError('article', articleId); + } + + const createdComment = await prismaClient.comment.create({ + data: { + articleId, + content, + userId: req.user.id, + }, + }); + + return res.status(201).send(createdComment); +} + +export async function getCommentList(req: Request, res: Response) { + const { id: articleId } = create(req.params, IdParamsStruct); + const { cursor, limit } = create(req.query, GetCommentListParamsStruct); + + const article = await prismaClient.article.findUnique({ where: { id: articleId } }); + if (!article) { + throw new NotFoundError('article', articleId); + } + + const commentsWithCursor = await prismaClient.comment.findMany({ + cursor: cursor ? { id: cursor } : undefined, + take: limit + 1, + where: { articleId }, + orderBy: { createdAt: 'desc' }, + }); + const comments = commentsWithCursor.slice(0, limit); + const cursorComment = commentsWithCursor[commentsWithCursor.length - 1]; + const nextCursor = cursorComment ? cursorComment.id : null; + + return res.send({ + list: comments, + nextCursor, + }); +} + +export async function createLike(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id: articleId } = create(req.params, IdParamsStruct); + + const existingArticle = await prismaClient.article.findUnique({ where: { id: articleId } }); + if (!existingArticle) { + throw new NotFoundError('article', articleId); + } + + const existingLike = await prismaClient.like.findFirst({ + where: { articleId, userId: req.user.id }, + }); + if (existingLike) { + throw new BadRequestError('Already liked'); + } + + await prismaClient.like.create({ data: { articleId, userId: req.user.id } }); + return res.status(201).send(); +} + +export async function deleteLike(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id: articleId } = create(req.params, IdParamsStruct); + + const existingArticle = await prismaClient.article.findUnique({ where: { id: articleId } }); + if (!existingArticle) { + throw new NotFoundError('article', articleId); + } + + const existingLike = await prismaClient.like.findFirst({ + where: { articleId, userId: req.user.id }, + }); + if (!existingLike) { + throw new BadRequestError('Not liked'); + } + + await prismaClient.like.delete({ where: { id: existingLike.id } }); + return res.status(204).send(); +} diff --git a/src/controllers/authController.ts b/src/controllers/authController.ts new file mode 100644 index 00000000..4a2078a8 --- /dev/null +++ b/src/controllers/authController.ts @@ -0,0 +1,91 @@ +import { create } from 'superstruct'; +import bcrypt from 'bcrypt'; +import { prismaClient } from '../lib/prismaClient.js'; +import { generateTokens, verifyRefreshToken } from '../lib/token.js'; +import { + ACCESS_TOKEN_COOKIE_NAME, + REFRESH_TOKEN_COOKIE_NAME, + NODE_ENV, +} from '../lib/constants.js'; +import { LoginBodyStruct, RegisterBodyStruct } from '../structs/authStructs.js'; +import BadRequestError from '../lib/errors/BadRequestError.js'; +import { Request, Response, NextFunction } from 'express'; + +export async function register(req: Request, res: Response) { + const { email, nickname, password } = create(req.body, RegisterBodyStruct); + + const salt = await bcrypt.genSalt(10); + const hashedPassword = await bcrypt.hash(password, salt); + + const isExist = await prismaClient.user.findUnique({ where: { email } }); + if (isExist) { + throw new BadRequestError('User already exists'); + } + + const user = await prismaClient.user.create({ + data: { email, nickname, password: hashedPassword }, + }); + + const { password: _, ...userWithoutPassword } = user; + res.status(201).json(userWithoutPassword); +} + +export async function login(req: Request, res: Response) { + const { email, password } = create(req.body, LoginBodyStruct); + + const user = await prismaClient.user.findUnique({ where: { email } }); + if (!user) { + throw new BadRequestError('Invalid credentials'); + } + + const isPasswordValid = await bcrypt.compare(password, user.password); + if (!isPasswordValid) { + throw new BadRequestError('Invalid credentials'); + } + + const { accessToken, refreshToken } = generateTokens(String(user?.id)); + setTokenCookies(res, accessToken, refreshToken); + res.status(200).send(); +} + +export async function logout(req: Request, res: Response) { + clearTokenCookies(res); + res.status(200).send(); +} + +export async function refreshToken(req: Request, res: Response) { + const refreshToken = req.cookies[REFRESH_TOKEN_COOKIE_NAME]; + if (!refreshToken) { + throw new BadRequestError('Invalid refresh token'); + } + + const { userId } = verifyRefreshToken(refreshToken); + + const user = await prismaClient.user.findUnique({ where: { id: Number(userId) } }); + if (!user) { + throw new BadRequestError('Invalid refresh token'); + } + + const { accessToken, refreshToken: newRefreshToken } = generateTokens(userId); + setTokenCookies(res, accessToken, newRefreshToken); + res.status(200).send(); +} + +function setTokenCookies(res: Response, accessToken: String, refreshToken: String) { + res.cookie(ACCESS_TOKEN_COOKIE_NAME, accessToken, { + httpOnly: true, + secure: NODE_ENV === 'production', + maxAge: 1 * 60 * 60 * 1000, // 1 hour + }); + res.cookie(REFRESH_TOKEN_COOKIE_NAME, refreshToken, { + httpOnly: true, + secure: NODE_ENV === 'production', + maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days + path: '/auth/refresh', + }); +} + +function clearTokenCookies(res: Response) { + res.clearCookie(ACCESS_TOKEN_COOKIE_NAME); + res.clearCookie(REFRESH_TOKEN_COOKIE_NAME); +} diff --git a/src/controllers/commentsController.ts b/src/controllers/commentsController.ts new file mode 100644 index 00000000..77cf8fb5 --- /dev/null +++ b/src/controllers/commentsController.ts @@ -0,0 +1,53 @@ +import { create } from 'superstruct'; +import { prismaClient } from '../lib/prismaClient.js'; +import { UpdateCommentBodyStruct } from '../structs/commentsStruct.js'; +import NotFoundError from '../lib/errors/NotFoundError.js'; +import { IdParamsStruct } from '../structs/commonStructs.js'; +import UnauthorizedError from '../lib/errors/UnauthorizedError.js'; +import ForbiddenError from '../lib/errors/ForbiddenError.js'; +import { Request, Response, NextFunction} from 'express' + +export async function updateComment(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id } = create(req.params, IdParamsStruct); + const { content } = create(req.body, UpdateCommentBodyStruct); + + const existingComment = await prismaClient.comment.findUnique({ where: { id } }); + if (!existingComment) { + throw new NotFoundError('comment', id); + } + + if (existingComment.userId !== req.user.id) { + throw new ForbiddenError('Should be the owner of the comment'); + } + + const updatedComment = await prismaClient.comment.update({ + where: { id }, + data: { content }, + }); + + +} + +export async function deleteComment(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id } = create(req.params, IdParamsStruct); + + const existingComment = await prismaClient.comment.findUnique({ where: { id } }); + if (!existingComment) { + throw new NotFoundError('comment', id); + } + + if (existingComment.userId !== req.user.id) { + throw new ForbiddenError('Should be the owner of the comment'); + } + + await prismaClient.comment.delete({ where: { id } }); + +} diff --git a/src/controllers/errorController.ts b/src/controllers/errorController.ts new file mode 100644 index 00000000..dbeeba2a --- /dev/null +++ b/src/controllers/errorController.ts @@ -0,0 +1,44 @@ +import { StructError } from 'superstruct'; +import BadRequestError from '../lib/errors/BadRequestError'; +import NotFoundError from '../lib/errors/NotFoundError.js'; +import UnauthorizedError from '../lib/errors/UnauthorizedError'; +import ForbiddenError from '../lib/errors/ForbiddenError'; +import { Request, Response, NextFunction } from 'express'; + +export function defaultNotFoundHandler(req: Request, res: Response, next: NextFunction) { + return res.status(404).send({ message: 'Not found' }); +} + +export function globalErrorHandler(err, req: Request, res: Response, next: NextFunction) { + /** From superstruct or application error */ + if (err instanceof StructError || err instanceof BadRequestError) { + return res.status(400).send({ message: err.message }); + } + + /** From express.json middleware */ + if (err instanceof SyntaxError && err.status === 400 && 'body' in err) { + return res.status(400).send({ message: 'Invalid JSON' }); + } + + /** Prisma error codes */ + if (err.code) { + console.error(err); + return res.status(500).send({ message: 'Failed to process data' }); + } + + /** Application errors */ + if (err instanceof NotFoundError) { + return res.status(404).send({ message: err.message }); + } + + if (err instanceof UnauthorizedError) { + return res.status(401).send({ message: err.message }); + } + + if (err instanceof ForbiddenError) { + return res.status(403).send({ message: err.message }); + } + + console.error(err); + return res.status(500).send({ message: 'Internal server error' }); +} diff --git a/src/controllers/imagesController.ts b/src/controllers/imagesController.ts new file mode 100644 index 00000000..9fc8e523 --- /dev/null +++ b/src/controllers/imagesController.ts @@ -0,0 +1,41 @@ +import multer from 'multer'; +import path from 'path'; +import { v4 as uuidv4 } from 'uuid'; +import { PUBLIC_PATH, STATIC_PATH } from '../lib/constants'; +import BadRequestError from '../lib/errors/BadRequestError'; +import { Request, Response, NextFunction} from 'express' +const ALLOWED_MIME_TYPES = ['image/png', 'image/jpeg', 'image/jpg']; +const FILE_SIZE_LIMIT = 5 * 1024 * 1024; + +export const upload = multer({ + storage: multer.diskStorage({ + destination(req, file, cb) { + cb(null, PUBLIC_PATH); + }, + filename(req, file, cb) { + const ext = path.extname(file.originalname); + const filename = `${uuidv4()}${ext}`; + cb(null, filename); + }, + }), + + limits: { + fileSize: FILE_SIZE_LIMIT, + }, + + fileFilter: function (req, file, cb) { + if (!ALLOWED_MIME_TYPES.includes(file.mimetype)) { + const err = new BadRequestError('Only png, jpeg, and jpg are allowed'); + return cb(err); + } + + cb(null, true); + }, +}); + +export async function uploadImage(req: Request, res: Response) { + const host = req.get('host'); + const filePath = path.join(host, STATIC_PATH, req.file.filename); + const url = `http://${filePath}`; + return res.send({ url }); +} diff --git a/src/controllers/productsController.ts b/src/controllers/productsController.ts new file mode 100644 index 00000000..37a4fd39 --- /dev/null +++ b/src/controllers/productsController.ts @@ -0,0 +1,226 @@ +import { create } from 'superstruct'; +import { prismaClient } from '../lib/prismaClient'; +import NotFoundError from '../lib/errors/NotFoundError'; +import { IdParamsStruct } from '../structs/commonStructs'; +import { + CreateProductBodyStruct, + GetProductListParamsStruct, + UpdateProductBodyStruct, +} from '../structs/productsStruct'; +import { CreateCommentBodyStruct, GetCommentListParamsStruct } from '../structs/commentsStruct.js'; +import UnauthorizedError from '../lib/errors/UnauthorizedError'; +import ForbiddenError from '../lib/errors/ForbiddenError'; +import BadRequestError from '../lib/errors/BadRequestError'; +import { Request, Response, NextFunction } from 'express'; +import { Prisma, PrismaClient } from '@prisma/client'; + +export async function createProduct(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const data = create(req.body, CreateProductBodyStruct); + + const createdProduct = await prismaClient.product.create({ + data: { + ...data, + userId: req.user.id, + }, + }); + + res.status(201).send(createdProduct); +} + +export async function getProduct(req: Request, res: Response) { + const { id } = create(req.params, IdParamsStruct); + + const product = await prismaClient.product.findUnique({ + where: { id }, + include: { favorites: true }, + }); + if (!product) { + throw new NotFoundError('product', id); + } + + const productWithFavorites = { + ...product, + favorites: undefined, + favoriteCount: product.favorites.length, + isFavorited: req.user + ? product.favorites.some((favorite) => favorite.userId === req.user?.id) + : undefined, + }; + + return res.send(productWithFavorites); +} + +export async function updateProduct(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id } = create(req.params, IdParamsStruct); + const { name, description, price, tags, images } = create(req.body, UpdateProductBodyStruct); + + const existingProduct = await prismaClient.product.findUnique({ where: { id } }); + if (!existingProduct) { + throw new NotFoundError('product', id); + } + + if (existingProduct.userId !== req.user.id) { + throw new ForbiddenError('Should be the owner of the product'); + } + + const updatedProduct = await prismaClient.product.update({ + where: { id }, + data: { + ...(name !== undefined && { name }), + ...(description !== undefined && { description }), + ...(price !== undefined && { price }), + ...(tags !== undefined && { tags }), + ...(images !== undefined && { images }), }, + }); + + return res.send(updatedProduct); +} + +export async function deleteProduct(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id } = create(req.params, IdParamsStruct); + const existingProduct = await prismaClient.product.findUnique({ where: { id } }); + + if (!existingProduct) { + throw new NotFoundError('product', id); + } + + if (existingProduct.userId !== req.user.id) { + throw new ForbiddenError('Should be the owner of the product'); + } + + await prismaClient.product.delete({ where: { id } }); + return res.status(204).send(); +} + +export async function getProductList(req: Request, res: Response) { + const { page, pageSize, orderBy, keyword } = create(req.query, GetProductListParamsStruct); + + const where: Prisma.ProductWhereInput = keyword + ? { + OR: [{ name: { contains: keyword } }, { description: { contains: keyword } }], + } + : {}; + + const totalCount = await prismaClient.product.count({ where }); + const products = await prismaClient.product.findMany({ + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: orderBy === 'recent' ? { id: 'desc' } : { id: 'asc' }, + where, + include: { + favorites: true, + }, + }); + + const productsWithFavorites = products.map((product) => ({ + ...product, + favorites: undefined, + favoriteCount: product.favorites.length, + isFavorited: req.user + ? product.favorites.some((favorite) => favorite.userId === req.user?.id) + : undefined, + })); + + return res.send({ + list: productsWithFavorites, + totalCount, + }); +} + +export async function createComment(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id: productId } = create(req.params, IdParamsStruct); + const { content } = create(req.body, CreateCommentBodyStruct); + + const existingProduct = await prismaClient.product.findUnique({ where: { id: productId } }); + if (!existingProduct) { + throw new NotFoundError('product', productId); + } + + const createdComment = await prismaClient.comment.create({ + data: { productId, content, userId: req.user.id }, + }); + + return res.status(201).send(createdComment); +} + +export async function getCommentList(req: Request, res: Response) { + const { id: productId } = create(req.params, IdParamsStruct); + const { cursor, limit } = create(req.query, GetCommentListParamsStruct); + + const existingProduct = await prismaClient.product.findUnique({ where: { id: productId } }); + if (!existingProduct) { + throw new NotFoundError('product', productId); + } + + const commentsWithCursorComment = await prismaClient.comment.findMany({ + where: {productId}, + take: limit + 1, + ...(cursor ? { cursor: { id: cursor }, skip: 1 } : {}), + orderBy: { id: 'asc' }, + }); + const comments = commentsWithCursorComment.slice(0, limit); + const cursorComment = commentsWithCursorComment[comments.length - 1]; + const nextCursor = cursorComment ? cursorComment.id : null; + + return res.send({ + list: comments, + nextCursor, + }); +} + +export async function createFavorite(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id: productId } = create(req.params, IdParamsStruct); + + const existingProduct = await prismaClient.product.findUnique({ where: { id: productId } }); + if (!existingProduct) { + throw new NotFoundError('product', productId); + } + + const existingFavorite = await prismaClient.favorite.findFirst({ + where: { productId, userId: req.user.id }, + }); + if (existingFavorite) { + throw new BadRequestError('Already favorited'); + } + + await prismaClient.favorite.create({ data: { productId, userId: req.user.id } }); + return res.status(201).send(); +} + +export async function deleteFavorite(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { id: productId } = create(req.params, IdParamsStruct); + + const existingFavorite = await prismaClient.favorite.findFirst({ + where: { productId, userId: req.user.id }, + }); + if (!existingFavorite) { + throw new BadRequestError('Not favorited'); + } + + await prismaClient.favorite.delete({ where: { id: existingFavorite.id } }); + return res.status(204).send(); +} diff --git a/src/controllers/usersController.ts b/src/controllers/usersController.ts new file mode 100644 index 00000000..98ccf82b --- /dev/null +++ b/src/controllers/usersController.ts @@ -0,0 +1,170 @@ +import { create } from 'superstruct'; +import bcrypt from 'bcrypt'; +import { prismaClient } from '../lib/prismaClient.js'; +import { + UpdateMeBodyStruct, + UpdatePasswordBodyStruct, + GetMyProductListParamsStruct, + GetMyFavoriteListParamsStruct, +} from '../structs/usersStructs.js'; +import NotFoundError from '../lib/errors/NotFoundError.js'; +import UnauthorizedError from '../lib/errors/UnauthorizedError.js'; +import { Request, Response, NextFunction} from 'express' + +export async function getMe(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const user = await prismaClient.user.findUnique({ where: { id: req.user.id } }); + if (!user) { + throw new NotFoundError('user', req.user.id); + } + + const { password: _, ...userWithoutPassword } = user; + return res.send(userWithoutPassword); +} + +export async function updateMe(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const data = create(req.body, UpdateMeBodyStruct); + + const updatedUser = await prismaClient.user.update({ + where: { id: req.user.id }, + data: { + ...(data.email !== undefined && { email: data.email }), + ...(data.nickname !== undefined && { nickname: data.nickname }), + ...(data.image !== undefined && { image: data.image }), + }, + }); + + const { password: _, ...userWithoutPassword } = updatedUser; + return res.status(200).send(userWithoutPassword); +} + +export async function updateMyPassword(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { password, newPassword } = create(req.body, UpdatePasswordBodyStruct); + + const user = await prismaClient.user.findUnique({ where: { id: req.user.id } }); + if (!user) { + throw new NotFoundError('user', req.user.id); + } + + const isPasswordValid = await bcrypt.compare(password, user.password); + if (!isPasswordValid) { + throw new UnauthorizedError('Invalid credentials'); + } + + const salt = await bcrypt.genSalt(10); + const hashedPassword = await bcrypt.hash(newPassword, salt); + + await prismaClient.user.update({ + where: { id: req.user.id }, + data: { password: hashedPassword }, + }); + + return res.status(200).send(); +} + +export async function getMyProductList(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { page, pageSize, orderBy, keyword } = create(req.query, GetMyProductListParamsStruct); + + const where = keyword + ? { + OR: [{ name: { contains: keyword } }, { description: { contains: keyword } }], + } + : {}; + const totalCount = await prismaClient.product.count({ + where: { + ...where, + userId: req.user.id, + }, + }); + const products = await prismaClient.product.findMany({ + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: orderBy === 'recent' ? { id: 'desc' } : { id: 'asc' }, + where: { + ...where, + userId: req.user.id, + }, + include: { + favorites: true, + }, + }); + + const productsWithFavorites = products.map((product) => ({ + ...product, + favorites: undefined, + favoriteCount: product.favorites.length, + isFavorited: product.favorites.some((favorite) => favorite.userId === req.user!.id), + })); + + return res.send({ + list: productsWithFavorites, + totalCount, + }); +} + +export async function getMyFavoriteList(req: Request, res: Response) { + if (!req.user) { + throw new UnauthorizedError('Unauthorized'); + } + + const { page, pageSize, orderBy, keyword } = create(req.query, GetMyFavoriteListParamsStruct); + + const where = keyword + ? { + OR: [{ name: { contains: keyword } }, { description: { contains: keyword } }], + } + : {}; + const totalCount = await prismaClient.product.count({ + where: { + ...where, + favorites: { + some: { + userId: req.user.id, + }, + }, + }, + }); + const products = await prismaClient.product.findMany({ + skip: (page - 1) * pageSize, + take: pageSize, + orderBy: orderBy === 'recent' ? { id: 'desc' } : { id: 'asc' }, + where: { + ...where, + favorites: { + some: { + userId: req.user.id, + }, + }, + }, + include: { + favorites: true, + }, + }); + + const productsWithFavorites = products.map((product) => ({ + ...product, + favorites: undefined, + favoriteCount: product.favorites.length, + isFavorited: true, + })); + + return res.send({ + list: productsWithFavorites, + totalCount, + }); +} diff --git a/src/lib/constants.ts b/src/lib/constants.ts new file mode 100644 index 00000000..80fbc829 --- /dev/null +++ b/src/lib/constants.ts @@ -0,0 +1,12 @@ +import dotenv from 'dotenv'; +dotenv.config(); + +export const ACCESS_TOKEN_COOKIE_NAME = 'access-token'; +export const REFRESH_TOKEN_COOKIE_NAME = 'refresh-token'; +export const DATABASE_URL = process.env.DATABASE_URL; +export const JWT_ACCESS_TOKEN_SECRET = process.env.JWT_ACCESS_TOKEN_SECRET; +export const JWT_REFRESH_TOKEN_SECRET = process.env.JWT_REFRESH_TOKEN_SECRET; +export const NODE_ENV = process.env.NODE_ENV || 'development'; +export const PORT = process.env.PORT || 3000; +export const PUBLIC_PATH = './public'; +export const STATIC_PATH = '/public'; diff --git a/src/lib/errors/BadRequestError.ts b/src/lib/errors/BadRequestError.ts new file mode 100644 index 00000000..4bafd09a --- /dev/null +++ b/src/lib/errors/BadRequestError.ts @@ -0,0 +1,8 @@ +class BadRequestError extends Error { + constructor(message: string) { + super(message); + this.name = 'BadRequestError'; + } +} + +export default BadRequestError; diff --git a/src/lib/errors/ForbiddenError.ts b/src/lib/errors/ForbiddenError.ts new file mode 100644 index 00000000..6091711c --- /dev/null +++ b/src/lib/errors/ForbiddenError.ts @@ -0,0 +1,8 @@ +class ForbiddenError extends Error { + constructor(message: string) { + super(message); + this.name = 'ForbiddenError'; + } +} + +export default ForbiddenError; diff --git a/src/lib/errors/NotFoundError.ts b/src/lib/errors/NotFoundError.ts new file mode 100644 index 00000000..8f27fc2f --- /dev/null +++ b/src/lib/errors/NotFoundError.ts @@ -0,0 +1,8 @@ +class NotFoundError extends Error { + constructor(modelName: string, id: string | number) { + super(`${modelName} with id ${id} not found`); + this.name = 'NotFoundError'; + } +} + +export default NotFoundError; diff --git a/src/lib/errors/UnauthorizedError.ts b/src/lib/errors/UnauthorizedError.ts new file mode 100644 index 00000000..980e8be4 --- /dev/null +++ b/src/lib/errors/UnauthorizedError.ts @@ -0,0 +1,8 @@ +class UnauthorizedError extends Error { + constructor(message: string) { + super(message); + this.name = 'UnauthorizedError'; + } +} + +export default UnauthorizedError; diff --git a/src/lib/prismaClient.ts b/src/lib/prismaClient.ts new file mode 100644 index 00000000..5e41d6fe --- /dev/null +++ b/src/lib/prismaClient.ts @@ -0,0 +1,3 @@ +import { PrismaClient } from '@prisma/client'; + +export const prismaClient = new PrismaClient(); diff --git a/src/lib/token.ts b/src/lib/token.ts new file mode 100644 index 00000000..d455f251 --- /dev/null +++ b/src/lib/token.ts @@ -0,0 +1,30 @@ +import jwt, { JwtPayload } from 'jsonwebtoken'; +import 'dotenv/config' + +const JWT_ACCESS_TOKEN_SECRET = process.env.JWT_ACCESS_TOKEN_SECRET as string; +const JWT_REFRESH_TOKEN_SECRET = process.env.JWT_REFRESH_TOKEN_SECRET as string; + +interface CustomJwtPayload extends JwtPayload { + id: string; +} + +export function generateTokens(userId: string) { + const accessToken = jwt.sign({ id: userId }, JWT_ACCESS_TOKEN_SECRET, { + expiresIn: '1h', + }); + const refreshToken = jwt.sign({ id: userId }, JWT_REFRESH_TOKEN_SECRET, { + expiresIn: '7d', + }); + return { accessToken, refreshToken }; +} + +export function verifyAccessToken(token: string) { + const decoded = jwt.verify(token, JWT_ACCESS_TOKEN_SECRET)as CustomJwtPayload; + return { userId: decoded.id }; +} + +export function verifyRefreshToken(token: string) { + const decoded = jwt.verify(token, JWT_REFRESH_TOKEN_SECRET) as CustomJwtPayload; + return { userId: decoded.id }; +} + \ No newline at end of file diff --git a/src/lib/withAsync.ts b/src/lib/withAsync.ts new file mode 100644 index 00000000..4530ff19 --- /dev/null +++ b/src/lib/withAsync.ts @@ -0,0 +1,13 @@ +import { Request, Response, NextFunction } from "express"; + +type asyncHandler = (req: Request, res: Response)=> Promise; + +export function withAsync(handler: asyncHandler) { + return async function (req: Request, res: Response, next: NextFunction) { + try { + await handler(req, res); + } catch (e) { + next(e); + } + }; +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 00000000..31236273 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,35 @@ +import express from 'express'; +import cors from 'cors'; +import path from 'path'; +import cookieParser from 'cookie-parser'; +import { PORT, PUBLIC_PATH, STATIC_PATH } from './lib/constants'; +import articlesRouter from './routers/articlesRouter'; +import productsRouter from './routers/productsRouter'; +import commentsRouter from './routers/commentsRouter'; +import imagesRouter from './routers/imagesRouter'; +import authRouter from './routers/authRouter'; +import usersRouter from './routers/usersRouter'; +import { defaultNotFoundHandler, globalErrorHandler } from './controllers/errorController'; + +const app = express(); + +app.use(cors()); +app.use(express.json()); +app.use(cookieParser()); +app.use(STATIC_PATH, express.static(path.resolve(process.cwd(), PUBLIC_PATH))); + +app.use('/articles', articlesRouter); +app.use('/products', productsRouter); +app.use('/comments', commentsRouter); +app.use('/images', imagesRouter); +app.use('/auth', authRouter); +app.use('/users', usersRouter); + +app.use(defaultNotFoundHandler); +app.use(globalErrorHandler); + +app.listen(PORT, () => { + console.log(`Server started on port ${PORT}`); +}); + + diff --git a/src/middlewares/authenticate.ts b/src/middlewares/authenticate.ts new file mode 100644 index 00000000..8f8240f9 --- /dev/null +++ b/src/middlewares/authenticate.ts @@ -0,0 +1,30 @@ +import { prismaClient } from '../lib/prismaClient'; +import { verifyAccessToken } from '../lib/token'; +import { ACCESS_TOKEN_COOKIE_NAME } from '../lib/constants'; +import { Request, Response, NextFunction } from 'express'; + +function authenticate(options = { optional: false }) { + return async (req: Request, res: Response, next: NextFunction) => { + const accessToken = req.cookies[ACCESS_TOKEN_COOKIE_NAME]; + if (!accessToken) { + if (options.optional) { + return next(); + } + return res.status(401).json({ message: 'Unauthorized' }); + } + + try { + const { userId } = verifyAccessToken(accessToken); + const user = await prismaClient.user.findUnique({ where: { id: userId } }); + req.user = user; + } catch (error) { + if (options.optional) { + return next(); + } + return res.status(401).json({ message: 'Unauthorized' }); + } + next(); + }; +} + +export default authenticate; diff --git a/src/routers/articlesRouter.ts b/src/routers/articlesRouter.ts new file mode 100644 index 00000000..71c23154 --- /dev/null +++ b/src/routers/articlesRouter.ts @@ -0,0 +1,28 @@ +import express from 'express'; +import { withAsync } from '../lib/withAsync'; +import { + createArticle, + getArticleList, + getArticle, + updateArticle, + deleteArticle, + createComment, + getCommentList, + createLike, + deleteLike, +} from '../controllers/articlesController'; +import authenticate from '../middlewares/authenticate'; + +const articlesRouter = express.Router(); + +articlesRouter.post('/', authenticate(), withAsync(createArticle)); +articlesRouter.get('/', authenticate({ optional: true }), withAsync(getArticleList)); +articlesRouter.get('/:id', authenticate({ optional: true }), withAsync(getArticle)); +articlesRouter.patch('/:id', authenticate(), withAsync(updateArticle)); +articlesRouter.delete('/:id', authenticate(), withAsync(deleteArticle)); +articlesRouter.post('/:id/comments', authenticate(), withAsync(createComment)); +articlesRouter.get('/:id/comments', withAsync(getCommentList)); +articlesRouter.post('/:id/likes', authenticate(), withAsync(createLike)); +articlesRouter.delete('/:id/likes', authenticate(), withAsync(deleteLike)); + +export default articlesRouter; diff --git a/src/routers/authRouter.ts b/src/routers/authRouter.ts new file mode 100644 index 00000000..f0650c29 --- /dev/null +++ b/src/routers/authRouter.ts @@ -0,0 +1,12 @@ +import express from 'express'; +import { register, login, logout, refreshToken } from '../controllers/authController'; +import { withAsync } from '../lib/withAsync'; + +const authRouter = express.Router(); + +authRouter.post('/register', withAsync(register)); +authRouter.post('/login', withAsync(login)); +authRouter.post('/logout', withAsync(logout)); +authRouter.post('/refresh', withAsync(refreshToken)); + +export default authRouter; diff --git a/src/routers/commentsRouter.ts b/src/routers/commentsRouter.ts new file mode 100644 index 00000000..f0da623c --- /dev/null +++ b/src/routers/commentsRouter.ts @@ -0,0 +1,11 @@ +import express from 'express'; +import { withAsync } from '../lib/withAsync'; +import { updateComment, deleteComment } from '../controllers/commentsController'; +import authenticate from '../middlewares/authenticate'; + +const commentsRouter = express.Router(); + +commentsRouter.patch('/:id', authenticate(), withAsync(updateComment)); +commentsRouter.delete('/:id', authenticate(), withAsync(deleteComment)); + +export default commentsRouter; diff --git a/src/routers/imagesRouter.ts b/src/routers/imagesRouter.ts new file mode 100644 index 00000000..163b87ce --- /dev/null +++ b/src/routers/imagesRouter.ts @@ -0,0 +1,9 @@ +import express from 'express'; +import { withAsync } from '../lib/withAsync.js'; +import { upload, uploadImage } from '../controllers/imagesController.js'; + +const imagesRouter = express.Router(); + +imagesRouter.post('/upload', upload.single('image'), withAsync(uploadImage)); + +export default imagesRouter; diff --git a/src/routers/productsRouter.ts b/src/routers/productsRouter.ts new file mode 100644 index 00000000..bd16e662 --- /dev/null +++ b/src/routers/productsRouter.ts @@ -0,0 +1,28 @@ +import express from 'express'; +import { withAsync } from '../lib/withAsync'; +import { + createProduct, + getProduct, + updateProduct, + deleteProduct, + getProductList, + createComment, + getCommentList, + createFavorite, + deleteFavorite, +} from '../controllers/productsController'; +import authenticate from '../middlewares/authenticate'; + +const productsRouter = express.Router(); + +productsRouter.post('/', authenticate(), withAsync(createProduct)); +productsRouter.get('/:id', authenticate({ optional: true }), withAsync(getProduct)); +productsRouter.patch('/:id', authenticate(), withAsync(updateProduct)); +productsRouter.delete('/:id', authenticate(), withAsync(deleteProduct)); +productsRouter.get('/', authenticate({ optional: true }), withAsync(getProductList)); +productsRouter.post('/:id/comments', authenticate(), withAsync(createComment)); +productsRouter.get('/:id/comments', withAsync(getCommentList)); +productsRouter.post('/:id/favorites', authenticate(), withAsync(createFavorite)); +productsRouter.delete('/:id/favorites', authenticate(), withAsync(deleteFavorite)); + +export default productsRouter; diff --git a/src/routers/usersRouter.ts b/src/routers/usersRouter.ts new file mode 100644 index 00000000..8c084ab0 --- /dev/null +++ b/src/routers/usersRouter.ts @@ -0,0 +1,20 @@ +import express from 'express'; +import { withAsync } from '../lib/withAsync.js'; +import { + getMe, + updateMe, + updateMyPassword, + getMyProductList, + getMyFavoriteList, +} from '../controllers/usersController.js'; +import authenticate from '../middlewares/authenticate.js'; + +const usersRouter = express.Router(); + +usersRouter.get('/me', authenticate(), withAsync(getMe)); +usersRouter.patch('/me', authenticate(), withAsync(updateMe)); +usersRouter.patch('/me/password', authenticate(), withAsync(updateMyPassword)); +usersRouter.get('/me/products', authenticate(), withAsync(getMyProductList)); +usersRouter.get('/me/favorites', authenticate(), withAsync(getMyFavoriteList)); + +export default usersRouter; diff --git a/src/structs/articlesStructs.ts b/src/structs/articlesStructs.ts new file mode 100644 index 00000000..36a49e4b --- /dev/null +++ b/src/structs/articlesStructs.ts @@ -0,0 +1,12 @@ +import { coerce, nonempty, nullable, object, partial, string } from 'superstruct'; +import { PageParamsStruct } from './commonStructs.js'; + +export const GetArticleListParamsStruct = PageParamsStruct; + +export const CreateArticleBodyStruct = object({ + title: coerce(nonempty(string()), string(), (value) => value.trim()), + content: nonempty(string()), + image: nullable(string()), +}); + +export const UpdateArticleBodyStruct = partial(CreateArticleBodyStruct); diff --git a/src/structs/authStructs.ts b/src/structs/authStructs.ts new file mode 100644 index 00000000..b211e181 --- /dev/null +++ b/src/structs/authStructs.ts @@ -0,0 +1,13 @@ +import { nonempty, object, string } from 'superstruct'; + +export const RegisterBodyStruct = object({ + email: nonempty(string()), + nickname: nonempty(string()), + password: nonempty(string()), +}); + +export const LoginBodyStruct = object({ + email: nonempty(string()), + password: nonempty(string()), +}); + diff --git a/src/structs/commentsStruct.ts b/src/structs/commentsStruct.ts new file mode 100644 index 00000000..9f93a0ec --- /dev/null +++ b/src/structs/commentsStruct.ts @@ -0,0 +1,10 @@ +import { nonempty, object, partial, string } from 'superstruct'; +import { CursorParamsStruct } from './commonStructs.js'; + +export const CreateCommentBodyStruct = object({ + content: nonempty(string()), +}); + +export const GetCommentListParamsStruct = CursorParamsStruct; + +export const UpdateCommentBodyStruct = partial(CreateCommentBodyStruct); diff --git a/src/structs/commonStructs.ts b/src/structs/commonStructs.ts new file mode 100644 index 00000000..605bfa9e --- /dev/null +++ b/src/structs/commonStructs.ts @@ -0,0 +1,22 @@ +import { coerce, integer, object, string, defaulted, optional, enums, nonempty } from 'superstruct'; + +/** Convert string to integer then validate it */ +const integerString = coerce(integer(), string(), (value) => parseInt(value)); + +export const IdParamsStruct = object({ + id: integerString, +}); + +export const PageParamsStruct = object({ + page: defaulted(integerString, 1), + pageSize: defaulted(integerString, 10), + orderBy: optional(enums(['recent'])), + keyword: optional(nonempty(string())), +}); + +export const CursorParamsStruct = object({ + cursor: defaulted(integerString, 0), + limit: defaulted(integerString, 10), + orderBy: optional(enums(['recent'])), + keyword: optional(nonempty(string())), +}); diff --git a/src/structs/productsStruct.ts b/src/structs/productsStruct.ts new file mode 100644 index 00000000..69d416cf --- /dev/null +++ b/src/structs/productsStruct.ts @@ -0,0 +1,14 @@ +import { coerce, partial, object, string, min, nonempty, array, integer } from 'superstruct'; +import { PageParamsStruct } from './commonStructs.js'; + +export const CreateProductBodyStruct = object({ + name: coerce(nonempty(string()), string(), (value) => value.trim()), + description: nonempty(string()), + price: min(integer(), 0), + tags: array(nonempty(string())), + images: array(nonempty(string())), +}); + +export const GetProductListParamsStruct = PageParamsStruct; + +export const UpdateProductBodyStruct = partial(CreateProductBodyStruct); diff --git a/src/structs/usersStructs.ts b/src/structs/usersStructs.ts new file mode 100644 index 00000000..28409568 --- /dev/null +++ b/src/structs/usersStructs.ts @@ -0,0 +1,19 @@ +import { nullable, object, partial, string } from 'superstruct'; +import { PageParamsStruct } from './commonStructs.js'; + +export const UpdateMeBodyStruct = partial( + object({ + email: string(), + nickname: string(), + image: nullable(string()), + }), +); + +export const UpdatePasswordBodyStruct = object({ + password: string(), + newPassword: string(), +}); + +export const GetMyProductListParamsStruct = PageParamsStruct; + +export const GetMyFavoriteListParamsStruct = PageParamsStruct; diff --git a/src/type/express.d.ts b/src/type/express.d.ts new file mode 100644 index 00000000..83688391 --- /dev/null +++ b/src/type/express.d.ts @@ -0,0 +1,12 @@ +declare global { + namespace Express { + interface Request { + user?: Omit | null; + + } + } +} + + + +export {}; \ No newline at end of file diff --git a/tests/test.http b/tests/test.http new file mode 100644 index 00000000..d15a9a7e --- /dev/null +++ b/tests/test.http @@ -0,0 +1,188 @@ +### 모든 Article 가져오기 +GET http://localhost:3000/articles?orderBy=recent + +### 새로운 Article 만들기 +POST http://localhost:3000/articles +Content-Type: application/json + +{ + "title": "새로운 Article", + "content": "이것은 새로운 Article의 내용입니다.", + "image": "https://example.com/image.jpg" +} + +### 특정 ID의 Article 가져오기 +GET http://localhost:3000/articles/1 + +### Article 업데이트하기 +PATCH http://localhost:3000/articles/1 +Content-Type: application/json + +{ + "title": "Article 업데이트", + "content": "이것은 업데이트된 내용입니다." +} + +### Article 삭제하기 +DELETE http://localhost:3000/articles/2 + +### Article 좋아요 테스트 +POST http://localhost:3000/articles/1/likes + +### Article 좋아요 취소 테스트 +DELETE http://localhost:3000/articles/1/likes + + + +### Article에 Comment 달기 테스트 +POST http://localhost:3000/articles/1/comments +Content-Type: application/json + +{ + "content": "이것은 Article에 대한 테스트 Comment입니다." +} + +### Article의 Comment 가져오기 테스트 +GET http://localhost:3000/articles/1/comments?limit=200 + +### Comment 업데이트 테스트 +PATCH http://localhost:3000/comments/1 +Content-Type: application/json + +{ + "content": "이것은 업데이트된 테스트 Comment입니다." +} + +### Comment 삭제 테스트 +DELETE http://localhost:3000/comments/1 + +### 새로운 Product 만들기 테스트 +POST http://localhost:3000/products +Content-Type: application/json + +{ + "name": "테스트 Product", + "description": "이것은 테스트 Product 설명입니다.", + "price": 100, + "tags": [], + "images": ["image1.png", "image2.png"] +} + +### 모든 Product 가져오기 테스트 +GET http://localhost:3000/products + +### 특정 ID의 Product 가져오기 테스트 +GET http://localhost:3000/products/1 + +### Product 업데이트하기 테스트 +PATCH http://localhost:3000/products/2 +Content-Type: application/json + +{ + "name": "업데이트된 테스트 Product", + "description": "이것은 업데이트된 테스트 Product 설명입니다.", + "price": 150, + "tags": ["업데이트", "Product"], + "images": ["업데이트된_image1.png"] +} + +### Product 삭제하기 테스트 +DELETE http://localhost:3000/products/2 + +### Product 좋아요 테스트 +POST http://localhost:3000/products/102/favorites + +### Product 좋아요 취소 테스트 +DELETE http://localhost:3000/products/1/favorites + + +### Product에 Comment 달기 테스트 +POST http://localhost:3000/products/1/comments +Content-Type: application/json + +{ + "content": "이것은 Product에 대한 테스트 Comment입니다." +} + +### Product의 Comment 가져오기 테스트 +GET http://localhost:3000/products/1/comments?limit=5 + + +### Product의 Comment 가져오기 테스트 (Cursor) +GET http://localhost:3000/products/1/comments?cursor=1&limit=5 + + +### Comment 업데이트하기 테스트 +PATCH http://localhost:3000/comments/2 +Content-Type: application/json + +{ + "content": "이것은 업데이트된 테스트 Comment입니다." +} + +### Comment 삭제하기 테스트 +DELETE http://localhost:3000/comments/2 + +### 이미지 업로드 테스트 +POST http://localhost:3000/images/upload +Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW + +------WebKitFormBoundary7MA4YWxkTrZu0gW +Content-Disposition: form-data; name="image"; filename="test.png" +Content-Type: image/png + +< ./test.png +------WebKitFormBoundary7MA4YWxkTrZu0gW-- + +### 회원가입 테스트 +POST http://localhost:3000/auth/register +Content-Type: application/json + +{ + + "email": "testuser@example.com", + "nickname": "testuser", + "password": "testpassword" +} + +### 로그인 테스트 +POST http://localhost:3000/auth/login +Content-Type: application/json + +{ + "email": "testuser@example.com", + "password": "testpassword" +} + +### 로그아웃 테스트 +POST http://localhost:3000/auth/logout + +### 토큰 갱신 테스트 +POST http://localhost:3000/auth/refresh + +### 내 정보 가져오기 테스트 +GET http://localhost:3000/users/me + +### 내 정보 업데이트 테스트 +PATCH http://localhost:3000/users/me +Content-Type: application/json + +{ + "nickname": "testuser-edit" +} + +### 내 비밀번호 업데이트 테스트 +PATCH http://localhost:3000/users/me/password +Content-Type: application/json + +{ + "password": "testpassword", + "newPassword": "newtestpassword" +} + +### 내 상품 목록 가져오기 테스트 +GET http://localhost:3000/users/me/products?page=1&pageSize=5 + +### 내 좋아요 목록 가져오기 테스트 +GET http://localhost:3000/users/me/favorites?page=1&pageSize=5 + diff --git a/tests/test.js b/tests/test.js new file mode 100644 index 00000000..8cd82dc8 --- /dev/null +++ b/tests/test.js @@ -0,0 +1,68 @@ +async function bulkArticleCreate() { + for (let i = 1; i <= 100; i++) { + await fetch(`http://localhost:3000/articles`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + title: `Article ${i}`, + content: `This is the content of article ${i}.`, + image: `https://example.com/image${i}.jpg`, + }), + }); + } +} + +async function bulkArticleCommentCreate(articleId) { + for (let i = 1; i <= 100; i++) { + await fetch(`http://localhost:3000/articles/${articleId}/comments`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + content: `This is the content of article ${articleId} comment${i}.`, + }), + }); + } +} + +async function bulkProductCreate() { + for (let i = 1; i <= 100; i++) { + await fetch(`http://localhost:3000/products`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + name: `Test Product ${i}`, + description: `This is a test product description ${i}.`, + price: 100, + tags: ['test', 'product'], + images: ['image1.png', 'image2.png'], + }), + }); + } +} + +async function bulkProductCommentCreate(productId) { + for (let i = 1; i <= 100; i++) { + await fetch(`http://localhost:3000/products/${productId}/comments`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + content: `This is the content of product ${productId} comment${i}.`, + }), + }); + } +} + +bulkArticleCreate(); +bulkArticleCommentCreate(1); +bulkArticleCommentCreate(2); +bulkProductCreate(); +bulkProductCommentCreate(1); +bulkProductCommentCreate(2); diff --git a/tests/test.png b/tests/test.png new file mode 100644 index 0000000000000000000000000000000000000000..35a7b5616a6b18773cb64d62627874b0bde02271 GIT binary patch literal 6066 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 Date: Sun, 18 Jan 2026 22:03:29 +0900 Subject: [PATCH 2/5] main --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index a860e403..c3fb047a 100644 --- a/package.json +++ b/package.json @@ -38,3 +38,5 @@ "dist" ] } + + From 4165f94f929381902277b827640771b7fcfaafe5 Mon Sep 17 00:00:00 2001 From: hadongwoo02 Date: Tue, 20 Jan 2026 16:45:55 +0900 Subject: [PATCH 3/5] =?UTF-8?q?[=ED=95=98=EB=8F=99=EC=9A=B0]=20sprint5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 7-sprint-mission | 1 + package.json | 2 ++ 2 files changed, 3 insertions(+) create mode 160000 7-sprint-mission diff --git a/7-sprint-mission b/7-sprint-mission new file mode 160000 index 00000000..33997959 --- /dev/null +++ b/7-sprint-mission @@ -0,0 +1 @@ +Subproject commit 33997959cc49d581bc459b52dc76cf42c99f0445 diff --git a/package.json b/package.json index c3fb047a..637b1868 100644 --- a/package.json +++ b/package.json @@ -40,3 +40,5 @@ } + + From 239055ba2c048adb6327196f840f8aa6b0acc611 Mon Sep 17 00:00:00 2001 From: hadongwoo02 Date: Tue, 20 Jan 2026 16:50:15 +0900 Subject: [PATCH 4/5] =?UTF-8?q?[=ED=95=98=EB=8F=99=EC=9A=B0]=20sprint5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/main.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/package.json b/package.json index 637b1868..c8f5384f 100644 --- a/package.json +++ b/package.json @@ -42,3 +42,4 @@ + diff --git a/src/main.ts b/src/main.ts index 31236273..75f27562 100644 --- a/src/main.ts +++ b/src/main.ts @@ -25,6 +25,7 @@ app.use('/images', imagesRouter); app.use('/auth', authRouter); app.use('/users', usersRouter); + app.use(defaultNotFoundHandler); app.use(globalErrorHandler); From 67983f7ee916f9aa098da899c718da4861122abe Mon Sep 17 00:00:00 2001 From: hadongwoo02 Date: Tue, 20 Jan 2026 17:03:26 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=EC=A0=9C=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index 75f27562..31236273 100644 --- a/src/main.ts +++ b/src/main.ts @@ -25,7 +25,6 @@ app.use('/images', imagesRouter); app.use('/auth', authRouter); app.use('/users', usersRouter); - app.use(defaultNotFoundHandler); app.use(globalErrorHandler);