From b1b7e97118465c28b1fc04a82e0f0652c4add58e Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Feb 2024 22:00:16 +0300 Subject: [PATCH 01/94] feat: add create group method This commit contains following changes: * GroupCreated in db/models. Represents group that creating from api * GroupMember - group member pepresentation with connected id, roles, and p> * GroupRole - role in group that has role code, name and description * Added ALL_PERMISSIONS_CODE - number that contain 31 true bit * Added logging in domain database manager * Fixed Typing and Linting --- src/auth/permissions.py | 3 + .../auto_increment_database_interface.py | 4 +- .../domain_router_database_manager.py | 4 +- src/db/models/annotations/__init__.py | 1 + src/db/models/annotations/validators.py | 20 +++++ src/db/models/group.py | 48 ++++++++++- src/db/mongo_manager.py | 7 +- src/routers/groups_router.py | 82 ++++++++++++++++++- 8 files changed, 159 insertions(+), 10 deletions(-) diff --git a/src/auth/permissions.py b/src/auth/permissions.py index aa36e4a..deccdda 100644 --- a/src/auth/permissions.py +++ b/src/auth/permissions.py @@ -1,6 +1,9 @@ """Global permissions enum""" import enum +ALL_PERMISSIONS_ROLE_CODE: int = 2 ** 31 - 1 +"""Number that contains all bits of permissions""" + class Permissions(enum.Enum): """Global Permissions enum""" diff --git a/src/db/helpers/auto_increment_database_interface.py b/src/db/helpers/auto_increment_database_interface.py index feeedb5..0693ef9 100644 --- a/src/db/helpers/auto_increment_database_interface.py +++ b/src/db/helpers/auto_increment_database_interface.py @@ -23,7 +23,9 @@ async def _insert_one_with_id(self, id for new created element """ - internal_database_collection = MongoManager.get_db().get_collection(self.__internal_collection_name) + internal_database_collection = MongoManager.get_db().get_collection( + self.__internal_collection_name + ) if internal_database_collection is None: raise ConnectionError("Database is not connected") diff --git a/src/db/managers/domain_router_database_manager.py b/src/db/managers/domain_router_database_manager.py index 764b70a..1cb9c74 100644 --- a/src/db/managers/domain_router_database_manager.py +++ b/src/db/managers/domain_router_database_manager.py @@ -1,6 +1,6 @@ """DomainRouterDatabaseManager definition""" from pymongo.errors import DuplicateKeyError - +from loguru import logger from config import Config from db.models.entity import Entity from db.helpers.abstract_database_manager import AbstractDatabaseManager @@ -54,6 +54,7 @@ async def reserve(self, domain: str) -> bool: try: await self.collection.insert_one(to_reserve.model_dump(by_alias=True)) + logger.info(f"Reserved entity <{domain}>") except DuplicateKeyError: return False @@ -80,3 +81,4 @@ async def delete(self, domain: str) -> None: domain: domain """ await self.collection.delete_one({"_id": domain}) + logger.info(f"Deleted entity <{domain}>") diff --git a/src/db/models/annotations/__init__.py b/src/db/models/annotations/__init__.py index 410f7f3..b355c6f 100644 --- a/src/db/models/annotations/__init__.py +++ b/src/db/models/annotations/__init__.py @@ -10,3 +10,4 @@ DescriptionAnnotation = Annotated[str, AfterValidator(validators.description_string)] RoleCodeAnnotation = Annotated[int, AfterValidator(validators.not_negative_number)] StrIdAnnotation = Annotated[str, AfterValidator(validators.string_id)] +StrIntIdAnnotation = Annotated[str, AfterValidator(validators.string_positive_number)] diff --git a/src/db/models/annotations/validators.py b/src/db/models/annotations/validators.py index a9c7f0a..eaa0a36 100644 --- a/src/db/models/annotations/validators.py +++ b/src/db/models/annotations/validators.py @@ -102,3 +102,23 @@ def string_id(string: str) -> str: if re.fullmatch(pattern, string) is None: raise ValueError("String is not valid") return string + + +def string_positive_number(string: str) -> str: + """ + Check if given string is a number and positive number + Args: + string: string to check + Returns: + string + Raises: + ValueError: if given string is not a positive number + """ + num = 0 + try: + num = int(string) + except Exception as e: + raise ValueError("string is not a number") from e + if num <= 0: + raise ValueError("String is not a positive number") + return string diff --git a/src/db/models/group.py b/src/db/models/group.py index 6b87726..5d1209d 100644 --- a/src/db/models/group.py +++ b/src/db/models/group.py @@ -1,12 +1,41 @@ """Group definition""" from pydantic import BaseModel, Field from db.models.annotations import IntIdAnnotation, NameAnnotation, DescriptionAnnotation, \ - DomainAnnotation + DomainAnnotation, RoleCodeAnnotation, StrIdAnnotation + + +class GroupRole(BaseModel): + """Group role""" + + id: StrIdAnnotation = Field(alias="_id") + """Group role id""" + + name: NameAnnotation + """Role name""" + + role_code: RoleCodeAnnotation + """role code""" + + description: DescriptionAnnotation = Field("") + """role description""" + + +class GroupMember(BaseModel): + """The user's access value generated by several fields""" + id: IntIdAnnotation = Field(alias="_id") + """Connected user id""" + + permissions: RoleCodeAnnotation + """Result role code, that represents final permissions""" + + roles: list[StrIdAnnotation] = Field([]) + """Roles, which member has""" class Group(BaseModel): """Group representation in database""" id: IntIdAnnotation = Field(alias='_id') + """Group id""" name: NameAnnotation """Group name""" @@ -17,11 +46,24 @@ class Group(BaseModel): domain: DomainAnnotation | None = Field(None) """Group domain""" - members: dict[int, tuple[int, list[str]]] = {} + members: list[GroupMember] = Field([]) """Group members""" owner: IntIdAnnotation """User ID of group owner""" - group_roles: dict[str, int] = Field({}) + roles: list[GroupRole] = Field([]) """List of names group roles in group""" + + +class GroupToCreate(BaseModel): + """Group to create template""" + + name: NameAnnotation + + description: DescriptionAnnotation = Field("") + + domain: DomainAnnotation | None = Field(None) + + members: list[IntIdAnnotation] = Field([]) + """Who will be in group""" diff --git a/src/db/mongo_manager.py b/src/db/mongo_manager.py index bf5f593..72374e7 100644 --- a/src/db/mongo_manager.py +++ b/src/db/mongo_manager.py @@ -1,19 +1,18 @@ """Core database mongo manager""" from loguru import logger -from motor.motor_asyncio import AsyncIOMotorClient +from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase from motor.core import AgnosticClient -from pymongo.database import Database class MongoManager: """The main class for communicate with database""" - _db: Database | None = None + _db: AsyncIOMotorDatabase | None = None _client: AgnosticClient | None = None @classmethod - def get_db(cls) -> Database: + def get_db(cls) -> AsyncIOMotorDatabase: """ Get database Returns: database diff --git a/src/routers/groups_router.py b/src/routers/groups_router.py index ce0bdea..d437947 100644 --- a/src/routers/groups_router.py +++ b/src/routers/groups_router.py @@ -1,4 +1,84 @@ """Groups endpoints""" -from fastapi import APIRouter +from typing import Any +from fastapi import APIRouter, Depends +from auth.utils import auth_user +from auth.permissions import Permissions, ALL_PERMISSIONS_ROLE_CODE +from utils.response_utils import get_error_response, get_response, get_response_model, \ + get_error_schema +from db.models.group import Group, GroupToCreate, GroupRole, GroupMember +from db.models.user import User +import db router = APIRouter() + + +@router.post( + "/create", + response_model=get_response_model(Group), + responses={ + 400: get_error_schema("Failed to create group") + } +) +async def create_group(group_to_create: GroupToCreate, + _current_user: User = Depends(auth_user( + Permissions.CREATE_GROUP + ))) -> Any: + """Creating new group""" + + # check existing for all members + for member_id in group_to_create.members: + member = await db.user.get(member_id) + if member is None: + return get_error_response("MEMBER_NOT_FOUND", data={ + "target_member_id": member_id + }) + + if group_to_create.domain is not None: + status = await db.domain.reserve(group_to_create.domain) + if status is False: + return get_error_response("DOMAIN_IN_USE") + + try: + members: list[GroupMember] = [] + + # creating start group roles + starter_roles: list[GroupRole] = [ + GroupRole( + _id="admin", + name="Admin", + description="Admin", + role_code=ALL_PERMISSIONS_ROLE_CODE + ) + ] # TODO: create here basic member role + + # generating members with roles + for member_id in group_to_create.members: + members.append( + GroupMember( + _id=member_id, + permissions=0, # TODO: add here basic member role + roles=[] + ) + ) + + # result group + group = Group( + _id=1, # not used + owner=_current_user.id, + name=group_to_create.name, + description=group_to_create.description, + domain=group_to_create.domain, + members=members, + roles=starter_roles + ) + + created_group_id = await db.group.insert_with_id(group) + + created_group = await db.group.get(created_group_id) + + return get_response(created_group) + + except Exception as e: + if group_to_create.domain is not None: + await db.domain.delete(group_to_create.domain) # if error occurs delete reserved entity + raise e From 863d90a71808528e0e5977097b858b1a80b17772 Mon Sep 17 00:00:00 2001 From: Spotika Date: Sat, 10 Feb 2024 19:23:59 +0300 Subject: [PATCH 02/94] addede a refresh methods and cross origins --- src/auth/models.py | 0 src/main.py | 16 ++++++++++++++ src/routers/auth_router.py | 41 +++++++++++++++++++++++++++++++++--- src/routers/groups_router.py | 2 ++ src/routers/users_router.py | 12 +++++++++++ 5 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/auth/models.py diff --git a/src/auth/models.py b/src/auth/models.py new file mode 100644 index 0000000..e69de29 diff --git a/src/main.py b/src/main.py index 3c012fe..e3a4891 100644 --- a/src/main.py +++ b/src/main.py @@ -2,6 +2,7 @@ from contextlib import asynccontextmanager from fastapi import FastAPI +from starlette.middleware.cors import CORSMiddleware from auth.utils import AuthException from utils.handlers import auth_exception_handler @@ -29,6 +30,21 @@ async def lifespan(_app: FastAPI): app = FastAPI(title=Config.app_title, debug=True, lifespan=lifespan) +origins = [ + "http://localhost", + "http://localhost:8080", + "http://localhost:5173", + "http://localhost:3000", +] + +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + # routers app.include_router(routers.users_router.router, prefix="/api/users") app.include_router(routers.auth_router.router, prefix="/api/auth") diff --git a/src/routers/auth_router.py b/src/routers/auth_router.py index 0804325..93fce20 100644 --- a/src/routers/auth_router.py +++ b/src/routers/auth_router.py @@ -1,20 +1,21 @@ """All auth methods and some useful stuff""" from typing import Literal -from fastapi import APIRouter import db from db.models.user import UserSignup, User from auth.utils import get_hashed_password -from auth.utils import verify_password, create_token +from auth.utils import verify_password, create_token, auth_user from auth.token_schema import TokenSchema from utils.response_utils import get_error_response, get_response_model, get_error_schema, \ get_response +from fastapi import APIRouter, Depends +from db.models.annotations import RoleCodeAnnotation router = APIRouter() -@router.post( +@router.get( "/signin", response_model=get_response_model(TokenSchema), responses={ @@ -86,3 +87,37 @@ async def signup(user: UserSignup): created_user = await db.user.get(created_user_id) return get_response(created_user) + + +@router.get( + "/refresh", + response_model=get_response_model(TokenSchema), + responses={ + 400: get_error_schema("Failed to refresh") + } +) +async def refresh_token(_current_user: User = Depends(auth_user())): + """Refresh tokens""" + + return get_response({ + "access_token": create_token(str(_current_user.id)), + "refresh_token": create_token(str(_current_user.id), False), + }) + +@router.get( + "/user_permissions", + responses={ + 400: get_error_schema("Failed to get user permissions") + } +) +async def user_permissions(_current_user: User = Depends(auth_user())) -> RoleCodeAnnotation: + """Get user permissions""" + + result_mask = 0 + + for role_name in _current_user.roles: + cur_role = await db.role.get(role_name) + if cur_role is not None: + result_mask |= cur_role.role_code + return result_mask + diff --git a/src/routers/groups_router.py b/src/routers/groups_router.py index d437947..7452da8 100644 --- a/src/routers/groups_router.py +++ b/src/routers/groups_router.py @@ -82,3 +82,5 @@ async def create_group(group_to_create: GroupToCreate, if group_to_create.domain is not None: await db.domain.delete(group_to_create.domain) # if error occurs delete reserved entity raise e + + diff --git a/src/routers/users_router.py b/src/routers/users_router.py index e49a840..566081e 100644 --- a/src/routers/users_router.py +++ b/src/routers/users_router.py @@ -70,3 +70,15 @@ async def delete_role(user_id: int, role_id: str, await db.user.delete_role(user_id, role_id) return get_response() + + +@router.get( + "/get_current", + response_model=get_response_model(User), + responses={ + 400: get_error_schema("Failed to retrieve current user") + } +) +async def get_current_user(_current_user: User = Depends(auth_user())): + """Get current user""" + return get_response(_current_user) \ No newline at end of file From 32760321f718948048f74a5710feed03be8c300c Mon Sep 17 00:00:00 2001 From: Spotika Date: Sun, 11 Feb 2024 13:16:02 +0300 Subject: [PATCH 03/94] added group methods that connected with frontend --- src/db/managers/group_database_manager.py | 9 ++++++ src/routers/groups_router.py | 17 ++++++++++ src/routers/users_router.py | 39 ++++++++++++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/db/managers/group_database_manager.py b/src/db/managers/group_database_manager.py index 7430a68..0b8f935 100644 --- a/src/db/managers/group_database_manager.py +++ b/src/db/managers/group_database_manager.py @@ -30,3 +30,12 @@ async def insert_with_id(self, group: Group) -> int: group: used document to insert """ return await self._insert_one_with_id(self.collection_name, group) + + async def get_all(self) -> list[Group]: + to_return = [] + cursor = self.collection.find({}) + async for group in cursor: + print(group) + to_return.append(Group(**group)) + + return to_return diff --git a/src/routers/groups_router.py b/src/routers/groups_router.py index 7452da8..443fb90 100644 --- a/src/routers/groups_router.py +++ b/src/routers/groups_router.py @@ -8,6 +8,7 @@ from db.models.group import Group, GroupToCreate, GroupRole, GroupMember from db.models.user import User import db +from db.models.annotations import IntIdAnnotation router = APIRouter() @@ -84,3 +85,19 @@ async def create_group(group_to_create: GroupToCreate, raise e +@router.get( + "/get", + response_model=Group, + responses={ + 400: get_error_schema("Failed to retreive group") + } +) +async def get_group(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())) -> Any: + """Retreive group by id""" + + group = await db.group.get(_id) + + if group is None: + return get_error_response("GROUP_NOT_FOUND") + + return get_response(group) diff --git a/src/routers/users_router.py b/src/routers/users_router.py index 566081e..ee86969 100644 --- a/src/routers/users_router.py +++ b/src/routers/users_router.py @@ -1,5 +1,8 @@ """Users endpoints""" +from typing import List, Any + from fastapi import APIRouter, Depends +from starlette.responses import JSONResponse from db.models.user import User import db @@ -7,6 +10,7 @@ get_response from auth.utils import auth_user from auth.utils import Permissions +from db.models.annotations import IntIdAnnotation router = APIRouter() @@ -81,4 +85,37 @@ async def delete_role(user_id: int, role_id: str, ) async def get_current_user(_current_user: User = Depends(auth_user())): """Get current user""" - return get_response(_current_user) \ No newline at end of file + return get_response(_current_user) + + +@router.get( + "/get_groups", + responses={ + 400: get_error_schema("Failed to retrieve groups") + } +) +async def get_groups( + _id: IntIdAnnotation, + _current_user: User = Depends(auth_user()) +) -> Any | IntIdAnnotation: + """Retrieve all groups thet has user""" + + user = await db.user.get(_id) + + if user is None: + return get_error_response("USER_NOT_FOUND") + + groups = await db.group.get_all() + + result = [] + + for group in groups: + if group.owner == _id: + result.append(group.id) + continue + for member in group.members: + if member.id == _id: + result.append(group.id) + break + + return get_response({"result": result}) From bbed78f7721d630aa6e37afb7e8af5b18d67ce65 Mon Sep 17 00:00:00 2001 From: Spotika Date: Sun, 11 Feb 2024 14:51:44 +0300 Subject: [PATCH 04/94] feat: added contest base model and database manager + create contest api method --- src/config.py | 1 + src/db/__init__.py | 2 + src/db/managers/contest_database_manager.py | 44 ++++++++++++++ src/db/managers/group_database_manager.py | 13 ++++ src/db/models/contest.py | 36 +++++++++++ src/db/models/group.py | 2 + src/main.py | 2 + src/routers/contests_router.py | 67 +++++++++++++++++++++ 8 files changed, 167 insertions(+) create mode 100644 src/db/managers/contest_database_manager.py create mode 100644 src/db/models/contest.py create mode 100644 src/routers/contests_router.py diff --git a/src/config.py b/src/config.py index b244a07..0af209d 100644 --- a/src/config.py +++ b/src/config.py @@ -49,6 +49,7 @@ class Collections: groups = os.environ.get("COLLECTION_GROUPS") or "" domain_router = os.environ.get("COLLECTION_DOMAIN") or "" internal_counters = os.environ.get("COLLECTION_INTERNAL_COUNTERS") or "" + contests = os.environ.get("COLLECTION_CONTESTS") or "" class Auth: """Data for auth system""" diff --git a/src/db/__init__.py b/src/db/__init__.py index 6618063..a9c3b1e 100644 --- a/src/db/__init__.py +++ b/src/db/__init__.py @@ -1,4 +1,5 @@ """Database interfaces for some parts of database""" +from db.managers.contest_database_manager import ContestDatabaseManager from db.managers.user_database_manager import UserDatabaseManager from db.managers.group_database_manager import GroupDatabaseManager from db.managers.domain_router_database_manager import DomainRouterDatabaseManager @@ -8,3 +9,4 @@ group: GroupDatabaseManager = GroupDatabaseManager() domain: DomainRouterDatabaseManager = DomainRouterDatabaseManager() role: RoleDatabaseManager = RoleDatabaseManager() +contest: ContestDatabaseManager = ContestDatabaseManager() diff --git a/src/db/managers/contest_database_manager.py b/src/db/managers/contest_database_manager.py new file mode 100644 index 0000000..7f2c956 --- /dev/null +++ b/src/db/managers/contest_database_manager.py @@ -0,0 +1,44 @@ +"""Contest database manager definition""" +from db.helpers.abstract_database_manager import AbstractDatabaseManager +from db.models.contest import Contest +from config import Config +from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface + + +class ContestDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): + """Database methods with groups""" + + collection_name = Config.Collections.contests + + async def get(self, _id: int) -> Contest | None: + """ + Getting group by id + Args: + _id: mongo object id + Returns: + Group object or None if not found + """ + group = await self.collection.find_one({"_id": _id}) + if group is None: + return None + return Contest(**group) + + async def insert_with_id(self, contest: Contest) -> int: + """ + Insert used with auto increment + Args: + contest: used document to insert + """ + return await self._insert_one_with_id(self.collection_name, contest) + + async def get_all(self) -> list[Contest]: + """ + Returns: returning all contest objects + """ + to_return = [] + cursor = self.collection.find({}) + async for group in cursor: + print(group) + to_return.append(Contest(**group)) + + return to_return diff --git a/src/db/managers/group_database_manager.py b/src/db/managers/group_database_manager.py index 0b8f935..276773e 100644 --- a/src/db/managers/group_database_manager.py +++ b/src/db/managers/group_database_manager.py @@ -3,6 +3,7 @@ from db.models.group import Group from config import Config from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface +from db.models.annotations import IntIdAnnotation class GroupDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): @@ -39,3 +40,15 @@ async def get_all(self) -> list[Group]: to_return.append(Group(**group)) return to_return + + async def add_contest(self, group_id: IntIdAnnotation, contest_id: IntIdAnnotation) -> None: + """ + Inserting new contest id in group contests + Args: + group_id: target group + contest_id: contest to insert + """ + await self.collection.update_one( + {"_id": group_id}, + {"$push": {"contests": contest_id}} + ) diff --git a/src/db/models/contest.py b/src/db/models/contest.py new file mode 100644 index 0000000..282c10d --- /dev/null +++ b/src/db/models/contest.py @@ -0,0 +1,36 @@ +"""Group definition""" +from pydantic import BaseModel, Field +from db.models.annotations import IntIdAnnotation, NameAnnotation, DescriptionAnnotation, \ + DomainAnnotation, RoleCodeAnnotation, StrIdAnnotation + + +class Contest(BaseModel): + """Group representation in database""" + id: IntIdAnnotation = Field(alias='_id') + """Group id""" + + name: NameAnnotation + """Group name""" + + description: DescriptionAnnotation = Field("") + """Group description""" + + domain: DomainAnnotation | None = Field(None) + """Group domain""" + + linked_group: IntIdAnnotation + """Linked group""" + + tasks: list[IntIdAnnotation] = Field([]) + + +class ContestToCreate(BaseModel): + """Group to create template""" + + name: NameAnnotation + + description: DescriptionAnnotation = Field("") + + domain: DomainAnnotation | None = Field(None) + + linked_group: IntIdAnnotation diff --git a/src/db/models/group.py b/src/db/models/group.py index 5d1209d..433d4bb 100644 --- a/src/db/models/group.py +++ b/src/db/models/group.py @@ -55,6 +55,8 @@ class Group(BaseModel): roles: list[GroupRole] = Field([]) """List of names group roles in group""" + contests: list[IntIdAnnotation] = Field([]) + class GroupToCreate(BaseModel): """Group to create template""" diff --git a/src/main.py b/src/main.py index e3a4891..e90576d 100644 --- a/src/main.py +++ b/src/main.py @@ -9,6 +9,7 @@ from config import Config import routers.auth_router from db.mongo_manager import MongoManager +import routers.contests_router @asynccontextmanager @@ -50,6 +51,7 @@ async def lifespan(_app: FastAPI): app.include_router(routers.auth_router.router, prefix="/api/auth") app.include_router(routers.roles_router.router, prefix="/api/roles") app.include_router(routers.groups_router.router, prefix="/api/groups") +app.include_router(routers.contests_router.router, prefix="/api/contests") # exception handlers app.add_exception_handler(AuthException, auth_exception_handler) diff --git a/src/routers/contests_router.py b/src/routers/contests_router.py new file mode 100644 index 0000000..a316edf --- /dev/null +++ b/src/routers/contests_router.py @@ -0,0 +1,67 @@ +"""Groups endpoints""" +from typing import Any +from fastapi import APIRouter, Depends +from auth.utils import auth_user +from auth.permissions import Permissions, ALL_PERMISSIONS_ROLE_CODE +from utils.response_utils import get_error_response, get_response, get_response_model, \ + get_error_schema +from db.models.contest import Contest, ContestToCreate +from db.models.user import User +import db + +router = APIRouter() + + +@router.post( + "/create", + response_model=get_response_model(Contest), + responses={ + 400: get_error_schema("Failed to create contest") + } +) +async def create_contest(contest_to_create: ContestToCreate, + _current_user: User = Depends(auth_user())) -> Any: + """Creating new contest""" + + # check existing for all members + + linked_group = await db.group.get(contest_to_create.linked_group) + + if linked_group is None: + return get_error_response("LINKED_GROUP_NOT_FOUND") + + if _current_user.id != linked_group.owner: + return get_error_response("USER_NOT_GROUP_OWNER", + status_code=401) # TODO: make group permissions and roles + + if contest_to_create.domain is not None: + status = await db.domain.reserve(contest_to_create.domain) + if status is False: + return get_error_response("DOMAIN_IN_USE") + + try: + + # result group + contest = Contest( + _id=1, # not used + name=contest_to_create.name, + description=contest_to_create.description, + domain=contest_to_create.domain, + linked_group=contest_to_create.linked_group, + tasks=[] + ) + + created_contest_id = await db.contest.insert_with_id(contest) + + await db.group.add_contest(contest.linked_group, created_contest_id) + + created_contest = await db.contest.get(created_contest_id) + + return get_response(created_contest) + + except Exception as e: + if contest_to_create.domain is not None: + await db.domain.delete( + contest_to_create.domain + ) # if error occurs delete reserved entity + raise e \ No newline at end of file From 231ee5aa94c259935d7baaa5acc6a82f77beefa4 Mon Sep 17 00:00:00 2001 From: Spotika Date: Sun, 11 Feb 2024 15:42:03 +0300 Subject: [PATCH 05/94] created new get contests in froup method --- src/routers/groups_router.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/routers/groups_router.py b/src/routers/groups_router.py index 443fb90..56b54e9 100644 --- a/src/routers/groups_router.py +++ b/src/routers/groups_router.py @@ -3,15 +3,19 @@ from fastapi import APIRouter, Depends from auth.utils import auth_user from auth.permissions import Permissions, ALL_PERMISSIONS_ROLE_CODE +from db.models.contest import Contest from utils.response_utils import get_error_response, get_response, get_response_model, \ get_error_schema from db.models.group import Group, GroupToCreate, GroupRole, GroupMember from db.models.user import User import db from db.models.annotations import IntIdAnnotation +from pydantic import BaseModel router = APIRouter() +class ListContests(BaseModel): + contests: list[Contest] @router.post( "/create", @@ -87,7 +91,7 @@ async def create_group(group_to_create: GroupToCreate, @router.get( "/get", - response_model=Group, + response_model=get_response_model(Group), responses={ 400: get_error_schema("Failed to retreive group") } @@ -101,3 +105,32 @@ async def get_group(_id: IntIdAnnotation, _current_user: User = Depends(auth_use return get_error_response("GROUP_NOT_FOUND") return get_response(group) + + +@router.get( + "/get_contests", + response_model=get_response_model(ListContests), + responses={ + 400: get_error_schema("Failed to retreive contests") + } +) +async def get_contests( + group_id: IntIdAnnotation, + _current_user: User = Depends(auth_user()) +) -> Any: + """Retreive contests by group id""" + + group = await db.group.get(group_id) + + if group is None: + return get_error_response("GROUP_NOT_FOUND") + + result = ListContests(contests=[]) + + for contest_id in group.contests: + contest = await db.contest.get(contest_id) + if contest is None: + continue + result.contests.append(contest) + + return get_response(result) \ No newline at end of file From 560afea24e9cf6efe412fb8591b37df74bf8eb04 Mon Sep 17 00:00:00 2001 From: Spotika Date: Mon, 12 Feb 2024 12:42:41 +0300 Subject: [PATCH 06/94] banana --- .gitignore | 1 + poetry.lock | 16 +++++++- pyproject.toml | 1 + src/db/managers/contest_database_manager.py | 11 +++--- src/routers/contests_router.py | 44 ++++++++++++++++++++- src/routers/groups_router.py | 6 ++- 6 files changed, 69 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 60da074..485ded3 100644 --- a/.gitignore +++ b/.gitignore @@ -176,3 +176,4 @@ main_config.env .ruff_cache run.sh test.sh +./data \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index e86c318..9eba1e1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -893,6 +893,20 @@ cryptography = ["cryptography (>=3.4.0)"] pycrypto = ["pyasn1", "pycrypto (>=2.6.0,<2.7.0)"] pycryptodome = ["pyasn1", "pycryptodome (>=3.3.1,<4.0.0)"] +[[package]] +name = "python-multipart" +version = "0.0.9" +description = "A streaming multipart parser for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"}, + {file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"}, +] + +[package.extras] +dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"] + [[package]] name = "rsa" version = "4.9" @@ -1108,4 +1122,4 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "f9c693a8cbb4124d0abb7c6ba6574079d0b9655cc1b84a6b78c3a4a98298679b" +content-hash = "1c25349f5865279c0d2b31e90bfd233bbb720313649929dda4884bc070212bbc" diff --git a/pyproject.toml b/pyproject.toml index ad45e15..24e9e7a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ pytest-asyncio = "^0.23.3" loguru = "^0.7.2" httpx = "^0.26.0" trio = "^0.24.0" +python-multipart = "^0.0.9" [tool.poetry.group.dev.dependencies] diff --git a/src/db/managers/contest_database_manager.py b/src/db/managers/contest_database_manager.py index 7f2c956..2ad558e 100644 --- a/src/db/managers/contest_database_manager.py +++ b/src/db/managers/contest_database_manager.py @@ -6,22 +6,22 @@ class ContestDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): - """Database methods with groups""" + """Database methods with contest""" collection_name = Config.Collections.contests async def get(self, _id: int) -> Contest | None: """ - Getting group by id + Getting contest by id Args: _id: mongo object id Returns: Group object or None if not found """ - group = await self.collection.find_one({"_id": _id}) - if group is None: + contest = await self.collection.find_one({"_id": _id}) + if contest is None: return None - return Contest(**group) + return Contest(**contest) async def insert_with_id(self, contest: Contest) -> int: """ @@ -38,7 +38,6 @@ async def get_all(self) -> list[Contest]: to_return = [] cursor = self.collection.find({}) async for group in cursor: - print(group) to_return.append(Contest(**group)) return to_return diff --git a/src/routers/contests_router.py b/src/routers/contests_router.py index a316edf..58f86d1 100644 --- a/src/routers/contests_router.py +++ b/src/routers/contests_router.py @@ -1,6 +1,9 @@ """Groups endpoints""" +import tempfile from typing import Any -from fastapi import APIRouter, Depends +from zipfile import ZipFile + +from fastapi import APIRouter, Depends, UploadFile from auth.utils import auth_user from auth.permissions import Permissions, ALL_PERMISSIONS_ROLE_CODE from utils.response_utils import get_error_response, get_response, get_response_model, \ @@ -8,6 +11,7 @@ from db.models.contest import Contest, ContestToCreate from db.models.user import User import db +from db.models.user import IntIdAnnotation router = APIRouter() @@ -55,6 +59,9 @@ async def create_contest(contest_to_create: ContestToCreate, await db.group.add_contest(contest.linked_group, created_contest_id) + if contest.domain is not None: + await db.domain.attach(contest.domain, "user", created_contest_id) + created_contest = await db.contest.get(created_contest_id) return get_response(created_contest) @@ -64,4 +71,37 @@ async def create_contest(contest_to_create: ContestToCreate, await db.domain.delete( contest_to_create.domain ) # if error occurs delete reserved entity - raise e \ No newline at end of file + raise e + + +@router.get( + "/get", + response_model=get_response_model(Contest), + responses={ + 400: get_error_schema("Failed to retrieve contest") + } +) +async def get_contest(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())) -> Any: + """Return a contest by id""" + + contest = await db.contest.get(_id) + + if contest is None: + return get_error_schema("CONTEST_NOT_FOUND") + + return get_response(contest) + + +@router.post( + "/add_task_by_zip" +) +async def add_task_by_zip(contest_id: IntIdAnnotation, task_archive: UploadFile): + """Add a task to contest by zip""" + + with tempfile.NamedTemporaryFile() as file_object: + # print(file_object.name) + with open(file_object.name, "wb") as file_object1: + file_object1.write(await task_archive.read()) + with ZipFile(file_object1.name, "r") as zip_file: + with zip_file.open("css/tokens.css", "r") as theme_file: + print(str(theme_file.read())) diff --git a/src/routers/groups_router.py b/src/routers/groups_router.py index 56b54e9..99aab6e 100644 --- a/src/routers/groups_router.py +++ b/src/routers/groups_router.py @@ -74,13 +74,17 @@ async def create_group(group_to_create: GroupToCreate, description=group_to_create.description, domain=group_to_create.domain, members=members, - roles=starter_roles + roles=starter_roles, + contests=[] ) created_group_id = await db.group.insert_with_id(group) created_group = await db.group.get(created_group_id) + if group.domain is not None: + await db.domain.attach(group.domain, "group", created_group_id) + return get_response(created_group) except Exception as e: From 33a1be35e79d0e9bfa8c04e76c1daa1cd3dd5146 Mon Sep 17 00:00:00 2001 From: Spotika Date: Mon, 12 Feb 2024 17:58:38 +0300 Subject: [PATCH 07/94] feat: added task creation and base model --- src/db/managers/task_database_manager.py | 74 ++++++++++++++++++++++++ src/db/models/task.py | 0 src/routers/tasks_router.py | 0 3 files changed, 74 insertions(+) create mode 100644 src/db/managers/task_database_manager.py create mode 100644 src/db/models/task.py create mode 100644 src/routers/tasks_router.py diff --git a/src/db/managers/task_database_manager.py b/src/db/managers/task_database_manager.py new file mode 100644 index 0000000..f54767c --- /dev/null +++ b/src/db/managers/task_database_manager.py @@ -0,0 +1,74 @@ +"""UserDatabaseManager definition""" +from db.helpers.abstract_database_manager import AbstractDatabaseManager +from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface +from db.models.user import User +from config import Config + + +class UserDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): + """Database methods to work with users""" + + collection_name = Config.Collections.users + + async def get(self, user_id: int) -> User | None: + """ + Getting user by id + Args: + user_id: the user id + + Returns: + User object or None, if not found + """ + + user = await self.collection.find_one({"_id": user_id}) + if user is None: + return None + return User(**user) + + async def get_by_email(self, email: str) -> User | None: + """ + Getting user by email + Args: + email: the email + + Returns: + User object or None, if not found + """ + + user = await self.collection.find_one({"email": email}) + if user is None: + return None + return User(**user) + + async def add_role(self, user_id: int, role_id: str) -> None: + """ + Adding role to user + Args: + user_id: the user + role_id: the role + """ + + await self.collection.update_one( + {"_id": user_id}, + {"$push": {"roles": role_id}} + ) + + async def delete_role(self, user_id: int, role_id: str) -> None: + """ + Deleting role to user + Args: + user_id: target user + role_id: role to delete + """ + await self.collection.update_one( + {"_id": user_id}, + {"$pull": {"roles": role_id}} + ) + + async def insert_with_id(self, user: User) -> int: + """ + Insert used with auto increment + Args: + user: used document to insert + """ + return await self._insert_one_with_id(self.collection_name, user) diff --git a/src/db/models/task.py b/src/db/models/task.py new file mode 100644 index 0000000..e69de29 diff --git a/src/routers/tasks_router.py b/src/routers/tasks_router.py new file mode 100644 index 0000000..e69de29 From a05266d93b8188076a64949da45a048e82d2cfae Mon Sep 17 00:00:00 2001 From: Spotika Date: Mon, 12 Feb 2024 17:58:38 +0300 Subject: [PATCH 08/94] feat: added task creation and base model --- src/auth/permissions.py | 2 +- src/config.py | 1 + src/db/__init__.py | 2 + src/db/managers/task_database_manager.py | 45 +++++++++++++++++++++++ src/db/models/task.py | 12 ++++++ src/main.py | 2 + src/routers/contests_router.py | 19 ++-------- src/routers/tasks_router.py | 47 ++++++++++++++++++++++++ 8 files changed, 114 insertions(+), 16 deletions(-) create mode 100644 src/db/managers/task_database_manager.py create mode 100644 src/db/models/task.py create mode 100644 src/routers/tasks_router.py diff --git a/src/auth/permissions.py b/src/auth/permissions.py index deccdda..550c8f6 100644 --- a/src/auth/permissions.py +++ b/src/auth/permissions.py @@ -11,4 +11,4 @@ class Permissions(enum.Enum): CREATE_GROUP = 1 CREATE_ROLE = 2 CHANGE_USER_ROLES = 3 - DELETE_USER = 4 + DELETE_USER = 4 \ No newline at end of file diff --git a/src/config.py b/src/config.py index 0af209d..0c29af2 100644 --- a/src/config.py +++ b/src/config.py @@ -50,6 +50,7 @@ class Collections: domain_router = os.environ.get("COLLECTION_DOMAIN") or "" internal_counters = os.environ.get("COLLECTION_INTERNAL_COUNTERS") or "" contests = os.environ.get("COLLECTION_CONTESTS") or "" + tasks = os.environ.get("COLLECTION_TASKS") or "" class Auth: """Data for auth system""" diff --git a/src/db/__init__.py b/src/db/__init__.py index a9c3b1e..9d8e58e 100644 --- a/src/db/__init__.py +++ b/src/db/__init__.py @@ -1,5 +1,6 @@ """Database interfaces for some parts of database""" from db.managers.contest_database_manager import ContestDatabaseManager +from db.managers.task_database_manager import TaskDatabaseManager from db.managers.user_database_manager import UserDatabaseManager from db.managers.group_database_manager import GroupDatabaseManager from db.managers.domain_router_database_manager import DomainRouterDatabaseManager @@ -10,3 +11,4 @@ domain: DomainRouterDatabaseManager = DomainRouterDatabaseManager() role: RoleDatabaseManager = RoleDatabaseManager() contest: ContestDatabaseManager = ContestDatabaseManager() +task: TaskDatabaseManager = TaskDatabaseManager() \ No newline at end of file diff --git a/src/db/managers/task_database_manager.py b/src/db/managers/task_database_manager.py new file mode 100644 index 0000000..474f92d --- /dev/null +++ b/src/db/managers/task_database_manager.py @@ -0,0 +1,45 @@ +"""UserDatabaseManager definition""" +from config import Config +from db.helpers.abstract_database_manager import AbstractDatabaseManager +from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface +from db.models.task import IntIdAnnotation +from db.models.task import Task +from db.models.annotations import NameAnnotation + + +class TaskDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): + """Database methods to work with users""" + + collection_name = Config.Collections.tasks + + async def get(self, task_id: IntIdAnnotation) -> Task | None: + """ + Getting user by id + Args: + task_id: the user id + + Returns: + User object or None, if not found + """ + + task = await self.collection.find_one({"_id": task_id}) + + if task is None: + return None + return Task(**task) + + async def insert_with_id(self, task: Task) -> int: + """ + Insert used with auto increment + Args: + task: used document to insert + """ + return await self._insert_one_with_id(self.collection_name, task) + + async def get_by_name(self, name: NameAnnotation) -> Task | None: + + task = await self.collection.find_one({"name": name}) + + if task is None: + return None + return Task(**task) diff --git a/src/db/models/task.py b/src/db/models/task.py new file mode 100644 index 0000000..5c47821 --- /dev/null +++ b/src/db/models/task.py @@ -0,0 +1,12 @@ +from pydantic import BaseModel, Field +from db.models.annotations import IntIdAnnotation, NameAnnotation + + +class Task(BaseModel): + """Task representation""" + + id: IntIdAnnotation = Field(alias='_id') + + name: NameAnnotation + + # TODO: add tags and other diff --git a/src/main.py b/src/main.py index e90576d..697cabf 100644 --- a/src/main.py +++ b/src/main.py @@ -10,6 +10,7 @@ import routers.auth_router from db.mongo_manager import MongoManager import routers.contests_router +import routers.tasks_router @asynccontextmanager @@ -52,6 +53,7 @@ async def lifespan(_app: FastAPI): app.include_router(routers.roles_router.router, prefix="/api/roles") app.include_router(routers.groups_router.router, prefix="/api/groups") app.include_router(routers.contests_router.router, prefix="/api/contests") +app.include_router(routers.tasks_router.router, prefix="/api/tasks") # exception handlers app.add_exception_handler(AuthException, auth_exception_handler) diff --git a/src/routers/contests_router.py b/src/routers/contests_router.py index 58f86d1..8f3c2a7 100644 --- a/src/routers/contests_router.py +++ b/src/routers/contests_router.py @@ -1,17 +1,19 @@ """Groups endpoints""" import tempfile from typing import Any -from zipfile import ZipFile from fastapi import APIRouter, Depends, UploadFile +from pydantic import BaseModel + from auth.utils import auth_user from auth.permissions import Permissions, ALL_PERMISSIONS_ROLE_CODE from utils.response_utils import get_error_response, get_response, get_response_model, \ get_error_schema from db.models.contest import Contest, ContestToCreate +from db.models.task import Task from db.models.user import User import db -from db.models.user import IntIdAnnotation +from db.models.annotations import NameAnnotation, IntIdAnnotation router = APIRouter() @@ -92,16 +94,3 @@ async def get_contest(_id: IntIdAnnotation, _current_user: User = Depends(auth_u return get_response(contest) -@router.post( - "/add_task_by_zip" -) -async def add_task_by_zip(contest_id: IntIdAnnotation, task_archive: UploadFile): - """Add a task to contest by zip""" - - with tempfile.NamedTemporaryFile() as file_object: - # print(file_object.name) - with open(file_object.name, "wb") as file_object1: - file_object1.write(await task_archive.read()) - with ZipFile(file_object1.name, "r") as zip_file: - with zip_file.open("css/tokens.css", "r") as theme_file: - print(str(theme_file.read())) diff --git a/src/routers/tasks_router.py b/src/routers/tasks_router.py new file mode 100644 index 0000000..7f61369 --- /dev/null +++ b/src/routers/tasks_router.py @@ -0,0 +1,47 @@ +import tempfile +from typing import Any + +from fastapi import APIRouter, Depends, UploadFile +from pydantic import BaseModel + +from auth.utils import auth_user +from utils.response_utils import get_error_response, get_response, get_response_model, \ + get_error_schema +from db.models.contest import Contest, ContestToCreate +from db.models.task import Task +from db.models.user import User +import db +from db.models.annotations import NameAnnotation, IntIdAnnotation + +router = APIRouter() + + +class AddTask(BaseModel): + created_task_id: IntIdAnnotation + + +@router.post( + "/create", + response_model=get_response_model(AddTask) +) +async def create_task(name: NameAnnotation, task_archive: UploadFile, _current_user: User = Depends( + auth_user() +)) -> Any: + """Add a task to contest by zip""" + + # TODO: add creating directory for tasks + # with tempfile.NamedTemporaryFile() as file_object: + # with open(file_object.name, "wb") as file_object1: + # file_object1.write(await task_archive.read()) + # with ZipFile(file_object1.name, "r") as zip_file: + # with zip_file.open("css/tokens.css", "r") as theme_file: + # print(str(theme_file.read())) + + # creating task object + task_to_create = Task( + _id=1, # not used + name=name + ) + created_task_id = await db.task.insert_with_id(task_to_create) + response = AddTask(created_task_id=created_task_id) + return get_response(response) From f249bd5db9bd383ef10b07a9a47b681b3ef5ff00 Mon Sep 17 00:00:00 2001 From: Spotika Date: Mon, 12 Feb 2024 20:20:07 +0300 Subject: [PATCH 09/94] feat: added more tasks methods --- data/problems/1/input.mdx | 3 ++ data/problems/1/legend.mdx | 5 +++ data/problems/1/notes.mdx | 3 ++ data/problems/1/output.mdx | 1 + data/problems/1/scoring.mdx | 13 ++++++ src/routers/tasks_router.py | 86 ++++++++++++++++++++++++++++++++++++- 6 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 data/problems/1/input.mdx create mode 100644 data/problems/1/legend.mdx create mode 100644 data/problems/1/notes.mdx create mode 100644 data/problems/1/output.mdx create mode 100644 data/problems/1/scoring.mdx diff --git a/data/problems/1/input.mdx b/data/problems/1/input.mdx new file mode 100644 index 0000000..0ea0f2c --- /dev/null +++ b/data/problems/1/input.mdx @@ -0,0 +1,3 @@ +В первой строке через пробел вводятся два натуральных числа $n$ и $k$ ($2 \leqslant k \leqslant n \leqslant 10^5$). + +Во второй строке вводится $n$ натуральных чисел через пробел $a_i$ ($1\leqslant a_i \leqslant 10^9$) --- вредности оленей. \ No newline at end of file diff --git a/data/problems/1/legend.mdx b/data/problems/1/legend.mdx new file mode 100644 index 0000000..70b8e77 --- /dev/null +++ b/data/problems/1/legend.mdx @@ -0,0 +1,5 @@ +Каждый год Санта собирает себе новую упряжку из оленей. Около его дома есть загон, где живут $n$ оленей. Санта заметил, что рождественские олени --- необычные волшебные животные, все они по-разному реагируют на команды погонщика. Потому он считает, что каждый $i$-й олень обладает некоторой \textit{вредностью} $a_i$, которая характеризуется натуральным числом. Запрягать волшебных животных в упряжку нужно определенным образом, чтобы они летели быстрее: необходимо расположить оленей в таком порядке, чтобы вредности соседних оленей отличались друг от друга как можно меньше. Санта хочет собрать упряжку из $k \leqslant n$ оленей. Помогите ему собрать самую лучшую упряжку. Более формально, из набора $a_1,\, a_2,\,\ldots,\,a_n$ требуется составить $k$-элемнтую последовательность $a_{i_1},\, a_{i_2},\,\ldots,\, a_{i_k}$ таким образом, чтобы сумма +$$ + S_{\text{min}} = \bigl | a_{i_2} - a_{i_1} \bigr | + \bigl | a_{i_3} - a_{i_2} \bigr | + \ldots + \bigl | a_{i_n} - a_{i_{n-1}} \bigr | +$$ +была минимальна. \ No newline at end of file diff --git a/data/problems/1/notes.mdx b/data/problems/1/notes.mdx new file mode 100644 index 0000000..92e1f1f --- /dev/null +++ b/data/problems/1/notes.mdx @@ -0,0 +1,3 @@ +В первом примере можно взять оленей со значениями вредности 1 и 2 или 4 и 5 (в любом порядке). + +В втором примере необходимо взять в упряжку оленей со значениями вредности 1, 3 и 3 в таком или обратном порядке. \ No newline at end of file diff --git a/data/problems/1/output.mdx b/data/problems/1/output.mdx new file mode 100644 index 0000000..8693dd8 --- /dev/null +++ b/data/problems/1/output.mdx @@ -0,0 +1 @@ +Выведите минимальную возможную сумму $S_{\text{min}}$. \ No newline at end of file diff --git a/data/problems/1/scoring.mdx b/data/problems/1/scoring.mdx new file mode 100644 index 0000000..3f5a927 --- /dev/null +++ b/data/problems/1/scoring.mdx @@ -0,0 +1,13 @@ +\begin{center} + \begin{tabular}{ | c | c | c | c | } \hline + \bf{Подгруппа} & + \bf{Доп. ограничения} & + \bf{Баллы} & + \bf{Требуемые подгруппы} \\ \hline + $0$ & тесты из условия & $0$ & --- \\ \hline + $1$ & $n \leqslant 100$, $k\leqslant 4$ & $10$ & --- \\ \hline + $2$ & $k = n$, $n \leqslant 100$ & $10$ & --- \\ \hline + $3$ & $k = n$ & $30$ & $2$ \\ \hline + $4$ & --- & $50$ & $1-3$ \\ \hline + \end{tabular} +\end{center} \ No newline at end of file diff --git a/src/routers/tasks_router.py b/src/routers/tasks_router.py index 7f61369..9ecb8ed 100644 --- a/src/routers/tasks_router.py +++ b/src/routers/tasks_router.py @@ -3,11 +3,11 @@ from fastapi import APIRouter, Depends, UploadFile from pydantic import BaseModel +from starlette.responses import FileResponse from auth.utils import auth_user from utils.response_utils import get_error_response, get_response, get_response_model, \ get_error_schema -from db.models.contest import Contest, ContestToCreate from db.models.task import Task from db.models.user import User import db @@ -45,3 +45,87 @@ async def create_task(name: NameAnnotation, task_archive: UploadFile, _current_u created_task_id = await db.task.insert_with_id(task_to_create) response = AddTask(created_task_id=created_task_id) return get_response(response) + + +@router.get( + "/get_legend" +) +async def get_task_legend(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): + """Retreive task legend""" + + try: + to_return = FileResponse(path=f'./data/problems/{_id}/legend.mdx', filename="legend.mdx", + media_type='multipart/form-data') + return to_return + except Exception: + return get_error_response("FILE_NOT_FOUND") + + +@router.get( + "/get_input" +) +async def get_task_input(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): + """Retreive task legend""" + + try: + to_return = FileResponse(path=f'./data/problems/{_id}/input.mdx', filename="input.mdx", + media_type='multipart/form-data') + return to_return + except Exception: + return get_error_response("FILE_NOT_FOUND") + + +@router.get( + "/get_output" +) +async def get_task_output(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): + """Retreive task legend""" + + try: + to_return = FileResponse(path=f'./data/problems/{_id}/output.mdx', filename="output.mdx", + media_type='multipart/form-data') + return to_return + except Exception: + return get_error_response("FILE_NOT_FOUND") + + +@router.get( + "/get_scoring" +) +async def get_task_scoring(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): + """Retreive task legend""" + + try: + to_return = FileResponse(path=f'./data/problems/{_id}/scoring.mdx', filename="scoring.mdx", + media_type='multipart/form-data') + return to_return + except Exception: + return get_error_response("FILE_NOT_FOUND") + + +@router.get( + "/get_notes" +) +async def get_notes(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): + """Retreive task legend""" + + try: + to_return = FileResponse(path=f'./data/problems/{_id}/notes.mdx', filename="notes.mdx", + media_type='multipart/form-data') + return to_return + except Exception: + return get_error_response("FILE_NOT_FOUND") + + +@router.get( + "/get_name" +) +async def get_name(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())) -> Any: + """Retreive task name by task id""" + + task = await db.task.get(_id) + + if task is None: + return get_error_response("TASK_NOT_FOUND") + + return task.name From b4ae14a87491056d1eb97c03f00e8ca739b66916 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 13 Feb 2024 10:15:32 +0300 Subject: [PATCH 10/94] feat: bananas --- data/problems/1/legend.mdx | 4 ++-- data/problems/1/scoring.mdx | 5 +++-- data/problems/2/input.mdx | 1 + data/problems/2/legend.mdx | 5 +++++ data/problems/2/notes.mdx | 1 + data/problems/2/output.mdx | 1 + data/problems/2/scoring.mdx | 3 +++ src/routers/tasks_router.py | 4 +++- 8 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 data/problems/2/input.mdx create mode 100644 data/problems/2/legend.mdx create mode 100644 data/problems/2/notes.mdx create mode 100644 data/problems/2/output.mdx create mode 100644 data/problems/2/scoring.mdx diff --git a/data/problems/1/legend.mdx b/data/problems/1/legend.mdx index 70b8e77..e3dbb03 100644 --- a/data/problems/1/legend.mdx +++ b/data/problems/1/legend.mdx @@ -1,5 +1,5 @@ -Каждый год Санта собирает себе новую упряжку из оленей. Около его дома есть загон, где живут $n$ оленей. Санта заметил, что рождественские олени --- необычные волшебные животные, все они по-разному реагируют на команды погонщика. Потому он считает, что каждый $i$-й олень обладает некоторой \textit{вредностью} $a_i$, которая характеризуется натуральным числом. Запрягать волшебных животных в упряжку нужно определенным образом, чтобы они летели быстрее: необходимо расположить оленей в таком порядке, чтобы вредности соседних оленей отличались друг от друга как можно меньше. Санта хочет собрать упряжку из $k \leqslant n$ оленей. Помогите ему собрать самую лучшую упряжку. Более формально, из набора $a_1,\, a_2,\,\ldots,\,a_n$ требуется составить $k$-элемнтую последовательность $a_{i_1},\, a_{i_2},\,\ldots,\, a_{i_k}$ таким образом, чтобы сумма +Каждый год Санта собирает себе новую упряжку из оленей. Около его дома есть загон, где живут $n$ оленей. Санта заметил, что рождественские олени --- необычные волшебные животные, все они по-разному реагируют на команды погонщика. Потому он считает, что каждый $i$-й олень обладает некоторой $\textit{вредностью}$ $a_i$, которая характеризуется натуральным числом. Запрягать волшебных животных в упряжку нужно определенным образом, чтобы они летели быстрее: необходимо расположить оленей в таком порядке, чтобы вредности соседних оленей отличались друг от друга как можно меньше. Санта хочет собрать упряжку из $k \leqslant n$ оленей. Помогите ему собрать самую лучшую упряжку. Более формально, из набора $a_1,\, a_2,\,\ldots,\,a_n$ требуется составить $k$-элемнтую последовательность $a_{i_1},\, a_{i_2},\,\ldots,\, a_{i_k}$ таким образом, чтобы сумма $$ - S_{\text{min}} = \bigl | a_{i_2} - a_{i_1} \bigr | + \bigl | a_{i_3} - a_{i_2} \bigr | + \ldots + \bigl | a_{i_n} - a_{i_{n-1}} \bigr | + S_{min} = \bigl | a_{i_2} - a_{i_1} \bigr | + \bigl | a_{i_3} - a_{i_2} \bigr | + \ldots + \bigl | a_{i_n} - a_{i_{n-1}} \bigr | $$ была минимальна. \ No newline at end of file diff --git a/data/problems/1/scoring.mdx b/data/problems/1/scoring.mdx index 3f5a927..62c21a3 100644 --- a/data/problems/1/scoring.mdx +++ b/data/problems/1/scoring.mdx @@ -1,4 +1,5 @@ -\begin{center} + +$$\begin{center} \begin{tabular}{ | c | c | c | c | } \hline \bf{Подгруппа} & \bf{Доп. ограничения} & @@ -10,4 +11,4 @@ $3$ & $k = n$ & $30$ & $2$ \\ \hline $4$ & --- & $50$ & $1-3$ \\ \hline \end{tabular} -\end{center} \ No newline at end of file +\end{center}$$ \ No newline at end of file diff --git a/data/problems/2/input.mdx b/data/problems/2/input.mdx new file mode 100644 index 0000000..7573c58 --- /dev/null +++ b/data/problems/2/input.mdx @@ -0,0 +1 @@ +В первой строке дано число $n$ ($0 \lt n \lt 2 * 10^5$). Во второй строке записано $n-1$ число - элементы перестановки $X$ без одного элемента ($0 \lt x_i \lt n + 1$). \ No newline at end of file diff --git a/data/problems/2/legend.mdx b/data/problems/2/legend.mdx new file mode 100644 index 0000000..95cd518 --- /dev/null +++ b/data/problems/2/legend.mdx @@ -0,0 +1,5 @@ +На день рождения Алене подарили перестановку $X$ длины $n$. Напомним, что перестановкой является упорядоченный набор из $n$ различных чисел от $1$ до $n$ (например, $\{1, 2, 3\}$ является перестановкой, а $\{1, 2, 4\}$ или $\{1, 2, 2\}$ - не является). + +К сожалению, когда Алена оставила свой подарок в комнате без присмотра, к нему подбежала собака Елань и съела одно число. + +Помогите Алене восстановить ее перестановку и узнать съеденное число, иначе получите ~тапочком по лицу~ реджект. \ No newline at end of file diff --git a/data/problems/2/notes.mdx b/data/problems/2/notes.mdx new file mode 100644 index 0000000..43b4bb9 --- /dev/null +++ b/data/problems/2/notes.mdx @@ -0,0 +1 @@ +Это тестовая задача, придуманная разработчиками тестирующей системы Elan. Она создана в Polygon и экспортирована в Elan. \ No newline at end of file diff --git a/data/problems/2/output.mdx b/data/problems/2/output.mdx new file mode 100644 index 0000000..588fc8b --- /dev/null +++ b/data/problems/2/output.mdx @@ -0,0 +1 @@ +Выведите число, которое съела Елань. \ No newline at end of file diff --git a/data/problems/2/scoring.mdx b/data/problems/2/scoring.mdx new file mode 100644 index 0000000..32adb5c --- /dev/null +++ b/data/problems/2/scoring.mdx @@ -0,0 +1,3 @@ +Потестовая оценка. В данной задаче используется 3 теста. Больше генерить мне было лень, да и зачем? Я верю, что вы легко справитесь с такой простой задачей. + +--- M F \ No newline at end of file diff --git a/src/routers/tasks_router.py b/src/routers/tasks_router.py index 9ecb8ed..93da021 100644 --- a/src/routers/tasks_router.py +++ b/src/routers/tasks_router.py @@ -56,8 +56,10 @@ async def get_task_legend(_id: IntIdAnnotation, _current_user: User = Depends(au try: to_return = FileResponse(path=f'./data/problems/{_id}/legend.mdx', filename="legend.mdx", media_type='multipart/form-data') + print(to_return) return to_return - except Exception: + except Exception as e: + print("Exception", e) return get_error_response("FILE_NOT_FOUND") From a12de07efbbbea647f9f936c6ffd3db4bef4b5e8 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 13 Feb 2024 19:24:45 +0300 Subject: [PATCH 11/94] refactor: change task to problem --- src/config.py | 3 +- src/db/__init__.py | 4 +- src/db/managers/contest_database_manager.py | 14 +++++++ src/db/managers/problem_database_manager.py | 42 +++++++++++++++++++ src/db/managers/task_database_manager.py | 42 ------------------- src/db/models/contest.py | 16 ++++++- src/db/models/{task.py => problem.py} | 4 +- src/main.py | 4 +- src/routers/contests_router.py | 29 +++++++++++-- .../{tasks_router.py => problems_router.py} | 10 ++--- 10 files changed, 110 insertions(+), 58 deletions(-) create mode 100644 src/db/managers/problem_database_manager.py delete mode 100644 src/db/managers/task_database_manager.py rename src/db/models/{task.py => problem.py} (78%) rename src/routers/{tasks_router.py => problems_router.py} (93%) diff --git a/src/config.py b/src/config.py index 0c29af2..3ba2ca0 100644 --- a/src/config.py +++ b/src/config.py @@ -50,7 +50,7 @@ class Collections: domain_router = os.environ.get("COLLECTION_DOMAIN") or "" internal_counters = os.environ.get("COLLECTION_INTERNAL_COUNTERS") or "" contests = os.environ.get("COLLECTION_CONTESTS") or "" - tasks = os.environ.get("COLLECTION_TASKS") or "" + problems = os.environ.get("COLLECTION_PROBLEMS") or "" class Auth: """Data for auth system""" @@ -62,3 +62,4 @@ class Auth: JWT_REFRESH_SECRET_KEY = os.environ.get("JWT_REFRESH_SECRET_KEY") or "" app_title = os.environ.get("APP_TITLE") or "" + elan_path = os.environ.get("ELAN_PATH") or "/ELAN" # FIXME NOT USED diff --git a/src/db/__init__.py b/src/db/__init__.py index 9d8e58e..6d0e014 100644 --- a/src/db/__init__.py +++ b/src/db/__init__.py @@ -1,6 +1,6 @@ """Database interfaces for some parts of database""" from db.managers.contest_database_manager import ContestDatabaseManager -from db.managers.task_database_manager import TaskDatabaseManager +from db.managers.problem_database_manager import ProblemDatabaseManager from db.managers.user_database_manager import UserDatabaseManager from db.managers.group_database_manager import GroupDatabaseManager from db.managers.domain_router_database_manager import DomainRouterDatabaseManager @@ -11,4 +11,4 @@ domain: DomainRouterDatabaseManager = DomainRouterDatabaseManager() role: RoleDatabaseManager = RoleDatabaseManager() contest: ContestDatabaseManager = ContestDatabaseManager() -task: TaskDatabaseManager = TaskDatabaseManager() \ No newline at end of file +problem: ProblemDatabaseManager = ProblemDatabaseManager() diff --git a/src/db/managers/contest_database_manager.py b/src/db/managers/contest_database_manager.py index 2ad558e..3e7e53f 100644 --- a/src/db/managers/contest_database_manager.py +++ b/src/db/managers/contest_database_manager.py @@ -3,6 +3,7 @@ from db.models.contest import Contest from config import Config from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface +from db.models.annotations import IntIdAnnotation class ContestDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): @@ -41,3 +42,16 @@ async def get_all(self) -> list[Contest]: to_return.append(Contest(**group)) return to_return + + async def add_problem(self, contest_id: IntIdAnnotation, problem_id: IntIdAnnotation) -> None: + """ + Adding problem to contest, with target contest id + Args: + contest_id: contest id + problem_id: problem id + """ + + await self.collection.find_one_and_update( + {"_id": contest_id}, + {"$push": {"problems": problem_id}} + ) diff --git a/src/db/managers/problem_database_manager.py b/src/db/managers/problem_database_manager.py new file mode 100644 index 0000000..ad2c31f --- /dev/null +++ b/src/db/managers/problem_database_manager.py @@ -0,0 +1,42 @@ +"""ProblemDatabaseManager definition""" +from config import Config +from db.helpers.abstract_database_manager import AbstractDatabaseManager +from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface +from db.models.problem import IntIdAnnotation +from db.models.problem import Problem +from db.models.annotations import NameAnnotation + + +class ProblemDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): + """Database methods to work with users""" + + collection_name = Config.Collections.problems + + async def get(self, problem: IntIdAnnotation) -> Problem | None: + """ + Getting user by id + Args: + problem: the user id + """ + + task = await self.collection.find_one({"_id": problem}) + + if task is None: + return None + return Problem(**task) + + async def insert_with_id(self, problem: Problem) -> int: + """ + Insert used with auto increment + Args: + problem: used document to insert + """ + return await self._insert_one_with_id(self.collection_name, problem) + + async def get_by_name(self, name: NameAnnotation) -> Problem | None: + + problem = await self.collection.find_one({"name": name}) + + if problem is None: + return None + return Problem(**problem) diff --git a/src/db/managers/task_database_manager.py b/src/db/managers/task_database_manager.py deleted file mode 100644 index 2fec434..0000000 --- a/src/db/managers/task_database_manager.py +++ /dev/null @@ -1,42 +0,0 @@ -"""UserDatabaseManager definition""" -from config import Config -from db.helpers.abstract_database_manager import AbstractDatabaseManager -from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface -from db.models.task import IntIdAnnotation -from db.models.task import Task -from db.models.annotations import NameAnnotation - - -class TaskDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): - """Database methods to work with users""" - - collection_name = Config.Collections.tasks - - async def get(self, task_id: IntIdAnnotation) -> Task | None: - """ - Getting user by id - Args: - task_id: the user id - """ - - task = await self.collection.find_one({"_id": task_id}) - - if task is None: - return None - return Task(**task) - - async def insert_with_id(self, task: Task) -> int: - """ - Insert used with auto increment - Args: - task: used document to insert - """ - return await self._insert_one_with_id(self.collection_name, task) - - async def get_by_name(self, name: NameAnnotation) -> Task | None: - - task = await self.collection.find_one({"name": name}) - - if task is None: - return None - return Task(**task) \ No newline at end of file diff --git a/src/db/models/contest.py b/src/db/models/contest.py index 282c10d..f142c98 100644 --- a/src/db/models/contest.py +++ b/src/db/models/contest.py @@ -1,9 +1,21 @@ """Group definition""" +from datetime import datetime + from pydantic import BaseModel, Field from db.models.annotations import IntIdAnnotation, NameAnnotation, DescriptionAnnotation, \ DomainAnnotation, RoleCodeAnnotation, StrIdAnnotation +class Submission(BaseModel): + """User submission""" + + # id: IntIdAnnotation = Field(alias="") + upload_time: datetime + code_text: str + status: str | None = None + target_problem_id: IntIdAnnotation + + class Contest(BaseModel): """Group representation in database""" id: IntIdAnnotation = Field(alias='_id') @@ -21,7 +33,9 @@ class Contest(BaseModel): linked_group: IntIdAnnotation """Linked group""" - tasks: list[IntIdAnnotation] = Field([]) + problems: list[IntIdAnnotation] = Field([]) + + submissions: list[Submission] = Field([]) class ContestToCreate(BaseModel): diff --git a/src/db/models/task.py b/src/db/models/problem.py similarity index 78% rename from src/db/models/task.py rename to src/db/models/problem.py index 5c47821..5aa58b5 100644 --- a/src/db/models/task.py +++ b/src/db/models/problem.py @@ -2,8 +2,8 @@ from db.models.annotations import IntIdAnnotation, NameAnnotation -class Task(BaseModel): - """Task representation""" +class Problem(BaseModel): + """Problem representation""" id: IntIdAnnotation = Field(alias='_id') diff --git a/src/main.py b/src/main.py index 697cabf..7d992a6 100644 --- a/src/main.py +++ b/src/main.py @@ -10,7 +10,7 @@ import routers.auth_router from db.mongo_manager import MongoManager import routers.contests_router -import routers.tasks_router +import routers.problems_router @asynccontextmanager @@ -53,7 +53,7 @@ async def lifespan(_app: FastAPI): app.include_router(routers.roles_router.router, prefix="/api/roles") app.include_router(routers.groups_router.router, prefix="/api/groups") app.include_router(routers.contests_router.router, prefix="/api/contests") -app.include_router(routers.tasks_router.router, prefix="/api/tasks") +app.include_router(routers.problems_router.router, prefix="/api/problems") # exception handlers app.add_exception_handler(AuthException, auth_exception_handler) diff --git a/src/routers/contests_router.py b/src/routers/contests_router.py index 8f3c2a7..2f500a0 100644 --- a/src/routers/contests_router.py +++ b/src/routers/contests_router.py @@ -10,7 +10,7 @@ from utils.response_utils import get_error_response, get_response, get_response_model, \ get_error_schema from db.models.contest import Contest, ContestToCreate -from db.models.task import Task +from db.models.problem import Problem from db.models.user import User import db from db.models.annotations import NameAnnotation, IntIdAnnotation @@ -26,7 +26,8 @@ } ) async def create_contest(contest_to_create: ContestToCreate, - _current_user: User = Depends(auth_user())) -> Any: + _current_user: User = Depends( + auth_user())) -> Any: # TODO: set permissions """Creating new contest""" # check existing for all members @@ -54,7 +55,7 @@ async def create_contest(contest_to_create: ContestToCreate, description=contest_to_create.description, domain=contest_to_create.domain, linked_group=contest_to_create.linked_group, - tasks=[] + problems=[] ) created_contest_id = await db.contest.insert_with_id(contest) @@ -94,3 +95,25 @@ async def get_contest(_id: IntIdAnnotation, _current_user: User = Depends(auth_u return get_response(contest) +@router.post( + "/add_problem", + response_model=get_response_model(), + responses={ + 400: get_error_schema("Failed to add task to contest") + } +) +async def add_problem_to_contest( + problem_id: IntIdAnnotation, + contest_id: IntIdAnnotation, + _current_user: User = Depends( + auth_user() +)) -> Any: + """Add a problem to contest""" + problem = await db.problem.get(problem_id) + + if problem is None: + return get_error_schema("PROBLEM_NOT_FOUND") + + await db.contest.add_problem(contest_id, problem_id) + + return get_response() diff --git a/src/routers/tasks_router.py b/src/routers/problems_router.py similarity index 93% rename from src/routers/tasks_router.py rename to src/routers/problems_router.py index 93da021..37c6762 100644 --- a/src/routers/tasks_router.py +++ b/src/routers/problems_router.py @@ -8,7 +8,7 @@ from auth.utils import auth_user from utils.response_utils import get_error_response, get_response, get_response_model, \ get_error_schema -from db.models.task import Task +from db.models.problem import Problem from db.models.user import User import db from db.models.annotations import NameAnnotation, IntIdAnnotation @@ -38,11 +38,11 @@ async def create_task(name: NameAnnotation, task_archive: UploadFile, _current_u # print(str(theme_file.read())) # creating task object - task_to_create = Task( + task_to_create = Problem( _id=1, # not used name=name ) - created_task_id = await db.task.insert_with_id(task_to_create) + created_task_id = await db.problem.insert_with_id(task_to_create) response = AddTask(created_task_id=created_task_id) return get_response(response) @@ -94,7 +94,7 @@ async def get_task_output(_id: IntIdAnnotation, _current_user: User = Depends(au @router.get( "/get_scoring" ) -async def get_task_scoring(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): +async def get_problem_scoring(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): """Retreive task legend""" try: @@ -125,7 +125,7 @@ async def get_notes(_id: IntIdAnnotation, _current_user: User = Depends(auth_use async def get_name(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())) -> Any: """Retreive task name by task id""" - task = await db.task.get(_id) + task = await db.problem.get(_id) if task is None: return get_error_response("TASK_NOT_FOUND") From 7a648fcf42835ffc3f5f83f8aaf6b0269ebcf5c8 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 14 Feb 2024 00:18:41 +0300 Subject: [PATCH 12/94] feat: added examples and submissions --- data/problems/problem1/example.01 | 2 + data/problems/problem1/example.01.a | 1 + data/problems/{1 => problem1}/input.mdx | 0 data/problems/{1 => problem1}/legend.mdx | 0 data/problems/{1 => problem1}/notes.mdx | 0 data/problems/{1 => problem1}/output.mdx | 0 data/problems/{1 => problem1}/scoring.mdx | 0 data/problems/problem2/example.01 | 2 + data/problems/problem2/example.01.a | 1 + data/problems/problem2/example.02 | 2 + data/problems/problem2/example.02.a | 1 + data/problems/{2 => problem2}/input.mdx | 0 data/problems/{2 => problem2}/legend.mdx | 0 data/problems/{2 => problem2}/notes.mdx | 0 data/problems/{2 => problem2}/output.mdx | 0 data/problems/{2 => problem2}/scoring.mdx | 0 .../contest1/submission10/solution.cpp | 1 + .../contest1/submission11/solution.cpp | 1 + .../contest1/submission12/solution.cpp | 1 + .../contest1/submission13/solution.cpp | 1 + .../contest1/submission14/solution.cpp | 1 + .../contest1/submission15/solution.cpp | 1 + .../contest1/submission16/solution.cpp | 377 ++++++++++++++++++ .../contest1/submission2/solution.cpp | 10 + .../contest1/submission3/solution.cpp | 1 + .../contest1/submission4/solution.cpp | 20 + .../contest1/submission5/solution.cpp | 20 + .../contest1/submission6/solution.cpp | 1 + .../contest1/submission7/solution.cpp | 1 + .../contest1/submission8/solution.cpp | 1 + .../contest1/submission9/solution.cpp | 1 + src/config.py | 1 + src/db/__init__.py | 2 + src/db/managers/problem_database_manager.py | 2 +- .../managers/submission_database_manager.py | 49 +++ src/db/models/submission.py | 26 ++ src/main.py | 2 + src/routers/problems_router.py | 90 +++-- src/routers/submissions_router.py | 63 +++ 39 files changed, 652 insertions(+), 30 deletions(-) create mode 100644 data/problems/problem1/example.01 create mode 100644 data/problems/problem1/example.01.a rename data/problems/{1 => problem1}/input.mdx (100%) rename data/problems/{1 => problem1}/legend.mdx (100%) rename data/problems/{1 => problem1}/notes.mdx (100%) rename data/problems/{1 => problem1}/output.mdx (100%) rename data/problems/{1 => problem1}/scoring.mdx (100%) create mode 100644 data/problems/problem2/example.01 create mode 100644 data/problems/problem2/example.01.a create mode 100644 data/problems/problem2/example.02 create mode 100644 data/problems/problem2/example.02.a rename data/problems/{2 => problem2}/input.mdx (100%) rename data/problems/{2 => problem2}/legend.mdx (100%) rename data/problems/{2 => problem2}/notes.mdx (100%) rename data/problems/{2 => problem2}/output.mdx (100%) rename data/problems/{2 => problem2}/scoring.mdx (100%) create mode 100644 data/submissions/contest1/submission10/solution.cpp create mode 100644 data/submissions/contest1/submission11/solution.cpp create mode 100644 data/submissions/contest1/submission12/solution.cpp create mode 100644 data/submissions/contest1/submission13/solution.cpp create mode 100644 data/submissions/contest1/submission14/solution.cpp create mode 100644 data/submissions/contest1/submission15/solution.cpp create mode 100644 data/submissions/contest1/submission16/solution.cpp create mode 100644 data/submissions/contest1/submission2/solution.cpp create mode 100644 data/submissions/contest1/submission3/solution.cpp create mode 100644 data/submissions/contest1/submission4/solution.cpp create mode 100644 data/submissions/contest1/submission5/solution.cpp create mode 100644 data/submissions/contest1/submission6/solution.cpp create mode 100644 data/submissions/contest1/submission7/solution.cpp create mode 100644 data/submissions/contest1/submission8/solution.cpp create mode 100644 data/submissions/contest1/submission9/solution.cpp create mode 100644 src/db/managers/submission_database_manager.py create mode 100644 src/db/models/submission.py create mode 100644 src/routers/submissions_router.py diff --git a/data/problems/problem1/example.01 b/data/problems/problem1/example.01 new file mode 100644 index 0000000..6911b80 --- /dev/null +++ b/data/problems/problem1/example.01 @@ -0,0 +1,2 @@ +5 +1 3 5 4 diff --git a/data/problems/problem1/example.01.a b/data/problems/problem1/example.01.a new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/data/problems/problem1/example.01.a @@ -0,0 +1 @@ +2 diff --git a/data/problems/1/input.mdx b/data/problems/problem1/input.mdx similarity index 100% rename from data/problems/1/input.mdx rename to data/problems/problem1/input.mdx diff --git a/data/problems/1/legend.mdx b/data/problems/problem1/legend.mdx similarity index 100% rename from data/problems/1/legend.mdx rename to data/problems/problem1/legend.mdx diff --git a/data/problems/1/notes.mdx b/data/problems/problem1/notes.mdx similarity index 100% rename from data/problems/1/notes.mdx rename to data/problems/problem1/notes.mdx diff --git a/data/problems/1/output.mdx b/data/problems/problem1/output.mdx similarity index 100% rename from data/problems/1/output.mdx rename to data/problems/problem1/output.mdx diff --git a/data/problems/1/scoring.mdx b/data/problems/problem1/scoring.mdx similarity index 100% rename from data/problems/1/scoring.mdx rename to data/problems/problem1/scoring.mdx diff --git a/data/problems/problem2/example.01 b/data/problems/problem2/example.01 new file mode 100644 index 0000000..1e5752d --- /dev/null +++ b/data/problems/problem2/example.01 @@ -0,0 +1,2 @@ +4 2 +1 5 2 4 diff --git a/data/problems/problem2/example.01.a b/data/problems/problem2/example.01.a new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/data/problems/problem2/example.01.a @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/data/problems/problem2/example.02 b/data/problems/problem2/example.02 new file mode 100644 index 0000000..d09a642 --- /dev/null +++ b/data/problems/problem2/example.02 @@ -0,0 +1,2 @@ +8 3 +3 10 7 9 3 7 15 1 diff --git a/data/problems/problem2/example.02.a b/data/problems/problem2/example.02.a new file mode 100644 index 0000000..d8263ee --- /dev/null +++ b/data/problems/problem2/example.02.a @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/data/problems/2/input.mdx b/data/problems/problem2/input.mdx similarity index 100% rename from data/problems/2/input.mdx rename to data/problems/problem2/input.mdx diff --git a/data/problems/2/legend.mdx b/data/problems/problem2/legend.mdx similarity index 100% rename from data/problems/2/legend.mdx rename to data/problems/problem2/legend.mdx diff --git a/data/problems/2/notes.mdx b/data/problems/problem2/notes.mdx similarity index 100% rename from data/problems/2/notes.mdx rename to data/problems/problem2/notes.mdx diff --git a/data/problems/2/output.mdx b/data/problems/problem2/output.mdx similarity index 100% rename from data/problems/2/output.mdx rename to data/problems/problem2/output.mdx diff --git a/data/problems/2/scoring.mdx b/data/problems/problem2/scoring.mdx similarity index 100% rename from data/problems/2/scoring.mdx rename to data/problems/problem2/scoring.mdx diff --git a/data/submissions/contest1/submission10/solution.cpp b/data/submissions/contest1/submission10/solution.cpp new file mode 100644 index 0000000..b8dc6c4 --- /dev/null +++ b/data/submissions/contest1/submission10/solution.cpp @@ -0,0 +1 @@ +this is for BANANA \ No newline at end of file diff --git a/data/submissions/contest1/submission11/solution.cpp b/data/submissions/contest1/submission11/solution.cpp new file mode 100644 index 0000000..9118d6c --- /dev/null +++ b/data/submissions/contest1/submission11/solution.cpp @@ -0,0 +1 @@ +asdasd \ No newline at end of file diff --git a/data/submissions/contest1/submission12/solution.cpp b/data/submissions/contest1/submission12/solution.cpp new file mode 100644 index 0000000..ed38c8a --- /dev/null +++ b/data/submissions/contest1/submission12/solution.cpp @@ -0,0 +1 @@ +// your code here! test test trest \ No newline at end of file diff --git a/data/submissions/contest1/submission13/solution.cpp b/data/submissions/contest1/submission13/solution.cpp new file mode 100644 index 0000000..9118d6c --- /dev/null +++ b/data/submissions/contest1/submission13/solution.cpp @@ -0,0 +1 @@ +asdasd \ No newline at end of file diff --git a/data/submissions/contest1/submission14/solution.cpp b/data/submissions/contest1/submission14/solution.cpp new file mode 100644 index 0000000..8898c3e --- /dev/null +++ b/data/submissions/contest1/submission14/solution.cpp @@ -0,0 +1 @@ +// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission15/solution.cpp b/data/submissions/contest1/submission15/solution.cpp new file mode 100644 index 0000000..ed38c8a --- /dev/null +++ b/data/submissions/contest1/submission15/solution.cpp @@ -0,0 +1 @@ +// your code here! test test trest \ No newline at end of file diff --git a/data/submissions/contest1/submission16/solution.cpp b/data/submissions/contest1/submission16/solution.cpp new file mode 100644 index 0000000..86bc8f6 --- /dev/null +++ b/data/submissions/contest1/submission16/solution.cpp @@ -0,0 +1,377 @@ +import {FC, useEffect, useState} from "react"; +import {useParams} from "react-router-dom"; +import { + Avatar, + Box, Button, + Stack, + SxProps, + ToggleButton, + ToggleButtonGroup, + Typography, + useTheme +} from "@mui/material"; +import {getCurrentUser, getWithToken, UserType} from "../../api/auth.tsx"; +import {ContestType, getContestById, getContestProblemsResources, sendSolution} from "../../api/api.tsx"; +import CheckIcon from "@mui/icons-material/Check"; +import ListAltIcon from '@mui/icons-material/ListAlt'; +import MenuIcon from '@mui/icons-material/Menu'; +import { Editor } from "@monaco-editor/react"; +import { ThemeModeContext } from "../../Theme/index.ts"; +import { useContext } from "react"; +import Latex from "react-latex-next"; + + +const ResultContent: FC = () => { + return
+ +
+} + + +type TaskResources = { + name: string, + legend: string, + input: string, + output: string, + scoring: string, + notes: string, + id: number +} + +type TasksProps = { + contest_id: any +} + +const TasksContent: FC = (props: TasksProps) => { + + const [tasksResources, setTasksResources] = useState([]); + const [taskText, setTaskText] = useState("test") + const theme = useTheme(); + const { toggleTheme, themeMode, setThemeMode } = useContext(ThemeModeContext); + + const [currentState, setCurrentState] = useState(0); + + const [statesNum, setStatesNum] = useState(0); + + const [navButtons, setNavButtons] = useState([]); + + const [code, setCode] = useState(["// your code here!"]) + + let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + const [editorState, setEditorState] = useState<"show" | "hide">("show") + + + useEffect(() => { + async function setup() { + const contestProblemsResources = await getContestProblemsResources(props.contest_id) + + + setStatesNum(contestProblemsResources.length) + let toChange = [] + for (let i = 0; i < contestProblemsResources.length; ++i) { + toChange.push( + + ) + } + setNavButtons(toChange); + setTasksResources(contestProblemsResources); + + let current_code = code; + while (current_code.length > contestProblemsResources.length) { + current_code.pop(); + } + + while (current_code.length < contestProblemsResources.length) { + current_code.push("// your code here!"); + } + + setCode(current_code); + } + + setup(); + + }, [currentState]); + + + const rootStyles: SxProps = { + padding: "40px", + height: "100%", + marginBottom: "40px" + } + + const navStyles: SxProps = { + display: "flex", + marginBottom: "30px", + overflow: "scroll", + justifyContent: "space-between" + } + + const taskStyles: SxProps = { + backgroundColor: `${theme.palette.surfaceContainerHigh.main}`, + borderRadius: "30px", + overflow: "scroll", + padding: "20px", + height: "100%", + paddingBottom: "150px", + display: "flex" + } + + + const handleChangeState = (e: any) => { + setCurrentState(e.target.value) + } + + + const handleSubmit = async () => { + const response = await sendSolution(props.contest_id, tasksResources[currentState].id, code[currentState]); + + if (response === undefined) { + alert("Error occured") + } else { + console.log(props.contest_id, tasksResources[currentState].id); + } + } + + // katex.render("c = \\pm\\sqrt{a^2 + b^2}", element, { + // throwOnError: false + // }); + + const handleEditorState = () => { + if (editorState == "show") { + setEditorState("hide") + } else { + setEditorState("show") + } + } + + return + + + {navButtons} + + + + + + + + + + {alphabet[currentState]}. {tasksResources[currentState]?.name} + + + + {tasksResources[currentState]?.legend|| ""} + + + + Формат входных данных + + + + {tasksResources[currentState]?.input || ""} + + + + Формат выходных данных + + + + {tasksResources[currentState]?.output || ""} + + + + Примечание + + + + {tasksResources[currentState]?.notes || ""} + + + + + + + { + let current_code = code; + current_code[currentState] = code_new; + setCode(current_code); + }} + /> + + + + + + + + +} + +const Contest: FC = () => { + + const [_user, setUser] = useState(); + const [contest, setContest] = useState(undefined); + + // const navigate = useNavigate(); + + const theme = useTheme(); + + const {id} = useParams(); + + + useEffect(() => { + async function temp() { + setUser(await getCurrentUser()); + // @ts-ignore + setContest(await getContestById(parseInt(id))); + } + + temp(); + }, []); + + const rootStyles: SxProps = { + borderRadius: "30px", + backgroundColor: `${theme.palette.surfaceContainerLow.main};`, + width: "100%", + minHeight: "100vh", + display: "flex", + position: "fixed", + // paddingBottom: "100px" + } + + const userStyles: SxProps = { + paddingTop: "80px", + display: "none", + flexDirection: "column", + alignItems: "center", + color: `${theme.palette.onSurface.main}`, + minWidth: "350px", + marginLeft: "30px" + } + + const navStyles: SxProps = { + width: "100%", + paddingLeft: "60px", + paddingRight: "300px", + flexGrow: "grow", + flexDirection: "column", + justifyContent: "center", + display: "flex", + position: "static" + } + + const avatarStyles = { + width: "300px", + height: "300px", + marginBottom: "10px" + } + + const navButtonsStyles: SxProps = { + width: "100%", + paddingBottom: "20px", + paddingTop: "20px" + } + + const dataStyles: SxProps = { + backgroundColor: `${theme.palette.surfaceContainerLowest.main}`, + borderRadius: "30px", + height: "100vh", + paddingBottom: "100px" + } + + const [alignment, setAlignment] = useState("tasks"); + + const [content, setContent] = useState(); + // + const handleAlignment = (_event: React.MouseEvent, + newAlignment: string) => { + if (newAlignment != null) { + setAlignment(newAlignment); + if (newAlignment == "tasks") { + setContent(); + } else if (newAlignment == "result") { + setContent(); + } + } + }; + + const nameStyles: SxProps = { + width: "300px", + whiteSpace: "pre-line", + wordWrap: "break-word", + overflow: "wrap" + } + + return <> + + + + + {contest?.name[0]}{contest?.name[1]} + + + + + {contest?.name} + + + + + {contest?.description} + + + + + + + + + {alignment === 'tasks' ? : } + Tasks + + + {alignment === "result" ? : } + Result + + + + + + {content} + {/* */} + + + + +} + + +export default Contest \ No newline at end of file diff --git a/data/submissions/contest1/submission2/solution.cpp b/data/submissions/contest1/submission2/solution.cpp new file mode 100644 index 0000000..d30e7a3 --- /dev/null +++ b/data/submissions/contest1/submission2/solution.cpp @@ -0,0 +1,10 @@ +#include + +using namespace std; + +int main() { + int n; + cin >> n; + cout << n; + return 0; +} diff --git a/data/submissions/contest1/submission3/solution.cpp b/data/submissions/contest1/submission3/solution.cpp new file mode 100644 index 0000000..30d74d2 --- /dev/null +++ b/data/submissions/contest1/submission3/solution.cpp @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/data/submissions/contest1/submission4/solution.cpp b/data/submissions/contest1/submission4/solution.cpp new file mode 100644 index 0000000..9a9e517 --- /dev/null +++ b/data/submissions/contest1/submission4/solution.cpp @@ -0,0 +1,20 @@ +#include +#include +using namespace std; + +int main() { + int n; + cin >> n; + + vector sp(n); + + for (int i = 0; i < n; ++i) { + cin >> sp[i]; + } + + for (int i = 0; i < n; ++i) { + cout << sp[i] << " "; + } + + return 0; +} \ No newline at end of file diff --git a/data/submissions/contest1/submission5/solution.cpp b/data/submissions/contest1/submission5/solution.cpp new file mode 100644 index 0000000..9a9e517 --- /dev/null +++ b/data/submissions/contest1/submission5/solution.cpp @@ -0,0 +1,20 @@ +#include +#include +using namespace std; + +int main() { + int n; + cin >> n; + + vector sp(n); + + for (int i = 0; i < n; ++i) { + cin >> sp[i]; + } + + for (int i = 0; i < n; ++i) { + cout << sp[i] << " "; + } + + return 0; +} \ No newline at end of file diff --git a/data/submissions/contest1/submission6/solution.cpp b/data/submissions/contest1/submission6/solution.cpp new file mode 100644 index 0000000..8898c3e --- /dev/null +++ b/data/submissions/contest1/submission6/solution.cpp @@ -0,0 +1 @@ +// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission7/solution.cpp b/data/submissions/contest1/submission7/solution.cpp new file mode 100644 index 0000000..8898c3e --- /dev/null +++ b/data/submissions/contest1/submission7/solution.cpp @@ -0,0 +1 @@ +// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission8/solution.cpp b/data/submissions/contest1/submission8/solution.cpp new file mode 100644 index 0000000..8898c3e --- /dev/null +++ b/data/submissions/contest1/submission8/solution.cpp @@ -0,0 +1 @@ +// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission9/solution.cpp b/data/submissions/contest1/submission9/solution.cpp new file mode 100644 index 0000000..8898c3e --- /dev/null +++ b/data/submissions/contest1/submission9/solution.cpp @@ -0,0 +1 @@ +// your code here! \ No newline at end of file diff --git a/src/config.py b/src/config.py index 3ba2ca0..77914f3 100644 --- a/src/config.py +++ b/src/config.py @@ -51,6 +51,7 @@ class Collections: internal_counters = os.environ.get("COLLECTION_INTERNAL_COUNTERS") or "" contests = os.environ.get("COLLECTION_CONTESTS") or "" problems = os.environ.get("COLLECTION_PROBLEMS") or "" + submissions = os.environ.get("COLLECTION_SUBMISSIONS") or "" class Auth: """Data for auth system""" diff --git a/src/db/__init__.py b/src/db/__init__.py index 6d0e014..6d67ea7 100644 --- a/src/db/__init__.py +++ b/src/db/__init__.py @@ -1,6 +1,7 @@ """Database interfaces for some parts of database""" from db.managers.contest_database_manager import ContestDatabaseManager from db.managers.problem_database_manager import ProblemDatabaseManager +from db.managers.submission_database_manager import SubmissionDatabaseManager from db.managers.user_database_manager import UserDatabaseManager from db.managers.group_database_manager import GroupDatabaseManager from db.managers.domain_router_database_manager import DomainRouterDatabaseManager @@ -12,3 +13,4 @@ role: RoleDatabaseManager = RoleDatabaseManager() contest: ContestDatabaseManager = ContestDatabaseManager() problem: ProblemDatabaseManager = ProblemDatabaseManager() +submission: SubmissionDatabaseManager = SubmissionDatabaseManager() diff --git a/src/db/managers/problem_database_manager.py b/src/db/managers/problem_database_manager.py index ad2c31f..be407a2 100644 --- a/src/db/managers/problem_database_manager.py +++ b/src/db/managers/problem_database_manager.py @@ -8,7 +8,7 @@ class ProblemDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): - """Database methods to work with users""" + """Database methods to work with problems""" collection_name = Config.Collections.problems diff --git a/src/db/managers/submission_database_manager.py b/src/db/managers/submission_database_manager.py new file mode 100644 index 0000000..50fe4d9 --- /dev/null +++ b/src/db/managers/submission_database_manager.py @@ -0,0 +1,49 @@ +"""SubmissionatabaseManager definition""" +from config import Config +from db.helpers.abstract_database_manager import AbstractDatabaseManager +from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface +from db.models.problem import IntIdAnnotation +from db.models.submission import Submission + + +class SubmissionDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): + """Database manager to work with submissions""" + + collection_name = Config.Collections.submissions + + async def get(self, submission_id: IntIdAnnotation) -> Submission | None: + """ + Getting submission by id + Args: + submission_id: the submission id + """ + + submission = await self.collection.find_one({"_id": submission_id}) + + if submission is None: + return None + return Submission(**submission) + + async def insert_with_id(self, submission: Submission) -> int: + """ + Insert submission with auto increment + Args: + submission: submission document to insert + """ + return await self._insert_one_with_id(self.collection_name, submission) + + async def attach_solution_path( + self, + submission_id: IntIdAnnotation, + solution_path: str + ) -> None: + """ + Attaching source code to submission + Args: + submission_id: submission id + solution_path: the source code path + """ + + await self.collection.update_one({"_id": submission_id}, {"$set": { + "solution_path": solution_path + }}) diff --git a/src/db/models/submission.py b/src/db/models/submission.py new file mode 100644 index 0000000..71bb46e --- /dev/null +++ b/src/db/models/submission.py @@ -0,0 +1,26 @@ +from pydantic import BaseModel, Field +from db.models.annotations import IntIdAnnotation + + +class SubmissionToCreate(BaseModel): + + problem_id: IntIdAnnotation + + contest_id: IntIdAnnotation + + solution: str + + +class Submission(BaseModel): + + id: IntIdAnnotation = Field(alias="_id") + + problem_id: IntIdAnnotation + + contest_id: IntIdAnnotation + + user_id: IntIdAnnotation + + solution_path: str | None = None + + status: str | None = None diff --git a/src/main.py b/src/main.py index 7d992a6..7926309 100644 --- a/src/main.py +++ b/src/main.py @@ -11,6 +11,7 @@ from db.mongo_manager import MongoManager import routers.contests_router import routers.problems_router +import routers.submissions_router @asynccontextmanager @@ -54,6 +55,7 @@ async def lifespan(_app: FastAPI): app.include_router(routers.groups_router.router, prefix="/api/groups") app.include_router(routers.contests_router.router, prefix="/api/contests") app.include_router(routers.problems_router.router, prefix="/api/problems") +app.include_router(routers.submissions_router.router, prefix="/api/submissions") # exception handlers app.add_exception_handler(AuthException, auth_exception_handler) diff --git a/src/routers/problems_router.py b/src/routers/problems_router.py index 37c6762..9e18b1a 100644 --- a/src/routers/problems_router.py +++ b/src/routers/problems_router.py @@ -12,49 +12,52 @@ from db.models.user import User import db from db.models.annotations import NameAnnotation, IntIdAnnotation +from config import Config + +import os router = APIRouter() -class AddTask(BaseModel): - created_task_id: IntIdAnnotation +class Addproblem(BaseModel): + created_problem_id: IntIdAnnotation @router.post( "/create", - response_model=get_response_model(AddTask) + response_model=get_response_model(Addproblem) ) -async def create_task(name: NameAnnotation, task_archive: UploadFile, _current_user: User = Depends( +async def create_problem(name: NameAnnotation, problem_archive: UploadFile, _current_user: User = Depends( auth_user() )) -> Any: - """Add a task to contest by zip""" + """Add a problem to contest by zip""" - # TODO: add creating directory for tasks + # TODO: add creating directory for problems # with tempfile.NamedTemporaryFile() as file_object: # with open(file_object.name, "wb") as file_object1: - # file_object1.write(await task_archive.read()) + # file_object1.write(await problem_archive.read()) # with ZipFile(file_object1.name, "r") as zip_file: # with zip_file.open("css/tokens.css", "r") as theme_file: # print(str(theme_file.read())) - # creating task object - task_to_create = Problem( + # creating problem object + problem_to_create = Problem( _id=1, # not used name=name ) - created_task_id = await db.problem.insert_with_id(task_to_create) - response = AddTask(created_task_id=created_task_id) + created_problem_id = await db.problem.insert_with_id(problem_to_create) + response = Addproblem(created_problem_id=created_problem_id) return get_response(response) @router.get( "/get_legend" ) -async def get_task_legend(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): - """Retreive task legend""" +async def get_problem_legend(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): + """Retreive problem legend""" try: - to_return = FileResponse(path=f'./data/problems/{_id}/legend.mdx', filename="legend.mdx", + to_return = FileResponse(path=f'{Config.elan_path}/problems/problem{_id}/legend.mdx', filename="legend.mdx", media_type='multipart/form-data') print(to_return) return to_return @@ -66,11 +69,11 @@ async def get_task_legend(_id: IntIdAnnotation, _current_user: User = Depends(au @router.get( "/get_input" ) -async def get_task_input(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): - """Retreive task legend""" +async def get_problem_input(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): + """Retreive problem legend""" try: - to_return = FileResponse(path=f'./data/problems/{_id}/input.mdx', filename="input.mdx", + to_return = FileResponse(path=f'{Config.elan_path}/problems/problem{_id}/input.mdx', filename="input.mdx", media_type='multipart/form-data') return to_return except Exception: @@ -80,11 +83,11 @@ async def get_task_input(_id: IntIdAnnotation, _current_user: User = Depends(aut @router.get( "/get_output" ) -async def get_task_output(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): - """Retreive task legend""" +async def get_problem_output(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): + """Retreive problem legend""" try: - to_return = FileResponse(path=f'./data/problems/{_id}/output.mdx', filename="output.mdx", + to_return = FileResponse(path=f'{Config.elan_path}/problems/problem{_id}/output.mdx', filename="output.mdx", media_type='multipart/form-data') return to_return except Exception: @@ -95,10 +98,10 @@ async def get_task_output(_id: IntIdAnnotation, _current_user: User = Depends(au "/get_scoring" ) async def get_problem_scoring(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): - """Retreive task legend""" + """Retreive problem legend""" try: - to_return = FileResponse(path=f'./data/problems/{_id}/scoring.mdx', filename="scoring.mdx", + to_return = FileResponse(path=f'{Config.elan_path}/problems/problem{_id}/scoring.mdx', filename="scoring.mdx", media_type='multipart/form-data') return to_return except Exception: @@ -109,10 +112,10 @@ async def get_problem_scoring(_id: IntIdAnnotation, _current_user: User = Depend "/get_notes" ) async def get_notes(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): - """Retreive task legend""" + """Retreive problem legend""" try: - to_return = FileResponse(path=f'./data/problems/{_id}/notes.mdx', filename="notes.mdx", + to_return = FileResponse(path=f'{Config.elan_path}/problems/problem{_id}/notes.mdx', filename="notes.mdx", media_type='multipart/form-data') return to_return except Exception: @@ -123,11 +126,40 @@ async def get_notes(_id: IntIdAnnotation, _current_user: User = Depends(auth_use "/get_name" ) async def get_name(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())) -> Any: - """Retreive task name by task id""" + """Retreive problem name by problem id""" + + problem = await db.problem.get(_id) + + if problem is None: + return get_error_response("PROBLEM_NOT_FOUND") + + return problem.name + + +class Examples(BaseModel): + + input: list[str] + output: list[str] + +@router.get( + "/get_examples", + response_model=get_response_model(Examples), + responses={ + 400: get_error_schema("Failed to retreive problem examples.") + } +) +async def get_examples(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())) -> Any: + directory = f"{Config.elan_path}/problems/problem{_id}/" + + result = Examples(input=[], output=[]) - task = await db.problem.get(_id) + for filename in os.scandir(directory): + if filename.is_file(): + if filename.name.startswith("example") and not filename.name.endswith(".a"): + with open(filename.path, "r") as file: + result.input.append(file.read()) + with open(filename.path+".a", "r") as file: + result.output.append(file.read()) - if task is None: - return get_error_response("TASK_NOT_FOUND") + return get_response(result) - return task.name diff --git a/src/routers/submissions_router.py b/src/routers/submissions_router.py new file mode 100644 index 0000000..aab10ba --- /dev/null +++ b/src/routers/submissions_router.py @@ -0,0 +1,63 @@ +import tempfile +from typing import Any + +from _pytest.main import Session +from fastapi import APIRouter, Depends, UploadFile +from pathlib import Path # FIXME КОСТЫЛЬ!!! + +from auth.utils import auth_user +from utils.response_utils import get_error_response, get_response, get_response_model, \ + get_error_schema +from db.models.problem import Problem +from db.models.submission import Submission, SubmissionToCreate +from db.models.user import User +import db +from config import Config +from loguru import logger + + +router = APIRouter() + + +@router.post( + "/create", + response_model=get_response_model(Submission) +) +async def create_submission( + to_create: SubmissionToCreate, + _current_user: User = Depends(auth_user()) +) -> Any: + """Creating submission and sent it to rabbitMQ""" + + contest = await db.contest.get(to_create.contest_id) + if contest is None: + return get_error_response("CONTEST_NOT_FOUND") + + if await db.problem.get(to_create.problem_id) is None: + return get_error_response("PROBLEM_NOT_FOUND") + + submission = Submission( + _id=1, # not used FIXME + contest_id=to_create.contest_id, + problem_id=to_create.problem_id, + user_id=_current_user.id, + status=None, + solution_path=None + ) + + created_submission_id = await db.submission.insert_with_id(submission) + + solution_directory = Config.elan_path + (f"/submissions" + f"/contest{contest.id}" + f"/submission{created_submission_id}") + + Path(solution_directory).mkdir(parents=True, exist_ok=True) + + solution_path = solution_directory + "/solution.cpp" # FIXME it only cpp making banana + + with open(solution_path, "w") as solution: + solution.write(to_create.solution) + + await db.submission.attach_solution_path(created_submission_id, solution_path) + + return get_response(await db.submission.get(created_submission_id)) From 8d821c18a272899b0086773e81abf62921295532 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 14 Feb 2024 21:51:50 +0300 Subject: [PATCH 13/94] added basic producer and time to submissions --- .gitignore | 2 +- data/problems/problem1/example.01 | 2 - data/problems/problem1/example.01.a | 1 - data/problems/problem1/input.mdx | 3 - data/problems/problem1/legend.mdx | 5 - data/problems/problem1/notes.mdx | 3 - data/problems/problem1/output.mdx | 1 - data/problems/problem1/scoring.mdx | 14 - data/problems/problem2/example.01 | 2 - data/problems/problem2/example.01.a | 1 - data/problems/problem2/example.02 | 2 - data/problems/problem2/example.02.a | 1 - data/problems/problem2/input.mdx | 1 - data/problems/problem2/legend.mdx | 5 - data/problems/problem2/notes.mdx | 1 - data/problems/problem2/output.mdx | 1 - data/problems/problem2/scoring.mdx | 3 - .../contest1/submission10/solution.cpp | 1 - .../contest1/submission11/solution.cpp | 1 - .../contest1/submission12/solution.cpp | 1 - .../contest1/submission13/solution.cpp | 1 - .../contest1/submission14/solution.cpp | 1 - .../contest1/submission15/solution.cpp | 1 - .../contest1/submission16/solution.cpp | 377 ------------------ .../contest1/submission2/solution.cpp | 10 - .../contest1/submission3/solution.cpp | 1 - .../contest1/submission4/solution.cpp | 20 - .../contest1/submission5/solution.cpp | 20 - .../contest1/submission6/solution.cpp | 1 - .../contest1/submission7/solution.cpp | 1 - .../contest1/submission8/solution.cpp | 1 - .../contest1/submission9/solution.cpp | 1 - poetry.lock | 18 +- pyproject.toml | 1 + src/config.py | 5 +- src/db/managers/group_database_manager.py | 1 - .../managers/submission_database_manager.py | 16 + src/db/models/submission.py | 7 +- src/producer.py | 17 + src/routers/submissions_router.py | 54 ++- 40 files changed, 113 insertions(+), 492 deletions(-) delete mode 100644 data/problems/problem1/example.01 delete mode 100644 data/problems/problem1/example.01.a delete mode 100644 data/problems/problem1/input.mdx delete mode 100644 data/problems/problem1/legend.mdx delete mode 100644 data/problems/problem1/notes.mdx delete mode 100644 data/problems/problem1/output.mdx delete mode 100644 data/problems/problem1/scoring.mdx delete mode 100644 data/problems/problem2/example.01 delete mode 100644 data/problems/problem2/example.01.a delete mode 100644 data/problems/problem2/example.02 delete mode 100644 data/problems/problem2/example.02.a delete mode 100644 data/problems/problem2/input.mdx delete mode 100644 data/problems/problem2/legend.mdx delete mode 100644 data/problems/problem2/notes.mdx delete mode 100644 data/problems/problem2/output.mdx delete mode 100644 data/problems/problem2/scoring.mdx delete mode 100644 data/submissions/contest1/submission10/solution.cpp delete mode 100644 data/submissions/contest1/submission11/solution.cpp delete mode 100644 data/submissions/contest1/submission12/solution.cpp delete mode 100644 data/submissions/contest1/submission13/solution.cpp delete mode 100644 data/submissions/contest1/submission14/solution.cpp delete mode 100644 data/submissions/contest1/submission15/solution.cpp delete mode 100644 data/submissions/contest1/submission16/solution.cpp delete mode 100644 data/submissions/contest1/submission2/solution.cpp delete mode 100644 data/submissions/contest1/submission3/solution.cpp delete mode 100644 data/submissions/contest1/submission4/solution.cpp delete mode 100644 data/submissions/contest1/submission5/solution.cpp delete mode 100644 data/submissions/contest1/submission6/solution.cpp delete mode 100644 data/submissions/contest1/submission7/solution.cpp delete mode 100644 data/submissions/contest1/submission8/solution.cpp delete mode 100644 data/submissions/contest1/submission9/solution.cpp create mode 100644 src/producer.py diff --git a/.gitignore b/.gitignore index 485ded3..392b43c 100644 --- a/.gitignore +++ b/.gitignore @@ -176,4 +176,4 @@ main_config.env .ruff_cache run.sh test.sh -./data \ No newline at end of file +./data/* \ No newline at end of file diff --git a/data/problems/problem1/example.01 b/data/problems/problem1/example.01 deleted file mode 100644 index 6911b80..0000000 --- a/data/problems/problem1/example.01 +++ /dev/null @@ -1,2 +0,0 @@ -5 -1 3 5 4 diff --git a/data/problems/problem1/example.01.a b/data/problems/problem1/example.01.a deleted file mode 100644 index 0cfbf08..0000000 --- a/data/problems/problem1/example.01.a +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/data/problems/problem1/input.mdx b/data/problems/problem1/input.mdx deleted file mode 100644 index 0ea0f2c..0000000 --- a/data/problems/problem1/input.mdx +++ /dev/null @@ -1,3 +0,0 @@ -В первой строке через пробел вводятся два натуральных числа $n$ и $k$ ($2 \leqslant k \leqslant n \leqslant 10^5$). - -Во второй строке вводится $n$ натуральных чисел через пробел $a_i$ ($1\leqslant a_i \leqslant 10^9$) --- вредности оленей. \ No newline at end of file diff --git a/data/problems/problem1/legend.mdx b/data/problems/problem1/legend.mdx deleted file mode 100644 index e3dbb03..0000000 --- a/data/problems/problem1/legend.mdx +++ /dev/null @@ -1,5 +0,0 @@ -Каждый год Санта собирает себе новую упряжку из оленей. Около его дома есть загон, где живут $n$ оленей. Санта заметил, что рождественские олени --- необычные волшебные животные, все они по-разному реагируют на команды погонщика. Потому он считает, что каждый $i$-й олень обладает некоторой $\textit{вредностью}$ $a_i$, которая характеризуется натуральным числом. Запрягать волшебных животных в упряжку нужно определенным образом, чтобы они летели быстрее: необходимо расположить оленей в таком порядке, чтобы вредности соседних оленей отличались друг от друга как можно меньше. Санта хочет собрать упряжку из $k \leqslant n$ оленей. Помогите ему собрать самую лучшую упряжку. Более формально, из набора $a_1,\, a_2,\,\ldots,\,a_n$ требуется составить $k$-элемнтую последовательность $a_{i_1},\, a_{i_2},\,\ldots,\, a_{i_k}$ таким образом, чтобы сумма -$$ - S_{min} = \bigl | a_{i_2} - a_{i_1} \bigr | + \bigl | a_{i_3} - a_{i_2} \bigr | + \ldots + \bigl | a_{i_n} - a_{i_{n-1}} \bigr | -$$ -была минимальна. \ No newline at end of file diff --git a/data/problems/problem1/notes.mdx b/data/problems/problem1/notes.mdx deleted file mode 100644 index 92e1f1f..0000000 --- a/data/problems/problem1/notes.mdx +++ /dev/null @@ -1,3 +0,0 @@ -В первом примере можно взять оленей со значениями вредности 1 и 2 или 4 и 5 (в любом порядке). - -В втором примере необходимо взять в упряжку оленей со значениями вредности 1, 3 и 3 в таком или обратном порядке. \ No newline at end of file diff --git a/data/problems/problem1/output.mdx b/data/problems/problem1/output.mdx deleted file mode 100644 index 8693dd8..0000000 --- a/data/problems/problem1/output.mdx +++ /dev/null @@ -1 +0,0 @@ -Выведите минимальную возможную сумму $S_{\text{min}}$. \ No newline at end of file diff --git a/data/problems/problem1/scoring.mdx b/data/problems/problem1/scoring.mdx deleted file mode 100644 index 62c21a3..0000000 --- a/data/problems/problem1/scoring.mdx +++ /dev/null @@ -1,14 +0,0 @@ - -$$\begin{center} - \begin{tabular}{ | c | c | c | c | } \hline - \bf{Подгруппа} & - \bf{Доп. ограничения} & - \bf{Баллы} & - \bf{Требуемые подгруппы} \\ \hline - $0$ & тесты из условия & $0$ & --- \\ \hline - $1$ & $n \leqslant 100$, $k\leqslant 4$ & $10$ & --- \\ \hline - $2$ & $k = n$, $n \leqslant 100$ & $10$ & --- \\ \hline - $3$ & $k = n$ & $30$ & $2$ \\ \hline - $4$ & --- & $50$ & $1-3$ \\ \hline - \end{tabular} -\end{center}$$ \ No newline at end of file diff --git a/data/problems/problem2/example.01 b/data/problems/problem2/example.01 deleted file mode 100644 index 1e5752d..0000000 --- a/data/problems/problem2/example.01 +++ /dev/null @@ -1,2 +0,0 @@ -4 2 -1 5 2 4 diff --git a/data/problems/problem2/example.01.a b/data/problems/problem2/example.01.a deleted file mode 100644 index 56a6051..0000000 --- a/data/problems/problem2/example.01.a +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/data/problems/problem2/example.02 b/data/problems/problem2/example.02 deleted file mode 100644 index d09a642..0000000 --- a/data/problems/problem2/example.02 +++ /dev/null @@ -1,2 +0,0 @@ -8 3 -3 10 7 9 3 7 15 1 diff --git a/data/problems/problem2/example.02.a b/data/problems/problem2/example.02.a deleted file mode 100644 index d8263ee..0000000 --- a/data/problems/problem2/example.02.a +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/data/problems/problem2/input.mdx b/data/problems/problem2/input.mdx deleted file mode 100644 index 7573c58..0000000 --- a/data/problems/problem2/input.mdx +++ /dev/null @@ -1 +0,0 @@ -В первой строке дано число $n$ ($0 \lt n \lt 2 * 10^5$). Во второй строке записано $n-1$ число - элементы перестановки $X$ без одного элемента ($0 \lt x_i \lt n + 1$). \ No newline at end of file diff --git a/data/problems/problem2/legend.mdx b/data/problems/problem2/legend.mdx deleted file mode 100644 index 95cd518..0000000 --- a/data/problems/problem2/legend.mdx +++ /dev/null @@ -1,5 +0,0 @@ -На день рождения Алене подарили перестановку $X$ длины $n$. Напомним, что перестановкой является упорядоченный набор из $n$ различных чисел от $1$ до $n$ (например, $\{1, 2, 3\}$ является перестановкой, а $\{1, 2, 4\}$ или $\{1, 2, 2\}$ - не является). - -К сожалению, когда Алена оставила свой подарок в комнате без присмотра, к нему подбежала собака Елань и съела одно число. - -Помогите Алене восстановить ее перестановку и узнать съеденное число, иначе получите ~тапочком по лицу~ реджект. \ No newline at end of file diff --git a/data/problems/problem2/notes.mdx b/data/problems/problem2/notes.mdx deleted file mode 100644 index 43b4bb9..0000000 --- a/data/problems/problem2/notes.mdx +++ /dev/null @@ -1 +0,0 @@ -Это тестовая задача, придуманная разработчиками тестирующей системы Elan. Она создана в Polygon и экспортирована в Elan. \ No newline at end of file diff --git a/data/problems/problem2/output.mdx b/data/problems/problem2/output.mdx deleted file mode 100644 index 588fc8b..0000000 --- a/data/problems/problem2/output.mdx +++ /dev/null @@ -1 +0,0 @@ -Выведите число, которое съела Елань. \ No newline at end of file diff --git a/data/problems/problem2/scoring.mdx b/data/problems/problem2/scoring.mdx deleted file mode 100644 index 32adb5c..0000000 --- a/data/problems/problem2/scoring.mdx +++ /dev/null @@ -1,3 +0,0 @@ -Потестовая оценка. В данной задаче используется 3 теста. Больше генерить мне было лень, да и зачем? Я верю, что вы легко справитесь с такой простой задачей. - ---- M F \ No newline at end of file diff --git a/data/submissions/contest1/submission10/solution.cpp b/data/submissions/contest1/submission10/solution.cpp deleted file mode 100644 index b8dc6c4..0000000 --- a/data/submissions/contest1/submission10/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -this is for BANANA \ No newline at end of file diff --git a/data/submissions/contest1/submission11/solution.cpp b/data/submissions/contest1/submission11/solution.cpp deleted file mode 100644 index 9118d6c..0000000 --- a/data/submissions/contest1/submission11/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -asdasd \ No newline at end of file diff --git a/data/submissions/contest1/submission12/solution.cpp b/data/submissions/contest1/submission12/solution.cpp deleted file mode 100644 index ed38c8a..0000000 --- a/data/submissions/contest1/submission12/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! test test trest \ No newline at end of file diff --git a/data/submissions/contest1/submission13/solution.cpp b/data/submissions/contest1/submission13/solution.cpp deleted file mode 100644 index 9118d6c..0000000 --- a/data/submissions/contest1/submission13/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -asdasd \ No newline at end of file diff --git a/data/submissions/contest1/submission14/solution.cpp b/data/submissions/contest1/submission14/solution.cpp deleted file mode 100644 index 8898c3e..0000000 --- a/data/submissions/contest1/submission14/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission15/solution.cpp b/data/submissions/contest1/submission15/solution.cpp deleted file mode 100644 index ed38c8a..0000000 --- a/data/submissions/contest1/submission15/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! test test trest \ No newline at end of file diff --git a/data/submissions/contest1/submission16/solution.cpp b/data/submissions/contest1/submission16/solution.cpp deleted file mode 100644 index 86bc8f6..0000000 --- a/data/submissions/contest1/submission16/solution.cpp +++ /dev/null @@ -1,377 +0,0 @@ -import {FC, useEffect, useState} from "react"; -import {useParams} from "react-router-dom"; -import { - Avatar, - Box, Button, - Stack, - SxProps, - ToggleButton, - ToggleButtonGroup, - Typography, - useTheme -} from "@mui/material"; -import {getCurrentUser, getWithToken, UserType} from "../../api/auth.tsx"; -import {ContestType, getContestById, getContestProblemsResources, sendSolution} from "../../api/api.tsx"; -import CheckIcon from "@mui/icons-material/Check"; -import ListAltIcon from '@mui/icons-material/ListAlt'; -import MenuIcon from '@mui/icons-material/Menu'; -import { Editor } from "@monaco-editor/react"; -import { ThemeModeContext } from "../../Theme/index.ts"; -import { useContext } from "react"; -import Latex from "react-latex-next"; - - -const ResultContent: FC = () => { - return
- -
-} - - -type TaskResources = { - name: string, - legend: string, - input: string, - output: string, - scoring: string, - notes: string, - id: number -} - -type TasksProps = { - contest_id: any -} - -const TasksContent: FC = (props: TasksProps) => { - - const [tasksResources, setTasksResources] = useState([]); - const [taskText, setTaskText] = useState("test") - const theme = useTheme(); - const { toggleTheme, themeMode, setThemeMode } = useContext(ThemeModeContext); - - const [currentState, setCurrentState] = useState(0); - - const [statesNum, setStatesNum] = useState(0); - - const [navButtons, setNavButtons] = useState([]); - - const [code, setCode] = useState(["// your code here!"]) - - let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - - const [editorState, setEditorState] = useState<"show" | "hide">("show") - - - useEffect(() => { - async function setup() { - const contestProblemsResources = await getContestProblemsResources(props.contest_id) - - - setStatesNum(contestProblemsResources.length) - let toChange = [] - for (let i = 0; i < contestProblemsResources.length; ++i) { - toChange.push( - - ) - } - setNavButtons(toChange); - setTasksResources(contestProblemsResources); - - let current_code = code; - while (current_code.length > contestProblemsResources.length) { - current_code.pop(); - } - - while (current_code.length < contestProblemsResources.length) { - current_code.push("// your code here!"); - } - - setCode(current_code); - } - - setup(); - - }, [currentState]); - - - const rootStyles: SxProps = { - padding: "40px", - height: "100%", - marginBottom: "40px" - } - - const navStyles: SxProps = { - display: "flex", - marginBottom: "30px", - overflow: "scroll", - justifyContent: "space-between" - } - - const taskStyles: SxProps = { - backgroundColor: `${theme.palette.surfaceContainerHigh.main}`, - borderRadius: "30px", - overflow: "scroll", - padding: "20px", - height: "100%", - paddingBottom: "150px", - display: "flex" - } - - - const handleChangeState = (e: any) => { - setCurrentState(e.target.value) - } - - - const handleSubmit = async () => { - const response = await sendSolution(props.contest_id, tasksResources[currentState].id, code[currentState]); - - if (response === undefined) { - alert("Error occured") - } else { - console.log(props.contest_id, tasksResources[currentState].id); - } - } - - // katex.render("c = \\pm\\sqrt{a^2 + b^2}", element, { - // throwOnError: false - // }); - - const handleEditorState = () => { - if (editorState == "show") { - setEditorState("hide") - } else { - setEditorState("show") - } - } - - return - - - {navButtons} - - - - - - - - - - {alphabet[currentState]}. {tasksResources[currentState]?.name} - - - - {tasksResources[currentState]?.legend|| ""} - - - - Формат входных данных - - - - {tasksResources[currentState]?.input || ""} - - - - Формат выходных данных - - - - {tasksResources[currentState]?.output || ""} - - - - Примечание - - - - {tasksResources[currentState]?.notes || ""} - - - - - - - { - let current_code = code; - current_code[currentState] = code_new; - setCode(current_code); - }} - /> - - - - - - - - -} - -const Contest: FC = () => { - - const [_user, setUser] = useState(); - const [contest, setContest] = useState(undefined); - - // const navigate = useNavigate(); - - const theme = useTheme(); - - const {id} = useParams(); - - - useEffect(() => { - async function temp() { - setUser(await getCurrentUser()); - // @ts-ignore - setContest(await getContestById(parseInt(id))); - } - - temp(); - }, []); - - const rootStyles: SxProps = { - borderRadius: "30px", - backgroundColor: `${theme.palette.surfaceContainerLow.main};`, - width: "100%", - minHeight: "100vh", - display: "flex", - position: "fixed", - // paddingBottom: "100px" - } - - const userStyles: SxProps = { - paddingTop: "80px", - display: "none", - flexDirection: "column", - alignItems: "center", - color: `${theme.palette.onSurface.main}`, - minWidth: "350px", - marginLeft: "30px" - } - - const navStyles: SxProps = { - width: "100%", - paddingLeft: "60px", - paddingRight: "300px", - flexGrow: "grow", - flexDirection: "column", - justifyContent: "center", - display: "flex", - position: "static" - } - - const avatarStyles = { - width: "300px", - height: "300px", - marginBottom: "10px" - } - - const navButtonsStyles: SxProps = { - width: "100%", - paddingBottom: "20px", - paddingTop: "20px" - } - - const dataStyles: SxProps = { - backgroundColor: `${theme.palette.surfaceContainerLowest.main}`, - borderRadius: "30px", - height: "100vh", - paddingBottom: "100px" - } - - const [alignment, setAlignment] = useState("tasks"); - - const [content, setContent] = useState(); - // - const handleAlignment = (_event: React.MouseEvent, - newAlignment: string) => { - if (newAlignment != null) { - setAlignment(newAlignment); - if (newAlignment == "tasks") { - setContent(); - } else if (newAlignment == "result") { - setContent(); - } - } - }; - - const nameStyles: SxProps = { - width: "300px", - whiteSpace: "pre-line", - wordWrap: "break-word", - overflow: "wrap" - } - - return <> - - - - - {contest?.name[0]}{contest?.name[1]} - - - - - {contest?.name} - - - - - {contest?.description} - - - - - - - - - {alignment === 'tasks' ? : } - Tasks - - - {alignment === "result" ? : } - Result - - - - - - {content} - {/* */} - - - - -} - - -export default Contest \ No newline at end of file diff --git a/data/submissions/contest1/submission2/solution.cpp b/data/submissions/contest1/submission2/solution.cpp deleted file mode 100644 index d30e7a3..0000000 --- a/data/submissions/contest1/submission2/solution.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include - -using namespace std; - -int main() { - int n; - cin >> n; - cout << n; - return 0; -} diff --git a/data/submissions/contest1/submission3/solution.cpp b/data/submissions/contest1/submission3/solution.cpp deleted file mode 100644 index 30d74d2..0000000 --- a/data/submissions/contest1/submission3/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file diff --git a/data/submissions/contest1/submission4/solution.cpp b/data/submissions/contest1/submission4/solution.cpp deleted file mode 100644 index 9a9e517..0000000 --- a/data/submissions/contest1/submission4/solution.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -using namespace std; - -int main() { - int n; - cin >> n; - - vector sp(n); - - for (int i = 0; i < n; ++i) { - cin >> sp[i]; - } - - for (int i = 0; i < n; ++i) { - cout << sp[i] << " "; - } - - return 0; -} \ No newline at end of file diff --git a/data/submissions/contest1/submission5/solution.cpp b/data/submissions/contest1/submission5/solution.cpp deleted file mode 100644 index 9a9e517..0000000 --- a/data/submissions/contest1/submission5/solution.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -using namespace std; - -int main() { - int n; - cin >> n; - - vector sp(n); - - for (int i = 0; i < n; ++i) { - cin >> sp[i]; - } - - for (int i = 0; i < n; ++i) { - cout << sp[i] << " "; - } - - return 0; -} \ No newline at end of file diff --git a/data/submissions/contest1/submission6/solution.cpp b/data/submissions/contest1/submission6/solution.cpp deleted file mode 100644 index 8898c3e..0000000 --- a/data/submissions/contest1/submission6/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission7/solution.cpp b/data/submissions/contest1/submission7/solution.cpp deleted file mode 100644 index 8898c3e..0000000 --- a/data/submissions/contest1/submission7/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission8/solution.cpp b/data/submissions/contest1/submission8/solution.cpp deleted file mode 100644 index 8898c3e..0000000 --- a/data/submissions/contest1/submission8/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission9/solution.cpp b/data/submissions/contest1/submission9/solution.cpp deleted file mode 100644 index 8898c3e..0000000 --- a/data/submissions/contest1/submission9/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 9eba1e1..d846b2a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -524,6 +524,22 @@ bcrypt = ["bcrypt (>=3.1.0)"] build-docs = ["cloud-sptheme (>=1.10.1)", "sphinx (>=1.6)", "sphinxcontrib-fulltoc (>=1.2.0)"] totp = ["cryptography"] +[[package]] +name = "pika" +version = "1.3.2" +description = "Pika Python AMQP Client Library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pika-1.3.2-py3-none-any.whl", hash = "sha256:0779a7c1fafd805672796085560d290213a465e4f6f76a6fb19e378d8041a14f"}, + {file = "pika-1.3.2.tar.gz", hash = "sha256:b2a327ddddf8570b4965b3576ac77091b850262d34ce8c1d8cb4e4146aa4145f"}, +] + +[package.extras] +gevent = ["gevent"] +tornado = ["tornado"] +twisted = ["twisted"] + [[package]] name = "platformdirs" version = "4.1.0" @@ -1122,4 +1138,4 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "1c25349f5865279c0d2b31e90bfd233bbb720313649929dda4884bc070212bbc" +content-hash = "4b7866f7f4a26b9e4ea432403c3123ad998b2b831304bd139153c78bb960ef64" diff --git a/pyproject.toml b/pyproject.toml index 24e9e7a..b0fa5fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,7 @@ loguru = "^0.7.2" httpx = "^0.26.0" trio = "^0.24.0" python-multipart = "^0.0.9" +pika = "^1.3.2" [tool.poetry.group.dev.dependencies] diff --git a/src/config.py b/src/config.py index 77914f3..11717b1 100644 --- a/src/config.py +++ b/src/config.py @@ -63,4 +63,7 @@ class Auth: JWT_REFRESH_SECRET_KEY = os.environ.get("JWT_REFRESH_SECRET_KEY") or "" app_title = os.environ.get("APP_TITLE") or "" - elan_path = os.environ.get("ELAN_PATH") or "/ELAN" # FIXME NOT USED + elan_path = os.environ.get("ELAN_PATH") or "/ELAN" # FIXME NOT USED or user idk + + # FIXME it may not work later + rabbitmq_main_queue = os.environ.get("RABBITMQ_MAIN_QUEUE") or "INVOKER" diff --git a/src/db/managers/group_database_manager.py b/src/db/managers/group_database_manager.py index 276773e..4ea4181 100644 --- a/src/db/managers/group_database_manager.py +++ b/src/db/managers/group_database_manager.py @@ -36,7 +36,6 @@ async def get_all(self) -> list[Group]: to_return = [] cursor = self.collection.find({}) async for group in cursor: - print(group) to_return.append(Group(**group)) return to_return diff --git a/src/db/managers/submission_database_manager.py b/src/db/managers/submission_database_manager.py index 50fe4d9..4493b12 100644 --- a/src/db/managers/submission_database_manager.py +++ b/src/db/managers/submission_database_manager.py @@ -47,3 +47,19 @@ async def attach_solution_path( await self.collection.update_one({"_id": submission_id}, {"$set": { "solution_path": solution_path }}) + + async def get_all_submission_for_user_in_contest( + self, + user_id: IntIdAnnotation, + contest_id: IntIdAnnotation + ) -> list[Submission]: + result: list[Submission] = [] + cursor = self.collection.find({ + "user_id": user_id, + "contest_id": contest_id + }) + + async for document in cursor: + result.append(Submission(**document)) + + return result diff --git a/src/db/models/submission.py b/src/db/models/submission.py index 71bb46e..f6e3323 100644 --- a/src/db/models/submission.py +++ b/src/db/models/submission.py @@ -1,4 +1,7 @@ -from pydantic import BaseModel, Field +from datetime import datetime +from typing import Annotated + +from pydantic import BaseModel, Field, AfterValidator from db.models.annotations import IntIdAnnotation @@ -24,3 +27,5 @@ class Submission(BaseModel): solution_path: str | None = None status: str | None = None + + upload_time: str diff --git a/src/producer.py b/src/producer.py new file mode 100644 index 0000000..c16eb6a --- /dev/null +++ b/src/producer.py @@ -0,0 +1,17 @@ +import pika +from config import Config +from loguru import logger +from db.models.annotations import IntIdAnnotation + + +def produce_submission(submission_id: IntIdAnnotation): + with pika.BlockingConnection(pika.ConnectionParameters( + host='localhost')) as connection: + channel = connection.channel() + + channel.queue_declare(queue=Config.rabbitmq_main_queue) + + channel.basic_publish(exchange="", + routing_key=Config.rabbitmq_main_queue, + body=f"{submission_id}") + logger.info(f'Published submission with id {submission_id}') diff --git a/src/routers/submissions_router.py b/src/routers/submissions_router.py index aab10ba..b84a84f 100644 --- a/src/routers/submissions_router.py +++ b/src/routers/submissions_router.py @@ -5,7 +5,10 @@ from fastapi import APIRouter, Depends, UploadFile from pathlib import Path # FIXME КОСТЫЛЬ!!! +from pydantic import BaseModel + from auth.utils import auth_user +from db.models.annotations import IntIdAnnotation from utils.response_utils import get_error_response, get_response, get_response_model, \ get_error_schema from db.models.problem import Problem @@ -14,14 +17,15 @@ import db from config import Config from loguru import logger - +from datetime import datetime +from producer import produce_submission router = APIRouter() @router.post( "/create", - response_model=get_response_model(Submission) + response_model=get_response_model() ) async def create_submission( to_create: SubmissionToCreate, @@ -42,7 +46,8 @@ async def create_submission( problem_id=to_create.problem_id, user_id=_current_user.id, status=None, - solution_path=None + solution_path=None, + upload_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S") ) created_submission_id = await db.submission.insert_with_id(submission) @@ -60,4 +65,47 @@ async def create_submission( await db.submission.attach_solution_path(created_submission_id, solution_path) + produce_submission(created_submission_id) + return get_response(await db.submission.get(created_submission_id)) + + +class UserContestSubmissions(BaseModel): + result: list[Submission] + problem_names: list[str] # FIXME set name annotation + + +@router.get( + "/get_user_contest_submissions", + response_model=get_response_model(UserContestSubmissions), + responses={ + 400: get_error_schema("Failed to retreive submissions") + } +) +async def get_user_contest_submissions( + user_id: IntIdAnnotation, + contest_id: IntIdAnnotation, + _current_user: User = Depends(auth_user()) +) -> Any: + contest = await db.contest.get(contest_id) + + if contest is None: + return get_error_response("CONTEST_NOT_FOUND") + + user = db.user.get(user_id) + + if user is None: + return get_error_response("USER_NOT_FOUND") + + result = await db.submission.get_all_submission_for_user_in_contest(user_id, contest_id) + + problem_names: list[str] = [] # FIXME set name annotation + + for submission in result: + problem = await db.problem.get(submission.problem_id) + if problem is None: + problem_names.append("undefined") + else: + problem_names.append(problem.name) + + return get_response(UserContestSubmissions(result=result, problem_names=problem_names)) From 5ecc41336ffe7d382f7d0cf5da4a3faa199c19f4 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 14 Feb 2024 22:01:48 +0300 Subject: [PATCH 14/94] fix: fix ./data files --- data/problems/problem1/example.01 | 2 + data/problems/problem1/example.01.a | 1 + data/problems/problem1/input.mdx | 3 + data/problems/problem1/legend.mdx | 5 + data/problems/problem1/notes.mdx | 3 + data/problems/problem1/output.mdx | 1 + data/problems/problem1/scoring.mdx | 14 + data/problems/problem2/example.01 | 2 + data/problems/problem2/example.01.a | 1 + data/problems/problem2/example.02 | 2 + data/problems/problem2/example.02.a | 1 + data/problems/problem2/input.mdx | 1 + data/problems/problem2/legend.mdx | 5 + data/problems/problem2/notes.mdx | 1 + data/problems/problem2/output.mdx | 1 + data/problems/problem2/scoring.mdx | 3 + .../contest1/submission10/solution.cpp | 1 + .../contest1/submission11/solution.cpp | 1 + .../contest1/submission12/solution.cpp | 1 + .../contest1/submission13/solution.cpp | 1 + .../contest1/submission14/solution.cpp | 1 + .../contest1/submission15/solution.cpp | 1 + .../contest1/submission16/solution.cpp | 377 ++++++++++++++++++ .../contest1/submission2/solution.cpp | 10 + .../contest1/submission3/solution.cpp | 1 + .../contest1/submission4/solution.cpp | 20 + .../contest1/submission5/solution.cpp | 20 + .../contest1/submission6/solution.cpp | 1 + .../contest1/submission7/solution.cpp | 1 + .../contest1/submission8/solution.cpp | 1 + .../contest1/submission9/solution.cpp | 1 + 31 files changed, 484 insertions(+) create mode 100644 data/problems/problem1/example.01 create mode 100644 data/problems/problem1/example.01.a create mode 100644 data/problems/problem1/input.mdx create mode 100644 data/problems/problem1/legend.mdx create mode 100644 data/problems/problem1/notes.mdx create mode 100644 data/problems/problem1/output.mdx create mode 100644 data/problems/problem1/scoring.mdx create mode 100644 data/problems/problem2/example.01 create mode 100644 data/problems/problem2/example.01.a create mode 100644 data/problems/problem2/example.02 create mode 100644 data/problems/problem2/example.02.a create mode 100644 data/problems/problem2/input.mdx create mode 100644 data/problems/problem2/legend.mdx create mode 100644 data/problems/problem2/notes.mdx create mode 100644 data/problems/problem2/output.mdx create mode 100644 data/problems/problem2/scoring.mdx create mode 100644 data/submissions/contest1/submission10/solution.cpp create mode 100644 data/submissions/contest1/submission11/solution.cpp create mode 100644 data/submissions/contest1/submission12/solution.cpp create mode 100644 data/submissions/contest1/submission13/solution.cpp create mode 100644 data/submissions/contest1/submission14/solution.cpp create mode 100644 data/submissions/contest1/submission15/solution.cpp create mode 100644 data/submissions/contest1/submission16/solution.cpp create mode 100644 data/submissions/contest1/submission2/solution.cpp create mode 100644 data/submissions/contest1/submission3/solution.cpp create mode 100644 data/submissions/contest1/submission4/solution.cpp create mode 100644 data/submissions/contest1/submission5/solution.cpp create mode 100644 data/submissions/contest1/submission6/solution.cpp create mode 100644 data/submissions/contest1/submission7/solution.cpp create mode 100644 data/submissions/contest1/submission8/solution.cpp create mode 100644 data/submissions/contest1/submission9/solution.cpp diff --git a/data/problems/problem1/example.01 b/data/problems/problem1/example.01 new file mode 100644 index 0000000..6911b80 --- /dev/null +++ b/data/problems/problem1/example.01 @@ -0,0 +1,2 @@ +5 +1 3 5 4 diff --git a/data/problems/problem1/example.01.a b/data/problems/problem1/example.01.a new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/data/problems/problem1/example.01.a @@ -0,0 +1 @@ +2 diff --git a/data/problems/problem1/input.mdx b/data/problems/problem1/input.mdx new file mode 100644 index 0000000..0ea0f2c --- /dev/null +++ b/data/problems/problem1/input.mdx @@ -0,0 +1,3 @@ +В первой строке через пробел вводятся два натуральных числа $n$ и $k$ ($2 \leqslant k \leqslant n \leqslant 10^5$). + +Во второй строке вводится $n$ натуральных чисел через пробел $a_i$ ($1\leqslant a_i \leqslant 10^9$) --- вредности оленей. \ No newline at end of file diff --git a/data/problems/problem1/legend.mdx b/data/problems/problem1/legend.mdx new file mode 100644 index 0000000..e3dbb03 --- /dev/null +++ b/data/problems/problem1/legend.mdx @@ -0,0 +1,5 @@ +Каждый год Санта собирает себе новую упряжку из оленей. Около его дома есть загон, где живут $n$ оленей. Санта заметил, что рождественские олени --- необычные волшебные животные, все они по-разному реагируют на команды погонщика. Потому он считает, что каждый $i$-й олень обладает некоторой $\textit{вредностью}$ $a_i$, которая характеризуется натуральным числом. Запрягать волшебных животных в упряжку нужно определенным образом, чтобы они летели быстрее: необходимо расположить оленей в таком порядке, чтобы вредности соседних оленей отличались друг от друга как можно меньше. Санта хочет собрать упряжку из $k \leqslant n$ оленей. Помогите ему собрать самую лучшую упряжку. Более формально, из набора $a_1,\, a_2,\,\ldots,\,a_n$ требуется составить $k$-элемнтую последовательность $a_{i_1},\, a_{i_2},\,\ldots,\, a_{i_k}$ таким образом, чтобы сумма +$$ + S_{min} = \bigl | a_{i_2} - a_{i_1} \bigr | + \bigl | a_{i_3} - a_{i_2} \bigr | + \ldots + \bigl | a_{i_n} - a_{i_{n-1}} \bigr | +$$ +была минимальна. \ No newline at end of file diff --git a/data/problems/problem1/notes.mdx b/data/problems/problem1/notes.mdx new file mode 100644 index 0000000..92e1f1f --- /dev/null +++ b/data/problems/problem1/notes.mdx @@ -0,0 +1,3 @@ +В первом примере можно взять оленей со значениями вредности 1 и 2 или 4 и 5 (в любом порядке). + +В втором примере необходимо взять в упряжку оленей со значениями вредности 1, 3 и 3 в таком или обратном порядке. \ No newline at end of file diff --git a/data/problems/problem1/output.mdx b/data/problems/problem1/output.mdx new file mode 100644 index 0000000..8693dd8 --- /dev/null +++ b/data/problems/problem1/output.mdx @@ -0,0 +1 @@ +Выведите минимальную возможную сумму $S_{\text{min}}$. \ No newline at end of file diff --git a/data/problems/problem1/scoring.mdx b/data/problems/problem1/scoring.mdx new file mode 100644 index 0000000..62c21a3 --- /dev/null +++ b/data/problems/problem1/scoring.mdx @@ -0,0 +1,14 @@ + +$$\begin{center} + \begin{tabular}{ | c | c | c | c | } \hline + \bf{Подгруппа} & + \bf{Доп. ограничения} & + \bf{Баллы} & + \bf{Требуемые подгруппы} \\ \hline + $0$ & тесты из условия & $0$ & --- \\ \hline + $1$ & $n \leqslant 100$, $k\leqslant 4$ & $10$ & --- \\ \hline + $2$ & $k = n$, $n \leqslant 100$ & $10$ & --- \\ \hline + $3$ & $k = n$ & $30$ & $2$ \\ \hline + $4$ & --- & $50$ & $1-3$ \\ \hline + \end{tabular} +\end{center}$$ \ No newline at end of file diff --git a/data/problems/problem2/example.01 b/data/problems/problem2/example.01 new file mode 100644 index 0000000..1e5752d --- /dev/null +++ b/data/problems/problem2/example.01 @@ -0,0 +1,2 @@ +4 2 +1 5 2 4 diff --git a/data/problems/problem2/example.01.a b/data/problems/problem2/example.01.a new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/data/problems/problem2/example.01.a @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/data/problems/problem2/example.02 b/data/problems/problem2/example.02 new file mode 100644 index 0000000..d09a642 --- /dev/null +++ b/data/problems/problem2/example.02 @@ -0,0 +1,2 @@ +8 3 +3 10 7 9 3 7 15 1 diff --git a/data/problems/problem2/example.02.a b/data/problems/problem2/example.02.a new file mode 100644 index 0000000..d8263ee --- /dev/null +++ b/data/problems/problem2/example.02.a @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/data/problems/problem2/input.mdx b/data/problems/problem2/input.mdx new file mode 100644 index 0000000..7573c58 --- /dev/null +++ b/data/problems/problem2/input.mdx @@ -0,0 +1 @@ +В первой строке дано число $n$ ($0 \lt n \lt 2 * 10^5$). Во второй строке записано $n-1$ число - элементы перестановки $X$ без одного элемента ($0 \lt x_i \lt n + 1$). \ No newline at end of file diff --git a/data/problems/problem2/legend.mdx b/data/problems/problem2/legend.mdx new file mode 100644 index 0000000..95cd518 --- /dev/null +++ b/data/problems/problem2/legend.mdx @@ -0,0 +1,5 @@ +На день рождения Алене подарили перестановку $X$ длины $n$. Напомним, что перестановкой является упорядоченный набор из $n$ различных чисел от $1$ до $n$ (например, $\{1, 2, 3\}$ является перестановкой, а $\{1, 2, 4\}$ или $\{1, 2, 2\}$ - не является). + +К сожалению, когда Алена оставила свой подарок в комнате без присмотра, к нему подбежала собака Елань и съела одно число. + +Помогите Алене восстановить ее перестановку и узнать съеденное число, иначе получите ~тапочком по лицу~ реджект. \ No newline at end of file diff --git a/data/problems/problem2/notes.mdx b/data/problems/problem2/notes.mdx new file mode 100644 index 0000000..43b4bb9 --- /dev/null +++ b/data/problems/problem2/notes.mdx @@ -0,0 +1 @@ +Это тестовая задача, придуманная разработчиками тестирующей системы Elan. Она создана в Polygon и экспортирована в Elan. \ No newline at end of file diff --git a/data/problems/problem2/output.mdx b/data/problems/problem2/output.mdx new file mode 100644 index 0000000..588fc8b --- /dev/null +++ b/data/problems/problem2/output.mdx @@ -0,0 +1 @@ +Выведите число, которое съела Елань. \ No newline at end of file diff --git a/data/problems/problem2/scoring.mdx b/data/problems/problem2/scoring.mdx new file mode 100644 index 0000000..32adb5c --- /dev/null +++ b/data/problems/problem2/scoring.mdx @@ -0,0 +1,3 @@ +Потестовая оценка. В данной задаче используется 3 теста. Больше генерить мне было лень, да и зачем? Я верю, что вы легко справитесь с такой простой задачей. + +--- M F \ No newline at end of file diff --git a/data/submissions/contest1/submission10/solution.cpp b/data/submissions/contest1/submission10/solution.cpp new file mode 100644 index 0000000..b8dc6c4 --- /dev/null +++ b/data/submissions/contest1/submission10/solution.cpp @@ -0,0 +1 @@ +this is for BANANA \ No newline at end of file diff --git a/data/submissions/contest1/submission11/solution.cpp b/data/submissions/contest1/submission11/solution.cpp new file mode 100644 index 0000000..9118d6c --- /dev/null +++ b/data/submissions/contest1/submission11/solution.cpp @@ -0,0 +1 @@ +asdasd \ No newline at end of file diff --git a/data/submissions/contest1/submission12/solution.cpp b/data/submissions/contest1/submission12/solution.cpp new file mode 100644 index 0000000..ed38c8a --- /dev/null +++ b/data/submissions/contest1/submission12/solution.cpp @@ -0,0 +1 @@ +// your code here! test test trest \ No newline at end of file diff --git a/data/submissions/contest1/submission13/solution.cpp b/data/submissions/contest1/submission13/solution.cpp new file mode 100644 index 0000000..9118d6c --- /dev/null +++ b/data/submissions/contest1/submission13/solution.cpp @@ -0,0 +1 @@ +asdasd \ No newline at end of file diff --git a/data/submissions/contest1/submission14/solution.cpp b/data/submissions/contest1/submission14/solution.cpp new file mode 100644 index 0000000..8898c3e --- /dev/null +++ b/data/submissions/contest1/submission14/solution.cpp @@ -0,0 +1 @@ +// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission15/solution.cpp b/data/submissions/contest1/submission15/solution.cpp new file mode 100644 index 0000000..ed38c8a --- /dev/null +++ b/data/submissions/contest1/submission15/solution.cpp @@ -0,0 +1 @@ +// your code here! test test trest \ No newline at end of file diff --git a/data/submissions/contest1/submission16/solution.cpp b/data/submissions/contest1/submission16/solution.cpp new file mode 100644 index 0000000..86bc8f6 --- /dev/null +++ b/data/submissions/contest1/submission16/solution.cpp @@ -0,0 +1,377 @@ +import {FC, useEffect, useState} from "react"; +import {useParams} from "react-router-dom"; +import { + Avatar, + Box, Button, + Stack, + SxProps, + ToggleButton, + ToggleButtonGroup, + Typography, + useTheme +} from "@mui/material"; +import {getCurrentUser, getWithToken, UserType} from "../../api/auth.tsx"; +import {ContestType, getContestById, getContestProblemsResources, sendSolution} from "../../api/api.tsx"; +import CheckIcon from "@mui/icons-material/Check"; +import ListAltIcon from '@mui/icons-material/ListAlt'; +import MenuIcon from '@mui/icons-material/Menu'; +import { Editor } from "@monaco-editor/react"; +import { ThemeModeContext } from "../../Theme/index.ts"; +import { useContext } from "react"; +import Latex from "react-latex-next"; + + +const ResultContent: FC = () => { + return
+ +
+} + + +type TaskResources = { + name: string, + legend: string, + input: string, + output: string, + scoring: string, + notes: string, + id: number +} + +type TasksProps = { + contest_id: any +} + +const TasksContent: FC = (props: TasksProps) => { + + const [tasksResources, setTasksResources] = useState([]); + const [taskText, setTaskText] = useState("test") + const theme = useTheme(); + const { toggleTheme, themeMode, setThemeMode } = useContext(ThemeModeContext); + + const [currentState, setCurrentState] = useState(0); + + const [statesNum, setStatesNum] = useState(0); + + const [navButtons, setNavButtons] = useState([]); + + const [code, setCode] = useState(["// your code here!"]) + + let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + const [editorState, setEditorState] = useState<"show" | "hide">("show") + + + useEffect(() => { + async function setup() { + const contestProblemsResources = await getContestProblemsResources(props.contest_id) + + + setStatesNum(contestProblemsResources.length) + let toChange = [] + for (let i = 0; i < contestProblemsResources.length; ++i) { + toChange.push( + + ) + } + setNavButtons(toChange); + setTasksResources(contestProblemsResources); + + let current_code = code; + while (current_code.length > contestProblemsResources.length) { + current_code.pop(); + } + + while (current_code.length < contestProblemsResources.length) { + current_code.push("// your code here!"); + } + + setCode(current_code); + } + + setup(); + + }, [currentState]); + + + const rootStyles: SxProps = { + padding: "40px", + height: "100%", + marginBottom: "40px" + } + + const navStyles: SxProps = { + display: "flex", + marginBottom: "30px", + overflow: "scroll", + justifyContent: "space-between" + } + + const taskStyles: SxProps = { + backgroundColor: `${theme.palette.surfaceContainerHigh.main}`, + borderRadius: "30px", + overflow: "scroll", + padding: "20px", + height: "100%", + paddingBottom: "150px", + display: "flex" + } + + + const handleChangeState = (e: any) => { + setCurrentState(e.target.value) + } + + + const handleSubmit = async () => { + const response = await sendSolution(props.contest_id, tasksResources[currentState].id, code[currentState]); + + if (response === undefined) { + alert("Error occured") + } else { + console.log(props.contest_id, tasksResources[currentState].id); + } + } + + // katex.render("c = \\pm\\sqrt{a^2 + b^2}", element, { + // throwOnError: false + // }); + + const handleEditorState = () => { + if (editorState == "show") { + setEditorState("hide") + } else { + setEditorState("show") + } + } + + return + + + {navButtons} + + + + + + + + + + {alphabet[currentState]}. {tasksResources[currentState]?.name} + + + + {tasksResources[currentState]?.legend|| ""} + + + + Формат входных данных + + + + {tasksResources[currentState]?.input || ""} + + + + Формат выходных данных + + + + {tasksResources[currentState]?.output || ""} + + + + Примечание + + + + {tasksResources[currentState]?.notes || ""} + + + + + + + { + let current_code = code; + current_code[currentState] = code_new; + setCode(current_code); + }} + /> + + + + + + + + +} + +const Contest: FC = () => { + + const [_user, setUser] = useState(); + const [contest, setContest] = useState(undefined); + + // const navigate = useNavigate(); + + const theme = useTheme(); + + const {id} = useParams(); + + + useEffect(() => { + async function temp() { + setUser(await getCurrentUser()); + // @ts-ignore + setContest(await getContestById(parseInt(id))); + } + + temp(); + }, []); + + const rootStyles: SxProps = { + borderRadius: "30px", + backgroundColor: `${theme.palette.surfaceContainerLow.main};`, + width: "100%", + minHeight: "100vh", + display: "flex", + position: "fixed", + // paddingBottom: "100px" + } + + const userStyles: SxProps = { + paddingTop: "80px", + display: "none", + flexDirection: "column", + alignItems: "center", + color: `${theme.palette.onSurface.main}`, + minWidth: "350px", + marginLeft: "30px" + } + + const navStyles: SxProps = { + width: "100%", + paddingLeft: "60px", + paddingRight: "300px", + flexGrow: "grow", + flexDirection: "column", + justifyContent: "center", + display: "flex", + position: "static" + } + + const avatarStyles = { + width: "300px", + height: "300px", + marginBottom: "10px" + } + + const navButtonsStyles: SxProps = { + width: "100%", + paddingBottom: "20px", + paddingTop: "20px" + } + + const dataStyles: SxProps = { + backgroundColor: `${theme.palette.surfaceContainerLowest.main}`, + borderRadius: "30px", + height: "100vh", + paddingBottom: "100px" + } + + const [alignment, setAlignment] = useState("tasks"); + + const [content, setContent] = useState(); + // + const handleAlignment = (_event: React.MouseEvent, + newAlignment: string) => { + if (newAlignment != null) { + setAlignment(newAlignment); + if (newAlignment == "tasks") { + setContent(); + } else if (newAlignment == "result") { + setContent(); + } + } + }; + + const nameStyles: SxProps = { + width: "300px", + whiteSpace: "pre-line", + wordWrap: "break-word", + overflow: "wrap" + } + + return <> + + + + + {contest?.name[0]}{contest?.name[1]} + + + + + {contest?.name} + + + + + {contest?.description} + + + + + + + + + {alignment === 'tasks' ? : } + Tasks + + + {alignment === "result" ? : } + Result + + + + + + {content} + {/* */} + + + + +} + + +export default Contest \ No newline at end of file diff --git a/data/submissions/contest1/submission2/solution.cpp b/data/submissions/contest1/submission2/solution.cpp new file mode 100644 index 0000000..d30e7a3 --- /dev/null +++ b/data/submissions/contest1/submission2/solution.cpp @@ -0,0 +1,10 @@ +#include + +using namespace std; + +int main() { + int n; + cin >> n; + cout << n; + return 0; +} diff --git a/data/submissions/contest1/submission3/solution.cpp b/data/submissions/contest1/submission3/solution.cpp new file mode 100644 index 0000000..30d74d2 --- /dev/null +++ b/data/submissions/contest1/submission3/solution.cpp @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/data/submissions/contest1/submission4/solution.cpp b/data/submissions/contest1/submission4/solution.cpp new file mode 100644 index 0000000..9a9e517 --- /dev/null +++ b/data/submissions/contest1/submission4/solution.cpp @@ -0,0 +1,20 @@ +#include +#include +using namespace std; + +int main() { + int n; + cin >> n; + + vector sp(n); + + for (int i = 0; i < n; ++i) { + cin >> sp[i]; + } + + for (int i = 0; i < n; ++i) { + cout << sp[i] << " "; + } + + return 0; +} \ No newline at end of file diff --git a/data/submissions/contest1/submission5/solution.cpp b/data/submissions/contest1/submission5/solution.cpp new file mode 100644 index 0000000..9a9e517 --- /dev/null +++ b/data/submissions/contest1/submission5/solution.cpp @@ -0,0 +1,20 @@ +#include +#include +using namespace std; + +int main() { + int n; + cin >> n; + + vector sp(n); + + for (int i = 0; i < n; ++i) { + cin >> sp[i]; + } + + for (int i = 0; i < n; ++i) { + cout << sp[i] << " "; + } + + return 0; +} \ No newline at end of file diff --git a/data/submissions/contest1/submission6/solution.cpp b/data/submissions/contest1/submission6/solution.cpp new file mode 100644 index 0000000..8898c3e --- /dev/null +++ b/data/submissions/contest1/submission6/solution.cpp @@ -0,0 +1 @@ +// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission7/solution.cpp b/data/submissions/contest1/submission7/solution.cpp new file mode 100644 index 0000000..8898c3e --- /dev/null +++ b/data/submissions/contest1/submission7/solution.cpp @@ -0,0 +1 @@ +// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission8/solution.cpp b/data/submissions/contest1/submission8/solution.cpp new file mode 100644 index 0000000..8898c3e --- /dev/null +++ b/data/submissions/contest1/submission8/solution.cpp @@ -0,0 +1 @@ +// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission9/solution.cpp b/data/submissions/contest1/submission9/solution.cpp new file mode 100644 index 0000000..8898c3e --- /dev/null +++ b/data/submissions/contest1/submission9/solution.cpp @@ -0,0 +1 @@ +// your code here! \ No newline at end of file From 840ecb9c952162cfc35fa6440570f3c3604e5a38 Mon Sep 17 00:00:00 2001 From: Spotika Date: Sun, 28 Apr 2024 17:29:12 +0300 Subject: [PATCH 15/94] chore: create working docker compose for run && test --- Dockerfile | 14 ++++++++++++++ docker-compose.yml | 16 ++++++++++++++++ testing/Dockerfile | 13 +++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 testing/Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f75a7fc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.12.1-alpine3.19 + +# WORKDIR . + +COPY ./pyproject.toml ./pyproject.toml + +RUN pip3 install poetry +RUN poetry install + +COPY ./src ./src + +WORKDIR ./src + +CMD ["poetry", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..89a5e95 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +version: "3" + +services: + backend: + container_name: elants_backend + build: . + + # depends_on: + # - db + # db: + testing: + container_name: elants_backend_testing + build: + context: . + dockerfile: ./testing/Dockerfile + # linting: diff --git a/testing/Dockerfile b/testing/Dockerfile new file mode 100644 index 0000000..23dae0e --- /dev/null +++ b/testing/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.12.1-alpine3.19 + +COPY ../pyproject.toml ./pyproject.toml + +RUN pip3 install poetry +RUN poetry install + +COPY ./src ./src +COPY ./testing ./testing + +WORKDIR ./testing + +CMD ["poetry", "run", "pytest", "-vv"] From 8e09d83b795070fd8dc270db354f6afd2573aa3c Mon Sep 17 00:00:00 2001 From: Spotika Date: Sun, 28 Apr 2024 17:29:56 +0300 Subject: [PATCH 16/94] chore: init configuration files for mypy and pytest --- .mypy.ini | 0 pyproject.toml | 9 --------- pytest.ini => testing/pytest.ini | 0 3 files changed, 9 deletions(-) create mode 100644 .mypy.ini rename pytest.ini => testing/pytest.ini (100%) diff --git a/.mypy.ini b/.mypy.ini new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml index b0fa5fe..01da3b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,12 +34,3 @@ types-python-jose = "^3.3.4.8" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" - -[tool.pytest.ini_options] -pythonpath = [ - "." -] -log_cli = true -log_cli_level = "INFO" -log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)" -log_cli_date_format = "%Y-%m-%d %H:%M:%S" \ No newline at end of file diff --git a/pytest.ini b/testing/pytest.ini similarity index 100% rename from pytest.ini rename to testing/pytest.ini From 95b8b1da8aa8975791b451fd56a15b3dff86d401 Mon Sep 17 00:00:00 2001 From: Spotika Date: Sun, 28 Apr 2024 17:38:26 +0300 Subject: [PATCH 17/94] chore: the testing and running functional has been removed from manage.py --- manage.py | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/manage.py b/manage.py index c43ba61..175794b 100755 --- a/manage.py +++ b/manage.py @@ -6,8 +6,6 @@ import argparse import sys from pathlib import Path -from dotenv import load_dotenv -import uvicorn from loguru import logger @@ -18,13 +16,6 @@ def parse_arguments(): lint_parser = subparsers.add_parser('lint') lint_parser.set_defaults(command='lint') - run_parser = subparsers.add_parser('run') - run_parser.set_defaults(command='run') - run_parser.add_argument('--config', help='Path to the .env file', required=True) - - test_parser = subparsers.add_parser('test') - test_parser.set_defaults(command='test') - test_parser.add_argument('--config', help='Path to the .env file', required=True) return parser.parse_args() @@ -35,29 +26,13 @@ def main(): # pylint: disable=missing-function-docstring # Check the command and execute the corresponding logic match args.command: - case "run": - # Run the FastAPI app using uvicorn - if args.config.endswith("example.env"): - logger.error(( - "You are using the example config 'example.env' instead of " - "your own one. Example config is not meant to be used " - "in production for security and other concerns. Please " - "create your own config file and run the app using " - "--config /path/to/config.env" - )) - sys.exit(1) - load_dotenv(dotenv_path=args.config) - uvicorn.run("src.main:app", host="127.0.0.1", port=8000, reload=True) - case "test": # run testing - load_dotenv(dotenv_path=args.config) - os.system("pytest ./testing -vv") case "lint": # run linting logger.info("Running pylint...") os.system("pylint --recursive=y ./src/") logger.info("Running ruff...") os.system("ruff src/") logger.info("Running mypy...") - os.system("mypy ./src/") + os.system("mypy --strict ./src/") case _: print(f"Unknown command: {args.command}") From 890128c15d8f8c972b526553730242abd1d1a68a Mon Sep 17 00:00:00 2001 From: Spotika Date: Mon, 29 Apr 2024 15:40:17 +0300 Subject: [PATCH 18/94] feat: change project configuration structure for more information see https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-155 --- .gitignore | 4 +- Dockerfile | 7 ++- configs/example_config.json | 24 +++++++++ docker-compose.yml | 6 ++- src/config.py | 69 ------------------------ src/config/__init__.py | 46 ++++++++++++++++ src/config/config_model.py | 103 ++++++++++++++++++++++++++++++++++++ src/main.py | 9 ++-- 8 files changed, 190 insertions(+), 78 deletions(-) create mode 100644 configs/example_config.json delete mode 100644 src/config.py create mode 100644 src/config/__init__.py create mode 100644 src/config/config_model.py diff --git a/.gitignore b/.gitignore index 392b43c..f6b88e9 100644 --- a/.gitignore +++ b/.gitignore @@ -172,8 +172,8 @@ src_cache fastapi-async-mongodb .vscode -main_config.env .ruff_cache run.sh test.sh -./data/* \ No newline at end of file +./data/* +configs/main_config.json diff --git a/Dockerfile b/Dockerfile index f75a7fc..d0d9759 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,17 @@ FROM python:3.12.1-alpine3.19 -# WORKDIR . +ARG ELANTS_CONFIG_FILE_PATH COPY ./pyproject.toml ./pyproject.toml + RUN pip3 install poetry RUN poetry install COPY ./src ./src - +COPY $ELANTS_CONFIG_FILE_PATH /elants_config.json WORKDIR ./src +ENV ELANTS_CONFIG_FILE_PATH=/elants_config.json + CMD ["poetry", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"] diff --git a/configs/example_config.json b/configs/example_config.json new file mode 100644 index 0000000..5f600fc --- /dev/null +++ b/configs/example_config.json @@ -0,0 +1,24 @@ +{ + "database": { + "connect_url": "mongodb://localhost:27017", + "name": "ELANDB", + "collections": { + "users": "Users", + "groups": "Groups", + "roles": "Roles", + "domains": "Domains", + "group_roles": "GroupRoles" + } + }, + "rabbitmq": { + "connect_url": "test urls://localhost" + }, + "auth": { + "algorithm": "HS256", + "access_token_expire_minutes": 30, + "refresh_token_expire_minutes": 10080, + "jwt_access_secret_key": "jwt_access_secret_key", + "jwt_refresh_secret_key": "jwt_refresh_secret_key" + }, + "app_title": null +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 89a5e95..887e48c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,8 +3,10 @@ version: "3" services: backend: container_name: elants_backend - build: . - + build: + dockerfile: Dockerfile + args: + - ELANTS_CONFIG_FILE_PATH=./configs/main_config.json # depends_on: # - db # db: diff --git a/src/config.py b/src/config.py deleted file mode 100644 index 11717b1..0000000 --- a/src/config.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Project config file""" -import os -import sys -from loguru import logger - - -class Config: - """Entire project config""" - if any(arg_value is None for arg_value in [ - os.environ.get("DB_CONNECT_URL"), - os.environ.get("DB_NAME"), - os.environ.get("COLLECTION_USERS"), - os.environ.get("COLLECTION_ROLES"), - os.environ.get("COLLECTION_GROUP_ROLES"), - os.environ.get("COLLECTION_GROUPS"), - os.environ.get("COLLECTION_DOMAIN"), - os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES"), - os.environ.get("REFRESH_TOKEN_EXPIRE_MINUTES"), - os.environ.get("ALGORITHM"), - os.environ.get("JWT_SECRET_KEY"), - os.environ.get("JWT_REFRESH_SECRET_KEY"), - os.environ.get("APP_TITLE") - ]): - logger.error([ - os.environ.get("DB_CONNECT_URL"), - os.environ.get("DB_NAME"), - os.environ.get("COLLECTION_USERS"), - os.environ.get("COLLECTION_ROLES"), - os.environ.get("COLLECTION_GROUP_ROLES"), - os.environ.get("COLLECTION_GROUPS"), - os.environ.get("COLLECTION_DOMAIN"), - os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES"), - os.environ.get("REFRESH_TOKEN_EXPIRE_MINUTES"), - os.environ.get("ALGORITHM"), - os.environ.get("JWT_SECRET_KEY"), - os.environ.get("JWT_REFRESH_SECRET_KEY"), - os.environ.get("APP_TITLE") - ]) - sys.exit(1) - db_connect_url: str = os.environ.get("DB_CONNECT_URL") or "" - - db_name: str = os.environ.get("DB_NAME") or "" - - class Collections: - """Collection db names""" - users = os.environ.get("COLLECTION_USERS") or "" - roles = os.environ.get("COLLECTION_ROLES") or "" - group_roles = os.environ.get("COLLECTION_GROUP_ROLES") or "" - groups = os.environ.get("COLLECTION_GROUPS") or "" - domain_router = os.environ.get("COLLECTION_DOMAIN") or "" - internal_counters = os.environ.get("COLLECTION_INTERNAL_COUNTERS") or "" - contests = os.environ.get("COLLECTION_CONTESTS") or "" - problems = os.environ.get("COLLECTION_PROBLEMS") or "" - submissions = os.environ.get("COLLECTION_SUBMISSIONS") or "" - - class Auth: - """Data for auth system""" - ACCESS_TOKEN_EXPIRE_MINUTES = int(os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES") or "") - REFRESH_TOKEN_EXPIRE_MINUTES = int(os.environ.get("REFRESH_TOKEN_EXPIRE_MINUTES") or "") - ALGORITHM = os.environ.get("ALGORITHM") or "" - - JWT_SECRET_KEY = os.environ.get("JWT_SECRET_KEY") or "" - JWT_REFRESH_SECRET_KEY = os.environ.get("JWT_REFRESH_SECRET_KEY") or "" - - app_title = os.environ.get("APP_TITLE") or "" - elan_path = os.environ.get("ELAN_PATH") or "/ELAN" # FIXME NOT USED or user idk - - # FIXME it may not work later - rabbitmq_main_queue = os.environ.get("RABBITMQ_MAIN_QUEUE") or "INVOKER" diff --git a/src/config/__init__.py b/src/config/__init__.py new file mode 100644 index 0000000..edfe144 --- /dev/null +++ b/src/config/__init__.py @@ -0,0 +1,46 @@ +"""Project configuration""" +import os +import sys +from loguru import logger + + +from . import config_model + +CONFIG_PATH_ENV_VARIABLE_NAME = "ELANTS_CONFIG_FILE_PATH" + +config_path = os.getenv(CONFIG_PATH_ENV_VARIABLE_NAME) + +if config_path is None: # check for existing env variable + logger.error( + f"Environment variable {CONFIG_PATH_ENV_VARIABLE_NAME} is not set" + ) + sys.exit(1) + +def check_json_file(file_path: str) -> bool: + """Check that file_path is a json file and exists + + Args: + file_path: file to check + + Returns: + True if file_path is a json file and exists, False otherwise + """ + if os.path.exists(file_path) and os.path.isfile(file_path): + _, file_extension = os.path.splitext(file_path) + if file_extension.lower() == '.json': + return True + return False + +if not check_json_file(config_path): # check_json_file + logger.error( + f"File {config_path} is not a json file or isnt exists" + ) + sys.exit(1) + +logger.info(f"Loading configuration from file {CONFIG_PATH_ENV_VARIABLE_NAME}") + +with open(config_path, "r", encoding="utf-8") as config_file: # parse && validate config file + config: config_model.Config = config_model.Config.model_validate_json(config_file.read()) + +logger.info(f"Successfully loaded configuration from file {CONFIG_PATH_ENV_VARIABLE_NAME}") +logger.info(f"Current configuration: {config.model_dump_json(indent=4)}") diff --git a/src/config/config_model.py b/src/config/config_model.py new file mode 100644 index 0000000..b4d146d --- /dev/null +++ b/src/config/config_model.py @@ -0,0 +1,103 @@ +"""Define configuration class""" +from pydantic import BaseModel, SecretStr + + +class MongoDBCollections(BaseModel): + """List of all collections in database""" + users: str + domains: str + groups: str + group_roles: str + roles: str + +class DatabaseConfig(BaseModel): + """Database configuration""" + connect_url: SecretStr + name: str + collections: MongoDBCollections + +class AuthConfig(BaseModel): + """Auth configuration""" + algorithm: str + access_token_expire_minutes: int + refresh_token_expire_minutes: int + jwt_access_secret_key: SecretStr + jwt_refresh_secret_key: SecretStr + +class RabbitMQConfig(BaseModel): + """Config for RabbitMQ""" + connect_url: SecretStr + # TODO: insert other necessary fields later + +class Config(BaseModel): + """Entire project configuration""" + database: DatabaseConfig + rabbitmq: RabbitMQConfig + auth: AuthConfig + app_title: str + + + +# class Config: +# """Entire project config""" +# if any(arg_value is None for arg_value in [ +# os.environ.get("DB_CONNECT_URL"), +# os.environ.get("DB_NAME"), +# os.environ.get("COLLECTION_USERS"), +# os.environ.get("COLLECTION_ROLES"), +# os.environ.get("COLLECTION_GROUP_ROLES"), +# os.environ.get("COLLECTION_GROUPS"), +# os.environ.get("COLLECTION_DOMAIN"), +# os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES"), +# os.environ.get("REFRESH_TOKEN_EXPIRE_MINUTES"), +# os.environ.get("ALGORITHM"), +# os.environ.get("JWT_SECRET_KEY"), +# os.environ.get("JWT_REFRESH_SECRET_KEY"), +# os.environ.get("APP_TITLE") +# ]): +# logger.error([ +# os.environ.get("DB_CONNECT_URL"), +# os.environ.get("DB_NAME"), +# os.environ.get("COLLECTION_USERS"), +# os.environ.get("COLLECTION_ROLES"), +# os.environ.get("COLLECTION_GROUP_ROLES"), +# os.environ.get("COLLECTION_GROUPS"), +# os.environ.get("COLLECTION_DOMAIN"), +# os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES"), +# os.environ.get("REFRESH_TOKEN_EXPIRE_MINUTES"), +# os.environ.get("ALGORITHM"), +# os.environ.get("JWT_SECRET_KEY"), +# os.environ.get("JWT_REFRESH_SECRET_KEY"), +# os.environ.get("APP_TITLE") +# ]) +# sys.exit(1) +# db_connect_url: str = os.environ.get("DB_CONNECT_URL") or "" + +# db_name: str = os.environ.get("DB_NAME") or "" + +# class Collections: +# """Collection db names""" +# users = os.environ.get("COLLECTION_USERS") or "" +# roles = os.environ.get("COLLECTION_ROLES") or "" +# group_roles = os.environ.get("COLLECTION_GROUP_ROLES") or "" +# groups = os.environ.get("COLLECTION_GROUPS") or "" +# domain_router = os.environ.get("COLLECTION_DOMAIN") or "" +# internal_counters = os.environ.get("COLLECTION_INTERNAL_COUNTERS") or "" +# contests = os.environ.get("COLLECTION_CONTESTS") or "" +# problems = os.environ.get("COLLECTION_PROBLEMS") or "" +# submissions = os.environ.get("COLLECTION_SUBMISSIONS") or "" + +# class Auth: +# """Data for auth system""" +# ACCESS_TOKEN_EXPIRE_MINUTES = int(os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES") or "") +# REFRESH_TOKEN_EXPIRE_MINUTES = int(os.environ.get("REFRESH_TOKEN_EXPIRE_MINUTES") or "") +# ALGORITHM = os.environ.get("ALGORITHM") or "" + +# JWT_SECRET_KEY = os.environ.get("JWT_SECRET_KEY") or "" +# JWT_REFRESH_SECRET_KEY = os.environ.get("JWT_REFRESH_SECRET_KEY") or "" + +# app_title = os.environ.get("APP_TITLE") or "" +# elan_path = os.environ.get("ELAN_PATH") or "/ELAN" # FIXME NOT USED or user idk + +# # FIXME it may not work later +# rabbitmq_main_queue = os.environ.get("RABBITMQ_MAIN_QUEUE") or "INVOKER" diff --git a/src/main.py b/src/main.py index 7926309..c4a0303 100644 --- a/src/main.py +++ b/src/main.py @@ -6,7 +6,7 @@ from auth.utils import AuthException from utils.handlers import auth_exception_handler -from config import Config +from config import config import routers.auth_router from db.mongo_manager import MongoManager import routers.contests_router @@ -24,14 +24,17 @@ async def lifespan(_app: FastAPI): """ # on startup - MongoManager.connect(Config.db_connect_url, Config.db_name) + MongoManager.connect( + config.database.connect_url.get_secret_value(), + config.database.name + ) yield # on shutdown MongoManager.disconnect() -app = FastAPI(title=Config.app_title, debug=True, lifespan=lifespan) +app = FastAPI(title=config.app_title, debug=True, lifespan=lifespan) origins = [ "http://localhost", From 92cf5db3ef9538316a2b5aeb4a36bb27e813c1c1 Mon Sep 17 00:00:00 2001 From: Spotika Date: Mon, 29 Apr 2024 17:50:01 +0300 Subject: [PATCH 19/94] chore: we can work with mongo in docker --- .gitignore | 1 + docker-compose.yml | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index f6b88e9..57c5f1b 100644 --- a/.gitignore +++ b/.gitignore @@ -177,3 +177,4 @@ run.sh test.sh ./data/* configs/main_config.json +mongo_data \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 887e48c..0a37142 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,9 +7,15 @@ services: dockerfile: Dockerfile args: - ELANTS_CONFIG_FILE_PATH=./configs/main_config.json - # depends_on: - # - db # db: + # image: mongo + # volumes: + # - ./mongo_data:/data/db + # - ./mongo_entrypoint:/docker-entrypoint-initdb.d + # env_file: + # - .env + # ports: + # - "27017:27017" testing: container_name: elants_backend_testing build: From 87d4801f29a0ada1e0814110f361114e0a7db875 Mon Sep 17 00:00:00 2001 From: Spotika Date: Mon, 29 Apr 2024 17:53:51 +0300 Subject: [PATCH 20/94] fix: fix logs --- src/config/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/__init__.py b/src/config/__init__.py index edfe144..beab2e4 100644 --- a/src/config/__init__.py +++ b/src/config/__init__.py @@ -37,10 +37,10 @@ def check_json_file(file_path: str) -> bool: ) sys.exit(1) -logger.info(f"Loading configuration from file {CONFIG_PATH_ENV_VARIABLE_NAME}") +logger.info(f"Loading configuration from file {config_path}") with open(config_path, "r", encoding="utf-8") as config_file: # parse && validate config file config: config_model.Config = config_model.Config.model_validate_json(config_file.read()) -logger.info(f"Successfully loaded configuration from file {CONFIG_PATH_ENV_VARIABLE_NAME}") +logger.info(f"Successfully loaded configuration from file {config_path}") logger.info(f"Current configuration: {config.model_dump_json(indent=4)}") From 0f1f8d42f4d4b63c4d07a4a0f106ca70b44aceb1 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 30 Apr 2024 11:57:06 +0300 Subject: [PATCH 21/94] refactor: delete useless code && comments --- docker-compose.yml | 10 ------ src/config/config_model.py | 66 -------------------------------------- 2 files changed, 76 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 0a37142..62ad5f2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,18 +7,8 @@ services: dockerfile: Dockerfile args: - ELANTS_CONFIG_FILE_PATH=./configs/main_config.json - # db: - # image: mongo - # volumes: - # - ./mongo_data:/data/db - # - ./mongo_entrypoint:/docker-entrypoint-initdb.d - # env_file: - # - .env - # ports: - # - "27017:27017" testing: container_name: elants_backend_testing build: context: . dockerfile: ./testing/Dockerfile - # linting: diff --git a/src/config/config_model.py b/src/config/config_model.py index b4d146d..45af3c9 100644 --- a/src/config/config_model.py +++ b/src/config/config_model.py @@ -35,69 +35,3 @@ class Config(BaseModel): rabbitmq: RabbitMQConfig auth: AuthConfig app_title: str - - - -# class Config: -# """Entire project config""" -# if any(arg_value is None for arg_value in [ -# os.environ.get("DB_CONNECT_URL"), -# os.environ.get("DB_NAME"), -# os.environ.get("COLLECTION_USERS"), -# os.environ.get("COLLECTION_ROLES"), -# os.environ.get("COLLECTION_GROUP_ROLES"), -# os.environ.get("COLLECTION_GROUPS"), -# os.environ.get("COLLECTION_DOMAIN"), -# os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES"), -# os.environ.get("REFRESH_TOKEN_EXPIRE_MINUTES"), -# os.environ.get("ALGORITHM"), -# os.environ.get("JWT_SECRET_KEY"), -# os.environ.get("JWT_REFRESH_SECRET_KEY"), -# os.environ.get("APP_TITLE") -# ]): -# logger.error([ -# os.environ.get("DB_CONNECT_URL"), -# os.environ.get("DB_NAME"), -# os.environ.get("COLLECTION_USERS"), -# os.environ.get("COLLECTION_ROLES"), -# os.environ.get("COLLECTION_GROUP_ROLES"), -# os.environ.get("COLLECTION_GROUPS"), -# os.environ.get("COLLECTION_DOMAIN"), -# os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES"), -# os.environ.get("REFRESH_TOKEN_EXPIRE_MINUTES"), -# os.environ.get("ALGORITHM"), -# os.environ.get("JWT_SECRET_KEY"), -# os.environ.get("JWT_REFRESH_SECRET_KEY"), -# os.environ.get("APP_TITLE") -# ]) -# sys.exit(1) -# db_connect_url: str = os.environ.get("DB_CONNECT_URL") or "" - -# db_name: str = os.environ.get("DB_NAME") or "" - -# class Collections: -# """Collection db names""" -# users = os.environ.get("COLLECTION_USERS") or "" -# roles = os.environ.get("COLLECTION_ROLES") or "" -# group_roles = os.environ.get("COLLECTION_GROUP_ROLES") or "" -# groups = os.environ.get("COLLECTION_GROUPS") or "" -# domain_router = os.environ.get("COLLECTION_DOMAIN") or "" -# internal_counters = os.environ.get("COLLECTION_INTERNAL_COUNTERS") or "" -# contests = os.environ.get("COLLECTION_CONTESTS") or "" -# problems = os.environ.get("COLLECTION_PROBLEMS") or "" -# submissions = os.environ.get("COLLECTION_SUBMISSIONS") or "" - -# class Auth: -# """Data for auth system""" -# ACCESS_TOKEN_EXPIRE_MINUTES = int(os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES") or "") -# REFRESH_TOKEN_EXPIRE_MINUTES = int(os.environ.get("REFRESH_TOKEN_EXPIRE_MINUTES") or "") -# ALGORITHM = os.environ.get("ALGORITHM") or "" - -# JWT_SECRET_KEY = os.environ.get("JWT_SECRET_KEY") or "" -# JWT_REFRESH_SECRET_KEY = os.environ.get("JWT_REFRESH_SECRET_KEY") or "" - -# app_title = os.environ.get("APP_TITLE") or "" -# elan_path = os.environ.get("ELAN_PATH") or "/ELAN" # FIXME NOT USED or user idk - -# # FIXME it may not work later -# rabbitmq_main_queue = os.environ.get("RABBITMQ_MAIN_QUEUE") or "INVOKER" From b7574dc7ecf084c555075325dd5956ee72e92d4c Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 30 Apr 2024 12:04:12 +0300 Subject: [PATCH 22/94] chore: create example docker-compose with ex. conf Example config was change to version with some null fields About fields and how fill them see https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-155 --- configs/example_config.json | 18 +++++++++--------- docker-compose-example.yml | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 docker-compose-example.yml diff --git a/configs/example_config.json b/configs/example_config.json index 5f600fc..d41f681 100644 --- a/configs/example_config.json +++ b/configs/example_config.json @@ -1,17 +1,17 @@ { "database": { - "connect_url": "mongodb://localhost:27017", - "name": "ELANDB", + "connect_url": null, + "name": null, "collections": { - "users": "Users", - "groups": "Groups", - "roles": "Roles", - "domains": "Domains", - "group_roles": "GroupRoles" + "users": null, + "groups": null, + "roles": null, + "domains": null, + "group_roles": null } }, "rabbitmq": { - "connect_url": "test urls://localhost" + "connect_url": null }, "auth": { "algorithm": "HS256", @@ -21,4 +21,4 @@ "jwt_refresh_secret_key": "jwt_refresh_secret_key" }, "app_title": null -} \ No newline at end of file +} diff --git a/docker-compose-example.yml b/docker-compose-example.yml new file mode 100644 index 0000000..bf45a03 --- /dev/null +++ b/docker-compose-example.yml @@ -0,0 +1,14 @@ +version: "3" + +services: + backend: + container_name: elants_backend + build: + dockerfile: Dockerfile + args: + - ELANTS_CONFIG_FILE_PATH=./configs/example_config.json + testing: + container_name: elants_backend_testing + build: + context: . + dockerfile: ./testing/Dockerfile From 6a44c34a214dc6a256bb4a015f3ebae8ba7c68c3 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 30 Apr 2024 12:41:15 +0300 Subject: [PATCH 23/94] chore: hide docker compose and create docker-compose example --- .gitignore | 3 ++- docker-compose.yml | 14 -------------- 2 files changed, 2 insertions(+), 15 deletions(-) delete mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore index 57c5f1b..b32a830 100644 --- a/.gitignore +++ b/.gitignore @@ -177,4 +177,5 @@ run.sh test.sh ./data/* configs/main_config.json -mongo_data \ No newline at end of file +mongo_data +docker-compose.yml \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 62ad5f2..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: "3" - -services: - backend: - container_name: elants_backend - build: - dockerfile: Dockerfile - args: - - ELANTS_CONFIG_FILE_PATH=./configs/main_config.json - testing: - container_name: elants_backend_testing - build: - context: . - dockerfile: ./testing/Dockerfile From debb50b5407853aa10e111205571d93ab9d38723 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 30 Apr 2024 12:43:05 +0300 Subject: [PATCH 24/94] chore: delete .env config --- example.env | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 example.env diff --git a/example.env b/example.env deleted file mode 100644 index cf76a43..0000000 --- a/example.env +++ /dev/null @@ -1,21 +0,0 @@ -# database -DB_CONNECT_URL=mongodb://localhost:27017 -DB_NAME=ELANDB - -# auth -ACCESS_TOKEN_EXPIRE_MINUTES=30 -REFRESH_TOKEN_EXPIRE_MINUTES=10080 -ALGORITHM=HS256 -JWT_SECRET_KEY=jwt_secret_key -JWT_REFRESH_SECRET_KEY=jwt_refresh_secret_key - -# misc -APP_TITLE="ELAN api" - -# collections -COLLECTION_USERS=Users -COLLECTION_ROLES=Roles -COLLECTION_GROUP_ROLES=GroupRoles -COLLECTION_GROUPS=Groups -COLLECTION_DOMAIN=Domains -COLLECTION_INTERNAL_COUNTERS=InternalCounters From ac3ed236f089e35fce343af879d2d40387c31cab Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 30 Apr 2024 17:01:40 +0300 Subject: [PATCH 25/94] fix: fix init config --- src/config/__init__.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/config/__init__.py b/src/config/__init__.py index beab2e4..68b6d5d 100644 --- a/src/config/__init__.py +++ b/src/config/__init__.py @@ -3,20 +3,20 @@ import sys from loguru import logger - from . import config_model -CONFIG_PATH_ENV_VARIABLE_NAME = "ELANTS_CONFIG_FILE_PATH" -config_path = os.getenv(CONFIG_PATH_ENV_VARIABLE_NAME) +_CONFIG_PATH_ENV_VARIABLE_NAME = "ELANTS_CONFIG_FILE_PATH" + +_config_path = os.getenv(_CONFIG_PATH_ENV_VARIABLE_NAME) -if config_path is None: # check for existing env variable +if _config_path is None: # check for existing env variable logger.error( - f"Environment variable {CONFIG_PATH_ENV_VARIABLE_NAME} is not set" + f"Environment variable {_CONFIG_PATH_ENV_VARIABLE_NAME} is not set" ) sys.exit(1) -def check_json_file(file_path: str) -> bool: +def _check_json_file(file_path: str) -> bool: """Check that file_path is a json file and exists Args: @@ -31,16 +31,19 @@ def check_json_file(file_path: str) -> bool: return True return False -if not check_json_file(config_path): # check_json_file +if not _check_json_file(_config_path): # check_json_file logger.error( - f"File {config_path} is not a json file or isnt exists" + f"File {_config_path} is not a json file or isnt exists" ) sys.exit(1) -logger.info(f"Loading configuration from file {config_path}") +def _load_config() -> config_model.Config: + """parse && validate config file""" + with open(_config_path, "r", encoding="utf-8") as config_file: + return config_model.Config.model_validate_json(config_file.read()) -with open(config_path, "r", encoding="utf-8") as config_file: # parse && validate config file - config: config_model.Config = config_model.Config.model_validate_json(config_file.read()) +logger.info(f"Loading configuration from file {_config_path}") +config = _load_config() -logger.info(f"Successfully loaded configuration from file {config_path}") +logger.info(f"Successfully loaded configuration from file {_config_path}") logger.info(f"Current configuration: {config.model_dump_json(indent=4)}") From 00c6cf6e93b21fe249b3ac5e46c02d1efa4c4bcf Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 30 Apr 2024 17:03:08 +0300 Subject: [PATCH 26/94] fix: add new default values to ex config --- configs/example_config.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/configs/example_config.json b/configs/example_config.json index d41f681..e35b3a2 100644 --- a/configs/example_config.json +++ b/configs/example_config.json @@ -1,13 +1,13 @@ { "database": { "connect_url": null, - "name": null, + "name": "ELANDB", "collections": { - "users": null, - "groups": null, - "roles": null, - "domains": null, - "group_roles": null + "users": "Users", + "groups": "Groups", + "roles": "Roles", + "domains": "Domains", + "group_roles": "GroupRoles" } }, "rabbitmq": { @@ -20,5 +20,5 @@ "jwt_access_secret_key": "jwt_access_secret_key", "jwt_refresh_secret_key": "jwt_refresh_secret_key" }, - "app_title": null + "app_title": "ELANTS API" } From cfe67cd822f1bac03843c8399d674029dd4b161f Mon Sep 17 00:00:00 2001 From: Andrew Cherkashin <81467323+Spotika@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:55:18 +0300 Subject: [PATCH 27/94] Total fix (#51) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: rebananing db module * replace motor with pymogo * remove database managers * make new autoincrement (delete class, create pure method) * create new field in config - "internal counters" * move annotations out of models * create schemas dir * create methods dir * create db and client variables in __init__ in db * refactor: slightly refactored schemas and models * dont care * refactor: refactor user base model * feat: collections mock * fix: replace db.get*...* by collections module * fix: improve type hints * fix: improve type hints x2 * feat: add indexes to users collection * feat: create indexes in db module * refactor: refactor role base model * refactor: refactor group base model * feat: add group member base model * feat: add group_members to collections * refactor: refactor contest base model * feat: add contest index * feat: add contest member base model * fix: fix clickup link * refactor: refactor entity model * refactor: refactor problem model * fix: fix typing error in MongoClient * refactor: refactor submission model * fix: fix annotations import * feat: add role code base model * fix: fix models __init__.py * refactor: some visual refactor * feat: user frendly config validation error * fix: fix circular imports. Breaking changes in auth module * feat: add mongo service to docker-compose Now mongodb only for backend. Added folder for mongodb data `mongodb_data` Changed connection string in example config to work with mongo in docker * refactor: remove all endpoints and refator main.py * fix: fix partial user indexes * refactor: clear all schemas * fix: fix docker compose * feat: run without docker * feat: new configs: with and without docker * feat: new option 'show_config' in config * feat: new response format implementation * ♻️ refactor(db): Change db/ directory hierarchy * 🔧 chore(gitignore): Update gitignore * 🐛 fix(db): Fix circular import * ✨ feat(api): Create endpoinds for test response specification * ✨ feat(api): Create response with custom error code * ♻️ refactor(auth): Move out shcme. Fix fole code naming * ♻️ refactor(auth): Move out schemas. Refactor naming in auth.utils + recreate main functions * 🐛 fix(auth): Fix imports * ✨ feat(methods): Create stub for getting user by id * ♻️ refactor(models): Change import structure * ✨ feat(auth): Create new auth_user dependency to auth through header * 🐛 fix(db): Replace ... = Field(...) by ... = ... * 🐛 fix(methods): Fix get methods * ✅ test: Make integration test which ruhs with docker * chore: general code structure refactor * refactor: refactor auth module * test: create test infra * refactor: fix pylint * chore: fix workflow actions versions * chore: try to change workflow node version * chore: change the latest version of actions in workflow * chore: test pyright workflow * chore: test pyright workflow * chore: add poetry to workflow * chore: fix all linters * chore: create test workflow * chore: fix test workflow * chore: fix test workflow * chore: fix test workflow * chore: fix test workflow * chore: fix test workflow * chore: show test logs through docker compose * chore: change actions target branch to master * feat(auth): create siginin and signup * feat: create super user on startup * feat: create super user on startup --------- Co-authored-by: Spotika --- .dockerignore | 2 + .github/workflows/mypy.yaml | 36 - .github/workflows/pylint.yaml | 9 +- .github/workflows/pyright.yaml | 37 + .github/workflows/test.yaml | 36 + .gitignore | 11 +- .gitmodules | 3 - .mypy.ini | 0 .pylintrc | 401 -- Dockerfile | 14 +- configs/example_config.json | 24 - configs/test.json | 11 + data/problems/problem1/example.01 | 2 - data/problems/problem1/example.01.a | 1 - data/problems/problem1/input.mdx | 3 - data/problems/problem1/legend.mdx | 5 - data/problems/problem1/notes.mdx | 3 - data/problems/problem1/output.mdx | 1 - data/problems/problem1/scoring.mdx | 14 - data/problems/problem2/example.01 | 2 - data/problems/problem2/example.01.a | 1 - data/problems/problem2/example.02 | 2 - data/problems/problem2/example.02.a | 1 - data/problems/problem2/input.mdx | 1 - data/problems/problem2/legend.mdx | 5 - data/problems/problem2/notes.mdx | 1 - data/problems/problem2/output.mdx | 1 - data/problems/problem2/scoring.mdx | 3 - .../contest1/submission10/solution.cpp | 1 - .../contest1/submission11/solution.cpp | 1 - .../contest1/submission12/solution.cpp | 1 - .../contest1/submission13/solution.cpp | 1 - .../contest1/submission14/solution.cpp | 1 - .../contest1/submission15/solution.cpp | 1 - .../contest1/submission16/solution.cpp | 377 -- .../contest1/submission2/solution.cpp | 10 - .../contest1/submission3/solution.cpp | 1 - .../contest1/submission4/solution.cpp | 20 - .../contest1/submission5/solution.cpp | 20 - .../contest1/submission6/solution.cpp | 1 - .../contest1/submission7/solution.cpp | 1 - .../contest1/submission8/solution.cpp | 1 - .../contest1/submission9/solution.cpp | 1 - docker-compose-example.yml | 14 - docker-compose.yml | 69 + manage.py | 41 - poetry.lock | 1437 ++--- pyproject.toml | 47 +- src/auth/__init__.py | 4 - src/auth/models.py | 0 src/auth/permissions.py | 14 - src/auth/token_schema.py | 8 - src/auth/utils.py | 197 - src/config/__init__.py | 52 +- src/config/config_model.py | 42 +- src/config/load_config.py | 36 + src/db/__init__.py | 30 +- src/db/client.py | 32 + src/db/helpers/abstract_database_manager.py | 29 - .../auto_increment_database_interface.py | 52 - src/db/managers/contest_database_manager.py | 57 - .../domain_router_database_manager.py | 84 - src/db/managers/group_database_manager.py | 53 - src/db/managers/problem_database_manager.py | 42 - src/db/managers/role_database_manager.py | 32 - .../managers/submission_database_manager.py | 65 - src/db/managers/user_database_manager.py | 74 - src/db/methods/__init__.py | 9 + src/db/methods/collections/__init__.py | 20 + src/db/methods/collections/collections.py | 21 + src/db/methods/domains.py | 43 + src/db/methods/helpers.py | 26 + src/db/methods/roles.py | 20 + src/db/methods/users.py | 36 + src/db/models/__init__.py | 8 - src/db/models/annotations/__init__.py | 13 - src/db/models/annotations/validators.py | 124 - src/db/models/contest.py | 50 - src/db/models/entity.py | 17 - src/db/models/group.py | 71 - src/db/models/problem.py | 12 - src/db/models/role.py | 20 - src/db/models/submission.py | 31 - src/db/models/user.py | 33 - src/db/mongo_manager.py | 66 - src/db/types/__init__.py | 13 + src/db/types/auth.py | 23 + src/db/types/common.py | 47 + src/db/types/contest.py | 22 + src/db/types/contest_member.py | 11 + src/db/types/domain.py | 14 + src/db/types/group.py | 15 + src/db/types/group_member.py | 13 + src/db/types/group_role.py | 13 + src/db/types/problem.py | 10 + src/db/types/role.py | 12 + src/db/types/submission.py | 17 + src/db/types/user.py | 23 + src/main.py | 77 +- src/producer.py | 17 - src/routers/__init__.py | 26 +- src/routers/auth.py | 74 + src/routers/auth_router.py | 123 - src/routers/contests.py | 4 + src/routers/contests_router.py | 119 - src/routers/groups.py | 4 + src/routers/groups_router.py | 140 - src/routers/problems.py | 4 + src/routers/problems_router.py | 165 - src/routers/roles.py | 4 + src/routers/roles_router.py | 43 - src/routers/service.py | 9 + src/routers/submissions.py | 4 + src/routers/submissions_router.py | 111 - src/routers/users.py | 4 + src/routers/users_router.py | 121 - src/utils/__init__.py | 5 - src/utils/auth/__init__.py | 17 + src/utils/auth/auth.py | 184 + src/utils/auth/permissions.py | 11 + src/utils/handlers.py | 78 +- src/utils/misc.py | 30 + src/utils/response.py | 64 + src/utils/response_utils.py | 93 - src/utils/schemas.py | 7 + src/utils/singleton.py | 11 - testing/Dockerfile | 13 - testing/core_db_test.py | 29 - testing/database_fixtures.py | 27 - testing/database_test/group_test.py | 83 - testing/database_test/user_test.py | 98 - testing/pytest.ini | 4 - testing/testing.env | 22 - testing/util_test.py | 32 - tests/.dockerignore | 1 + tests/Dockerfile | 11 + tests/jest.config.js | 4 + tests/package-lock.json | 4720 +++++++++++++++++ tests/package.json | 18 + tests/src/auth.test.ts | 116 + tests/src/helpers/constants.ts | 17 + tests/src/helpers/scripts.ts | 15 + tests/src/service.test.ts | 13 + tests/tsconfig.json | 13 + 144 files changed, 7007 insertions(+), 4210 deletions(-) create mode 100644 .dockerignore delete mode 100644 .github/workflows/mypy.yaml create mode 100644 .github/workflows/pyright.yaml create mode 100644 .github/workflows/test.yaml delete mode 100644 .gitmodules delete mode 100644 .mypy.ini delete mode 100644 .pylintrc delete mode 100644 configs/example_config.json create mode 100644 configs/test.json delete mode 100644 data/problems/problem1/example.01 delete mode 100644 data/problems/problem1/example.01.a delete mode 100644 data/problems/problem1/input.mdx delete mode 100644 data/problems/problem1/legend.mdx delete mode 100644 data/problems/problem1/notes.mdx delete mode 100644 data/problems/problem1/output.mdx delete mode 100644 data/problems/problem1/scoring.mdx delete mode 100644 data/problems/problem2/example.01 delete mode 100644 data/problems/problem2/example.01.a delete mode 100644 data/problems/problem2/example.02 delete mode 100644 data/problems/problem2/example.02.a delete mode 100644 data/problems/problem2/input.mdx delete mode 100644 data/problems/problem2/legend.mdx delete mode 100644 data/problems/problem2/notes.mdx delete mode 100644 data/problems/problem2/output.mdx delete mode 100644 data/problems/problem2/scoring.mdx delete mode 100644 data/submissions/contest1/submission10/solution.cpp delete mode 100644 data/submissions/contest1/submission11/solution.cpp delete mode 100644 data/submissions/contest1/submission12/solution.cpp delete mode 100644 data/submissions/contest1/submission13/solution.cpp delete mode 100644 data/submissions/contest1/submission14/solution.cpp delete mode 100644 data/submissions/contest1/submission15/solution.cpp delete mode 100644 data/submissions/contest1/submission16/solution.cpp delete mode 100644 data/submissions/contest1/submission2/solution.cpp delete mode 100644 data/submissions/contest1/submission3/solution.cpp delete mode 100644 data/submissions/contest1/submission4/solution.cpp delete mode 100644 data/submissions/contest1/submission5/solution.cpp delete mode 100644 data/submissions/contest1/submission6/solution.cpp delete mode 100644 data/submissions/contest1/submission7/solution.cpp delete mode 100644 data/submissions/contest1/submission8/solution.cpp delete mode 100644 data/submissions/contest1/submission9/solution.cpp delete mode 100644 docker-compose-example.yml create mode 100644 docker-compose.yml delete mode 100755 manage.py delete mode 100644 src/auth/__init__.py delete mode 100644 src/auth/models.py delete mode 100644 src/auth/permissions.py delete mode 100644 src/auth/token_schema.py delete mode 100644 src/auth/utils.py create mode 100644 src/config/load_config.py create mode 100644 src/db/client.py delete mode 100644 src/db/helpers/abstract_database_manager.py delete mode 100644 src/db/helpers/auto_increment_database_interface.py delete mode 100644 src/db/managers/contest_database_manager.py delete mode 100644 src/db/managers/domain_router_database_manager.py delete mode 100644 src/db/managers/group_database_manager.py delete mode 100644 src/db/managers/problem_database_manager.py delete mode 100644 src/db/managers/role_database_manager.py delete mode 100644 src/db/managers/submission_database_manager.py delete mode 100644 src/db/managers/user_database_manager.py create mode 100644 src/db/methods/__init__.py create mode 100644 src/db/methods/collections/__init__.py create mode 100644 src/db/methods/collections/collections.py create mode 100644 src/db/methods/domains.py create mode 100644 src/db/methods/helpers.py create mode 100644 src/db/methods/roles.py create mode 100644 src/db/methods/users.py delete mode 100644 src/db/models/__init__.py delete mode 100644 src/db/models/annotations/__init__.py delete mode 100644 src/db/models/annotations/validators.py delete mode 100644 src/db/models/contest.py delete mode 100644 src/db/models/entity.py delete mode 100644 src/db/models/group.py delete mode 100644 src/db/models/problem.py delete mode 100644 src/db/models/role.py delete mode 100644 src/db/models/submission.py delete mode 100644 src/db/models/user.py delete mode 100644 src/db/mongo_manager.py create mode 100644 src/db/types/__init__.py create mode 100644 src/db/types/auth.py create mode 100644 src/db/types/common.py create mode 100644 src/db/types/contest.py create mode 100644 src/db/types/contest_member.py create mode 100644 src/db/types/domain.py create mode 100644 src/db/types/group.py create mode 100644 src/db/types/group_member.py create mode 100644 src/db/types/group_role.py create mode 100644 src/db/types/problem.py create mode 100644 src/db/types/role.py create mode 100644 src/db/types/submission.py create mode 100644 src/db/types/user.py delete mode 100644 src/producer.py create mode 100644 src/routers/auth.py delete mode 100644 src/routers/auth_router.py create mode 100644 src/routers/contests.py delete mode 100644 src/routers/contests_router.py create mode 100644 src/routers/groups.py delete mode 100644 src/routers/groups_router.py create mode 100644 src/routers/problems.py delete mode 100644 src/routers/problems_router.py create mode 100644 src/routers/roles.py delete mode 100644 src/routers/roles_router.py create mode 100644 src/routers/service.py create mode 100644 src/routers/submissions.py delete mode 100644 src/routers/submissions_router.py create mode 100644 src/routers/users.py delete mode 100644 src/routers/users_router.py delete mode 100644 src/utils/__init__.py create mode 100644 src/utils/auth/__init__.py create mode 100644 src/utils/auth/auth.py create mode 100644 src/utils/auth/permissions.py create mode 100644 src/utils/misc.py create mode 100644 src/utils/response.py delete mode 100644 src/utils/response_utils.py create mode 100644 src/utils/schemas.py delete mode 100644 src/utils/singleton.py delete mode 100644 testing/Dockerfile delete mode 100644 testing/core_db_test.py delete mode 100644 testing/database_fixtures.py delete mode 100644 testing/database_test/group_test.py delete mode 100644 testing/database_test/user_test.py delete mode 100644 testing/pytest.ini delete mode 100644 testing/testing.env delete mode 100644 testing/util_test.py create mode 100644 tests/.dockerignore create mode 100644 tests/Dockerfile create mode 100644 tests/jest.config.js create mode 100644 tests/package-lock.json create mode 100644 tests/package.json create mode 100644 tests/src/auth.test.ts create mode 100644 tests/src/helpers/constants.ts create mode 100644 tests/src/helpers/scripts.ts create mode 100644 tests/src/service.test.ts create mode 100644 tests/tsconfig.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b8499fb --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +mongodb_data/ +tests/node_modules/ diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml deleted file mode 100644 index 256040e..0000000 --- a/.github/workflows/mypy.yaml +++ /dev/null @@ -1,36 +0,0 @@ -name: Python MyPy Check - -on: - push: - branches: - - master - -jobs: - mypy: - runs-on: ubuntu-latest - - steps: - - name: Check out code - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3.11 - - - name: Install dependencies - run: | - pip install mypy - - - name: Run MyPy - run: | - mypy --strict ${PWD} > mypy_output.txt - continue-on-error: true - - - name: Check MyPy results - run: | - cat mypy_output.txt - if ! grep -q "Success: no issues found in" mypy_output.txt; then - echo "MyPy issues found!" - exit 1 - fi diff --git a/.github/workflows/pylint.yaml b/.github/workflows/pylint.yaml index 6030873..4ad5acb 100644 --- a/.github/workflows/pylint.yaml +++ b/.github/workflows/pylint.yaml @@ -1,4 +1,4 @@ -name: Python Pylint Check +name: Pylint python check on: push: @@ -12,10 +12,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: 3.11 @@ -24,8 +24,7 @@ jobs: - name: Run pylint run: | - echo -e '"""Temp file for Github Action"""' > __init__.py - pylint ${PWD} > pylint_output.txt + pylint ${PWD}/src/** > pylint_output.txt continue-on-error: true - name: Check pylint results diff --git a/.github/workflows/pyright.yaml b/.github/workflows/pyright.yaml new file mode 100644 index 0000000..2e51c53 --- /dev/null +++ b/.github/workflows/pyright.yaml @@ -0,0 +1,37 @@ +name: Pyright python check + +on: + push: + branches: + - master + +jobs: + pyright: + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.11 + + - name: Install poetry + uses: abatilo/actions-poetry@v2 + + - name: Install dependencies + run: poetry install + + - name: Run Pyright + run: poetry run pyright > pyright_output.txt + continue-on-error: true + + - name: Check Pyright results + run: | + cat pyright_output.txt + if ! grep -q "0 errors, 0 warnings" pyright_output.txt; then + echo "Pyright issues found!" + exit 1 + fi diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..5e74fd8 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,36 @@ +name: Test API + +on: + push: + branches: + - master # Замените "main" на вашу основную ветку + +jobs: + test: + name: Run tests + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Compose + run: sudo apt install docker-compose + + - name: Build and run Docker Compose + run: | + sudo docker-compose up --build -d test + sudo docker-compose logs -f test > test_logs.txt + continue-on-error: true + + - name: Check test results + run: | + if grep -q "Test Suites: .* failed" test_logs.txt; then + echo "Tests failed" + exit 1 + else + echo "Tests passed" + fi + + - name: Show test logs + run: docker-compose logs --no-log-prefix test diff --git a/.gitignore b/.gitignore index b32a830..07948f0 100644 --- a/.gitignore +++ b/.gitignore @@ -160,8 +160,6 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ -frontend/ - ./src_cache ./data_cache ./future @@ -172,10 +170,7 @@ src_cache fastapi-async-mongodb .vscode -.ruff_cache -run.sh -test.sh ./data/* -configs/main_config.json -mongo_data -docker-compose.yml \ No newline at end of file +configs/main.json +mongodb_data/ +tests/node_modules/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 1980e4b..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -; [submodule "extern/runner"] -; path = extern/runner -; url = https://github.com/elansteam/runner.git diff --git a/.mypy.ini b/.mypy.ini deleted file mode 100644 index e69de29..0000000 diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index 9ba5ccf..0000000 --- a/.pylintrc +++ /dev/null @@ -1,401 +0,0 @@ -[MASTER] - -# Specify a configuration file. -#rcfile= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Add files or directories to the blacklist. They should be base names, not -# paths. -#ignore=third_party - -# Add files or directories matching the regex patterns to the blacklist. The -# regex matches against base names, not paths. -ignore-patterns=object_detection_grpc_client.py,prediction_pb2.py,prediction_pb2_grpc.py - -# Pickle collected data for later comparisons. -persistent=no - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -#load-plugins= - -# Use multiple processes to speed up Pylint. -jobs=4 - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -#confidence= - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -#enable= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -# -# Kubeflow disables string-interpolation because we are starting to use f -# style strings -disable=import-error,fixme,no-name-in-module,no-self-argument,unreachable,broad-exception-raised - -[REPORTS] - -# Set the output format. Available formats are text, parseable, colorized, msvs -# (visual studio) and html. You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". This option is deprecated -# and it will be removed in Pylint 2.0. -#files-output=no - -# Tells whether to display a full report or only the messages -reports=no - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - - -[BASIC] - -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,db,_ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -#name-group= - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty - -# Regular expression matching correct function names -#function-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for function names -#function-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct variable names -#variable-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for variable names -#variable-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct constant names -#const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Naming hint for constant names -#const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Regular expression matching correct attribute names -#attr-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for attribute names -#attr-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct argument names -#argument-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for argument names -#argument-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct class attribute names -#class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Naming hint for class attribute names -#class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct inline iteration names -#inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Naming hint for inline iteration names -#inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct class names -#class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Naming hint for class names -#class-name-hint=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression matching correct module names -#module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Naming hint for module names -#module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression matching correct method names -#method-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for method names -#method-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - - -[ELIF] - -# Maximum number of nested blocks for function / method body -#max-nested-blocks=5 - - -[TYPECHECK] - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -#ignored-modules= - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -#generated-members= - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - - -[FORMAT] - -# Maximum number of characters on a single line. -max-line-length=100 - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -#no-space-check=trailing-comma,dict-separator - -# Maximum number of lines in a module -max-module-lines=1000 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -# Use 2 spaces consistent with TensorFlow style. -indent-string=' ' - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - - -[VARIABLES] - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,future.builtins - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=4 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -#spelling-dict= - -# List of comma separated words that should not be checked. -#spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -#spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -#spelling-store-unknown-words=no - - -[IMPORTS] - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub,TERMIOS,Bastion,rexec - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -#import-graph= - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -#ext-import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -#int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -#known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=7 - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.* - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of return / yield for function / method body -#max-returns=6 - -# Maximum number of branch for function / method body -#max-branches=12 - -# Maximum number of statements in function / method body -#max-statements=50 - -# Maximum number of parents for a class (see R0901). -#max-parents=7 - -# Maximum number of attributes for a class (see R0902). -#max-attributes=7 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=0 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of boolean expressions in a if statement -#max-bool-expr=5 - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -#overgeneral-exceptions=Exception \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index d0d9759..96ef285 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,17 @@ FROM python:3.12.1-alpine3.19 -ARG ELANTS_CONFIG_FILE_PATH +ARG CONFIG_PATH COPY ./pyproject.toml ./pyproject.toml -RUN pip3 install poetry -RUN poetry install +RUN pip3 install poetry +RUN poetry install --no-root COPY ./src ./src -COPY $ELANTS_CONFIG_FILE_PATH /elants_config.json -WORKDIR ./src +COPY $CONFIG_PATH /config.json +WORKDIR /src -ENV ELANTS_CONFIG_FILE_PATH=/elants_config.json +ENV CONFIG_PATH=/config.json -CMD ["poetry", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"] +CMD ["poetry", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "4242"] diff --git a/configs/example_config.json b/configs/example_config.json deleted file mode 100644 index e35b3a2..0000000 --- a/configs/example_config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "database": { - "connect_url": null, - "name": "ELANDB", - "collections": { - "users": "Users", - "groups": "Groups", - "roles": "Roles", - "domains": "Domains", - "group_roles": "GroupRoles" - } - }, - "rabbitmq": { - "connect_url": null - }, - "auth": { - "algorithm": "HS256", - "access_token_expire_minutes": 30, - "refresh_token_expire_minutes": 10080, - "jwt_access_secret_key": "jwt_access_secret_key", - "jwt_refresh_secret_key": "jwt_refresh_secret_key" - }, - "app_title": "ELANTS API" -} diff --git a/configs/test.json b/configs/test.json new file mode 100644 index 0000000..be1166e --- /dev/null +++ b/configs/test.json @@ -0,0 +1,11 @@ +{ + "database": { + "connect_url": "mongodb://bulo4ka:ZOVSVO@db_test", + "name": "ELANDB" + }, + "auth": { + "jwt_access_secret_key": "jwt_access_secret_key", + "jwt_refresh_secret_key": "jwt_refresh_secret_key" + }, + "show_config": true +} diff --git a/data/problems/problem1/example.01 b/data/problems/problem1/example.01 deleted file mode 100644 index 6911b80..0000000 --- a/data/problems/problem1/example.01 +++ /dev/null @@ -1,2 +0,0 @@ -5 -1 3 5 4 diff --git a/data/problems/problem1/example.01.a b/data/problems/problem1/example.01.a deleted file mode 100644 index 0cfbf08..0000000 --- a/data/problems/problem1/example.01.a +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/data/problems/problem1/input.mdx b/data/problems/problem1/input.mdx deleted file mode 100644 index 0ea0f2c..0000000 --- a/data/problems/problem1/input.mdx +++ /dev/null @@ -1,3 +0,0 @@ -В первой строке через пробел вводятся два натуральных числа $n$ и $k$ ($2 \leqslant k \leqslant n \leqslant 10^5$). - -Во второй строке вводится $n$ натуральных чисел через пробел $a_i$ ($1\leqslant a_i \leqslant 10^9$) --- вредности оленей. \ No newline at end of file diff --git a/data/problems/problem1/legend.mdx b/data/problems/problem1/legend.mdx deleted file mode 100644 index e3dbb03..0000000 --- a/data/problems/problem1/legend.mdx +++ /dev/null @@ -1,5 +0,0 @@ -Каждый год Санта собирает себе новую упряжку из оленей. Около его дома есть загон, где живут $n$ оленей. Санта заметил, что рождественские олени --- необычные волшебные животные, все они по-разному реагируют на команды погонщика. Потому он считает, что каждый $i$-й олень обладает некоторой $\textit{вредностью}$ $a_i$, которая характеризуется натуральным числом. Запрягать волшебных животных в упряжку нужно определенным образом, чтобы они летели быстрее: необходимо расположить оленей в таком порядке, чтобы вредности соседних оленей отличались друг от друга как можно меньше. Санта хочет собрать упряжку из $k \leqslant n$ оленей. Помогите ему собрать самую лучшую упряжку. Более формально, из набора $a_1,\, a_2,\,\ldots,\,a_n$ требуется составить $k$-элемнтую последовательность $a_{i_1},\, a_{i_2},\,\ldots,\, a_{i_k}$ таким образом, чтобы сумма -$$ - S_{min} = \bigl | a_{i_2} - a_{i_1} \bigr | + \bigl | a_{i_3} - a_{i_2} \bigr | + \ldots + \bigl | a_{i_n} - a_{i_{n-1}} \bigr | -$$ -была минимальна. \ No newline at end of file diff --git a/data/problems/problem1/notes.mdx b/data/problems/problem1/notes.mdx deleted file mode 100644 index 92e1f1f..0000000 --- a/data/problems/problem1/notes.mdx +++ /dev/null @@ -1,3 +0,0 @@ -В первом примере можно взять оленей со значениями вредности 1 и 2 или 4 и 5 (в любом порядке). - -В втором примере необходимо взять в упряжку оленей со значениями вредности 1, 3 и 3 в таком или обратном порядке. \ No newline at end of file diff --git a/data/problems/problem1/output.mdx b/data/problems/problem1/output.mdx deleted file mode 100644 index 8693dd8..0000000 --- a/data/problems/problem1/output.mdx +++ /dev/null @@ -1 +0,0 @@ -Выведите минимальную возможную сумму $S_{\text{min}}$. \ No newline at end of file diff --git a/data/problems/problem1/scoring.mdx b/data/problems/problem1/scoring.mdx deleted file mode 100644 index 62c21a3..0000000 --- a/data/problems/problem1/scoring.mdx +++ /dev/null @@ -1,14 +0,0 @@ - -$$\begin{center} - \begin{tabular}{ | c | c | c | c | } \hline - \bf{Подгруппа} & - \bf{Доп. ограничения} & - \bf{Баллы} & - \bf{Требуемые подгруппы} \\ \hline - $0$ & тесты из условия & $0$ & --- \\ \hline - $1$ & $n \leqslant 100$, $k\leqslant 4$ & $10$ & --- \\ \hline - $2$ & $k = n$, $n \leqslant 100$ & $10$ & --- \\ \hline - $3$ & $k = n$ & $30$ & $2$ \\ \hline - $4$ & --- & $50$ & $1-3$ \\ \hline - \end{tabular} -\end{center}$$ \ No newline at end of file diff --git a/data/problems/problem2/example.01 b/data/problems/problem2/example.01 deleted file mode 100644 index 1e5752d..0000000 --- a/data/problems/problem2/example.01 +++ /dev/null @@ -1,2 +0,0 @@ -4 2 -1 5 2 4 diff --git a/data/problems/problem2/example.01.a b/data/problems/problem2/example.01.a deleted file mode 100644 index 56a6051..0000000 --- a/data/problems/problem2/example.01.a +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/data/problems/problem2/example.02 b/data/problems/problem2/example.02 deleted file mode 100644 index d09a642..0000000 --- a/data/problems/problem2/example.02 +++ /dev/null @@ -1,2 +0,0 @@ -8 3 -3 10 7 9 3 7 15 1 diff --git a/data/problems/problem2/example.02.a b/data/problems/problem2/example.02.a deleted file mode 100644 index d8263ee..0000000 --- a/data/problems/problem2/example.02.a +++ /dev/null @@ -1 +0,0 @@ -2 \ No newline at end of file diff --git a/data/problems/problem2/input.mdx b/data/problems/problem2/input.mdx deleted file mode 100644 index 7573c58..0000000 --- a/data/problems/problem2/input.mdx +++ /dev/null @@ -1 +0,0 @@ -В первой строке дано число $n$ ($0 \lt n \lt 2 * 10^5$). Во второй строке записано $n-1$ число - элементы перестановки $X$ без одного элемента ($0 \lt x_i \lt n + 1$). \ No newline at end of file diff --git a/data/problems/problem2/legend.mdx b/data/problems/problem2/legend.mdx deleted file mode 100644 index 95cd518..0000000 --- a/data/problems/problem2/legend.mdx +++ /dev/null @@ -1,5 +0,0 @@ -На день рождения Алене подарили перестановку $X$ длины $n$. Напомним, что перестановкой является упорядоченный набор из $n$ различных чисел от $1$ до $n$ (например, $\{1, 2, 3\}$ является перестановкой, а $\{1, 2, 4\}$ или $\{1, 2, 2\}$ - не является). - -К сожалению, когда Алена оставила свой подарок в комнате без присмотра, к нему подбежала собака Елань и съела одно число. - -Помогите Алене восстановить ее перестановку и узнать съеденное число, иначе получите ~тапочком по лицу~ реджект. \ No newline at end of file diff --git a/data/problems/problem2/notes.mdx b/data/problems/problem2/notes.mdx deleted file mode 100644 index 43b4bb9..0000000 --- a/data/problems/problem2/notes.mdx +++ /dev/null @@ -1 +0,0 @@ -Это тестовая задача, придуманная разработчиками тестирующей системы Elan. Она создана в Polygon и экспортирована в Elan. \ No newline at end of file diff --git a/data/problems/problem2/output.mdx b/data/problems/problem2/output.mdx deleted file mode 100644 index 588fc8b..0000000 --- a/data/problems/problem2/output.mdx +++ /dev/null @@ -1 +0,0 @@ -Выведите число, которое съела Елань. \ No newline at end of file diff --git a/data/problems/problem2/scoring.mdx b/data/problems/problem2/scoring.mdx deleted file mode 100644 index 32adb5c..0000000 --- a/data/problems/problem2/scoring.mdx +++ /dev/null @@ -1,3 +0,0 @@ -Потестовая оценка. В данной задаче используется 3 теста. Больше генерить мне было лень, да и зачем? Я верю, что вы легко справитесь с такой простой задачей. - ---- M F \ No newline at end of file diff --git a/data/submissions/contest1/submission10/solution.cpp b/data/submissions/contest1/submission10/solution.cpp deleted file mode 100644 index b8dc6c4..0000000 --- a/data/submissions/contest1/submission10/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -this is for BANANA \ No newline at end of file diff --git a/data/submissions/contest1/submission11/solution.cpp b/data/submissions/contest1/submission11/solution.cpp deleted file mode 100644 index 9118d6c..0000000 --- a/data/submissions/contest1/submission11/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -asdasd \ No newline at end of file diff --git a/data/submissions/contest1/submission12/solution.cpp b/data/submissions/contest1/submission12/solution.cpp deleted file mode 100644 index ed38c8a..0000000 --- a/data/submissions/contest1/submission12/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! test test trest \ No newline at end of file diff --git a/data/submissions/contest1/submission13/solution.cpp b/data/submissions/contest1/submission13/solution.cpp deleted file mode 100644 index 9118d6c..0000000 --- a/data/submissions/contest1/submission13/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -asdasd \ No newline at end of file diff --git a/data/submissions/contest1/submission14/solution.cpp b/data/submissions/contest1/submission14/solution.cpp deleted file mode 100644 index 8898c3e..0000000 --- a/data/submissions/contest1/submission14/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission15/solution.cpp b/data/submissions/contest1/submission15/solution.cpp deleted file mode 100644 index ed38c8a..0000000 --- a/data/submissions/contest1/submission15/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! test test trest \ No newline at end of file diff --git a/data/submissions/contest1/submission16/solution.cpp b/data/submissions/contest1/submission16/solution.cpp deleted file mode 100644 index 86bc8f6..0000000 --- a/data/submissions/contest1/submission16/solution.cpp +++ /dev/null @@ -1,377 +0,0 @@ -import {FC, useEffect, useState} from "react"; -import {useParams} from "react-router-dom"; -import { - Avatar, - Box, Button, - Stack, - SxProps, - ToggleButton, - ToggleButtonGroup, - Typography, - useTheme -} from "@mui/material"; -import {getCurrentUser, getWithToken, UserType} from "../../api/auth.tsx"; -import {ContestType, getContestById, getContestProblemsResources, sendSolution} from "../../api/api.tsx"; -import CheckIcon from "@mui/icons-material/Check"; -import ListAltIcon from '@mui/icons-material/ListAlt'; -import MenuIcon from '@mui/icons-material/Menu'; -import { Editor } from "@monaco-editor/react"; -import { ThemeModeContext } from "../../Theme/index.ts"; -import { useContext } from "react"; -import Latex from "react-latex-next"; - - -const ResultContent: FC = () => { - return
- -
-} - - -type TaskResources = { - name: string, - legend: string, - input: string, - output: string, - scoring: string, - notes: string, - id: number -} - -type TasksProps = { - contest_id: any -} - -const TasksContent: FC = (props: TasksProps) => { - - const [tasksResources, setTasksResources] = useState([]); - const [taskText, setTaskText] = useState("test") - const theme = useTheme(); - const { toggleTheme, themeMode, setThemeMode } = useContext(ThemeModeContext); - - const [currentState, setCurrentState] = useState(0); - - const [statesNum, setStatesNum] = useState(0); - - const [navButtons, setNavButtons] = useState([]); - - const [code, setCode] = useState(["// your code here!"]) - - let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - - const [editorState, setEditorState] = useState<"show" | "hide">("show") - - - useEffect(() => { - async function setup() { - const contestProblemsResources = await getContestProblemsResources(props.contest_id) - - - setStatesNum(contestProblemsResources.length) - let toChange = [] - for (let i = 0; i < contestProblemsResources.length; ++i) { - toChange.push( - - ) - } - setNavButtons(toChange); - setTasksResources(contestProblemsResources); - - let current_code = code; - while (current_code.length > contestProblemsResources.length) { - current_code.pop(); - } - - while (current_code.length < contestProblemsResources.length) { - current_code.push("// your code here!"); - } - - setCode(current_code); - } - - setup(); - - }, [currentState]); - - - const rootStyles: SxProps = { - padding: "40px", - height: "100%", - marginBottom: "40px" - } - - const navStyles: SxProps = { - display: "flex", - marginBottom: "30px", - overflow: "scroll", - justifyContent: "space-between" - } - - const taskStyles: SxProps = { - backgroundColor: `${theme.palette.surfaceContainerHigh.main}`, - borderRadius: "30px", - overflow: "scroll", - padding: "20px", - height: "100%", - paddingBottom: "150px", - display: "flex" - } - - - const handleChangeState = (e: any) => { - setCurrentState(e.target.value) - } - - - const handleSubmit = async () => { - const response = await sendSolution(props.contest_id, tasksResources[currentState].id, code[currentState]); - - if (response === undefined) { - alert("Error occured") - } else { - console.log(props.contest_id, tasksResources[currentState].id); - } - } - - // katex.render("c = \\pm\\sqrt{a^2 + b^2}", element, { - // throwOnError: false - // }); - - const handleEditorState = () => { - if (editorState == "show") { - setEditorState("hide") - } else { - setEditorState("show") - } - } - - return - - - {navButtons} - - - - - - - - - - {alphabet[currentState]}. {tasksResources[currentState]?.name} - - - - {tasksResources[currentState]?.legend|| ""} - - - - Формат входных данных - - - - {tasksResources[currentState]?.input || ""} - - - - Формат выходных данных - - - - {tasksResources[currentState]?.output || ""} - - - - Примечание - - - - {tasksResources[currentState]?.notes || ""} - - - - - - - { - let current_code = code; - current_code[currentState] = code_new; - setCode(current_code); - }} - /> - - - - - - - - -} - -const Contest: FC = () => { - - const [_user, setUser] = useState(); - const [contest, setContest] = useState(undefined); - - // const navigate = useNavigate(); - - const theme = useTheme(); - - const {id} = useParams(); - - - useEffect(() => { - async function temp() { - setUser(await getCurrentUser()); - // @ts-ignore - setContest(await getContestById(parseInt(id))); - } - - temp(); - }, []); - - const rootStyles: SxProps = { - borderRadius: "30px", - backgroundColor: `${theme.palette.surfaceContainerLow.main};`, - width: "100%", - minHeight: "100vh", - display: "flex", - position: "fixed", - // paddingBottom: "100px" - } - - const userStyles: SxProps = { - paddingTop: "80px", - display: "none", - flexDirection: "column", - alignItems: "center", - color: `${theme.palette.onSurface.main}`, - minWidth: "350px", - marginLeft: "30px" - } - - const navStyles: SxProps = { - width: "100%", - paddingLeft: "60px", - paddingRight: "300px", - flexGrow: "grow", - flexDirection: "column", - justifyContent: "center", - display: "flex", - position: "static" - } - - const avatarStyles = { - width: "300px", - height: "300px", - marginBottom: "10px" - } - - const navButtonsStyles: SxProps = { - width: "100%", - paddingBottom: "20px", - paddingTop: "20px" - } - - const dataStyles: SxProps = { - backgroundColor: `${theme.palette.surfaceContainerLowest.main}`, - borderRadius: "30px", - height: "100vh", - paddingBottom: "100px" - } - - const [alignment, setAlignment] = useState("tasks"); - - const [content, setContent] = useState(); - // - const handleAlignment = (_event: React.MouseEvent, - newAlignment: string) => { - if (newAlignment != null) { - setAlignment(newAlignment); - if (newAlignment == "tasks") { - setContent(); - } else if (newAlignment == "result") { - setContent(); - } - } - }; - - const nameStyles: SxProps = { - width: "300px", - whiteSpace: "pre-line", - wordWrap: "break-word", - overflow: "wrap" - } - - return <> - - - - - {contest?.name[0]}{contest?.name[1]} - - - - - {contest?.name} - - - - - {contest?.description} - - - - - - - - - {alignment === 'tasks' ? : } - Tasks - - - {alignment === "result" ? : } - Result - - - - - - {content} - {/* */} - - - - -} - - -export default Contest \ No newline at end of file diff --git a/data/submissions/contest1/submission2/solution.cpp b/data/submissions/contest1/submission2/solution.cpp deleted file mode 100644 index d30e7a3..0000000 --- a/data/submissions/contest1/submission2/solution.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include - -using namespace std; - -int main() { - int n; - cin >> n; - cout << n; - return 0; -} diff --git a/data/submissions/contest1/submission3/solution.cpp b/data/submissions/contest1/submission3/solution.cpp deleted file mode 100644 index 30d74d2..0000000 --- a/data/submissions/contest1/submission3/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file diff --git a/data/submissions/contest1/submission4/solution.cpp b/data/submissions/contest1/submission4/solution.cpp deleted file mode 100644 index 9a9e517..0000000 --- a/data/submissions/contest1/submission4/solution.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -using namespace std; - -int main() { - int n; - cin >> n; - - vector sp(n); - - for (int i = 0; i < n; ++i) { - cin >> sp[i]; - } - - for (int i = 0; i < n; ++i) { - cout << sp[i] << " "; - } - - return 0; -} \ No newline at end of file diff --git a/data/submissions/contest1/submission5/solution.cpp b/data/submissions/contest1/submission5/solution.cpp deleted file mode 100644 index 9a9e517..0000000 --- a/data/submissions/contest1/submission5/solution.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -using namespace std; - -int main() { - int n; - cin >> n; - - vector sp(n); - - for (int i = 0; i < n; ++i) { - cin >> sp[i]; - } - - for (int i = 0; i < n; ++i) { - cout << sp[i] << " "; - } - - return 0; -} \ No newline at end of file diff --git a/data/submissions/contest1/submission6/solution.cpp b/data/submissions/contest1/submission6/solution.cpp deleted file mode 100644 index 8898c3e..0000000 --- a/data/submissions/contest1/submission6/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission7/solution.cpp b/data/submissions/contest1/submission7/solution.cpp deleted file mode 100644 index 8898c3e..0000000 --- a/data/submissions/contest1/submission7/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission8/solution.cpp b/data/submissions/contest1/submission8/solution.cpp deleted file mode 100644 index 8898c3e..0000000 --- a/data/submissions/contest1/submission8/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! \ No newline at end of file diff --git a/data/submissions/contest1/submission9/solution.cpp b/data/submissions/contest1/submission9/solution.cpp deleted file mode 100644 index 8898c3e..0000000 --- a/data/submissions/contest1/submission9/solution.cpp +++ /dev/null @@ -1 +0,0 @@ -// your code here! \ No newline at end of file diff --git a/docker-compose-example.yml b/docker-compose-example.yml deleted file mode 100644 index bf45a03..0000000 --- a/docker-compose-example.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: "3" - -services: - backend: - container_name: elants_backend - build: - dockerfile: Dockerfile - args: - - ELANTS_CONFIG_FILE_PATH=./configs/example_config.json - testing: - container_name: elants_backend_testing - build: - context: . - dockerfile: ./testing/Dockerfile diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..66fbce1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,69 @@ +version: "3" + +services: + db: + container_name: elan_db + image: mongo + volumes: + - ./mongodb_data:/data/db + environment: + - MONGO_INITDB_ROOT_USERNAME=bulo4ka + - MONGO_INITDB_ROOT_PASSWORD=ZOVSVO + networks: + - main_network + api: + container_name: elan_api + build: + context: ./ + dockerfile: Dockerfile + args: + - CONFIG_PATH=./configs/main.json + ports: + - "4242:4242" + depends_on: + - db + networks: + - main_network + + db_test: + container_name: elan_db_test + image: mongo + environment: + - MONGO_INITDB_ROOT_USERNAME=bulo4ka + - MONGO_INITDB_ROOT_PASSWORD=ZOVSVO + networks: + - test_network + ports: + - "27017:27017" + api_test: + container_name: elan_api_test + build: + context: ./ + dockerfile: Dockerfile + args: + - CONFIG_PATH=./configs/test.json + depends_on: + - db_test + networks: + - test_network + healthcheck: + test: wget --no-verbose --tries=1 --spider http://api_test:4242/api/service/ping || exit 1 + interval: 10s + timeout: 10m + retries: 3 + test: + container_name: integration_test + build: + context: ./tests + dockerfile: ./Dockerfile + networks: + - test_network + depends_on: + api_test: + condition: service_healthy + tty: true + + +networks: + main_network: + test_network: diff --git a/manage.py b/manage.py deleted file mode 100755 index 175794b..0000000 --- a/manage.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -CLI for managing the project backend. -Use `python manage.py --help` for more information. -""" -import os -import argparse -import sys -from pathlib import Path -from loguru import logger - - -def parse_arguments(): - """Parsing args from command line""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='command', required=True, help='Available commands') - lint_parser = subparsers.add_parser('lint') - lint_parser.set_defaults(command='lint') - - return parser.parse_args() - - -def main(): # pylint: disable=missing-function-docstring - project_root = Path(__file__).resolve().parent - sys.path.append(str(project_root) + "/src") - args = parse_arguments() - - # Check the command and execute the corresponding logic - match args.command: - case "lint": # run linting - logger.info("Running pylint...") - os.system("pylint --recursive=y ./src/") - logger.info("Running ruff...") - os.system("ruff src/") - logger.info("Running mypy...") - os.system("mypy --strict ./src/") - case _: - print(f"Unknown command: {args.command}") - - -if __name__ == "__main__": - main() diff --git a/poetry.lock b/poetry.lock index d846b2a..ff9f758 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,145 +1,58 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "annotated-types" -version = "0.6.0" +version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" files = [ - {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, - {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] [[package]] name = "anyio" -version = "3.7.1" +version = "4.4.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, - {file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, + {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, + {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, ] [package.dependencies] -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" [package.extras] -doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] -test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (<0.22)"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] [[package]] name = "astroid" -version = "3.0.2" +version = "3.2.4" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.8.0" files = [ - {file = "astroid-3.0.2-py3-none-any.whl", hash = "sha256:d6e62862355f60e716164082d6b4b041d38e2a8cf1c7cd953ded5108bac8ff5c"}, - {file = "astroid-3.0.2.tar.gz", hash = "sha256:4a61cf0a59097c7bb52689b0fd63717cd2a8a14dc9f1eee97b82d814881c8c91"}, -] - -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} - -[[package]] -name = "attrs" -version = "23.2.0" -description = "Classes Without Boilerplate" -optional = false -python-versions = ">=3.7" -files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "astroid-3.2.4-py3-none-any.whl", hash = "sha256:413658a61eeca6202a59231abb473f932038fbcbf1666587f66d482083413a25"}, + {file = "astroid-3.2.4.tar.gz", hash = "sha256:0e14202810b30da1b735827f78f5157be2bbd4a7a59b7707ca0bfc2fb4c0063a"}, ] -[package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] - [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] -[[package]] -name = "cffi" -version = "1.16.0" -description = "Foreign Function Interface for Python calling C code." -optional = false -python-versions = ">=3.8" -files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, -] - -[package.dependencies] -pycparser = "*" - [[package]] name = "click" version = "8.1.7" @@ -165,23 +78,6 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[[package]] -name = "colorlog" -version = "6.8.2" -description = "Add colours to the output of Python's logging module." -optional = false -python-versions = ">=3.6" -files = [ - {file = "colorlog-6.8.2-py3-none-any.whl", hash = "sha256:4dcbb62368e2800cb3c5abd348da7e53f6c362dda502ec27c560b2e58a66bd33"}, - {file = "colorlog-6.8.2.tar.gz", hash = "sha256:3e3e079a41feb5a1b64f978b5ea4f46040a94f11f0e8bbb8261e3dbbeca64d44"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} - -[package.extras] -development = ["black", "flake8", "mypy", "pytest", "types-colorama"] - [[package]] name = "dill" version = "0.3.8" @@ -199,33 +95,33 @@ profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "dnspython" -version = "2.5.0" +version = "2.6.1" description = "DNS toolkit" optional = false python-versions = ">=3.8" files = [ - {file = "dnspython-2.5.0-py3-none-any.whl", hash = "sha256:6facdf76b73c742ccf2d07add296f178e629da60be23ce4b0a9c927b1e02c3a6"}, - {file = "dnspython-2.5.0.tar.gz", hash = "sha256:a0034815a59ba9ae888946be7ccca8f7c157b286f8455b379c692efb51022a15"}, + {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, + {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, ] [package.extras] -dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=5.0.3)", "mypy (>=1.0.1)", "pylint (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0.0)", "sphinx (>=7.0.0)", "twine (>=4.0.0)", "wheel (>=0.41.0)"] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] dnssec = ["cryptography (>=41)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.25.1)"] -doq = ["aioquic (>=0.9.20)"] -idna = ["idna (>=2.1)"] -trio = ["trio (>=0.14)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] +doq = ["aioquic (>=0.9.25)"] +idna = ["idna (>=3.6)"] +trio = ["trio (>=0.23)"] wmi = ["wmi (>=1.5.1)"] [[package]] name = "ecdsa" -version = "0.18.0" +version = "0.19.0" description = "ECDSA cryptographic signature library (pure python)" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.6" files = [ - {file = "ecdsa-0.18.0-py2.py3-none-any.whl", hash = "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd"}, - {file = "ecdsa-0.18.0.tar.gz", hash = "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49"}, + {file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"}, + {file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"}, ] [package.dependencies] @@ -236,38 +132,61 @@ gmpy = ["gmpy"] gmpy2 = ["gmpy2"] [[package]] -name = "exceptiongroup" -version = "1.2.0" -description = "Backport of PEP 654 (exception groups)" +name = "email-validator" +version = "2.2.0" +description = "A robust email address syntax and deliverability validation library." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"}, + {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"}, ] -[package.extras] -test = ["pytest (>=6)"] +[package.dependencies] +dnspython = ">=2.0.0" +idna = ">=2.0.0" [[package]] name = "fastapi" -version = "0.104.1" +version = "0.111.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.104.1-py3-none-any.whl", hash = "sha256:752dc31160cdbd0436bb93bad51560b57e525cbb1d4bbf6f4904ceee75548241"}, - {file = "fastapi-0.104.1.tar.gz", hash = "sha256:e5e4540a7c5e1dcfbbcf5b903c234feddcdcd881f191977a1c5dfd917487e7ae"}, + {file = "fastapi-0.111.1-py3-none-any.whl", hash = "sha256:4f51cfa25d72f9fbc3280832e84b32494cf186f50158d364a8765aabf22587bf"}, + {file = "fastapi-0.111.1.tar.gz", hash = "sha256:ddd1ac34cb1f76c2e2d7f8545a4bcb5463bce4834e81abf0b189e0c359ab2413"}, ] [package.dependencies] -anyio = ">=3.7.1,<4.0.0" +email_validator = ">=2.0.0" +fastapi-cli = ">=0.0.2" +httpx = ">=0.23.0" +jinja2 = ">=2.11.2" pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.27.0,<0.28.0" +python-multipart = ">=0.0.7" +starlette = ">=0.37.2,<0.38.0" typing-extensions = ">=4.8.0" +uvicorn = {version = ">=0.12.0", extras = ["standard"]} [package.extras] -all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "fastapi-cli" +version = "0.0.4" +description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fastapi_cli-0.0.4-py3-none-any.whl", hash = "sha256:a2552f3a7ae64058cdbb530be6fa6dbfc975dc165e4fa66d224c3d396e25e809"}, + {file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"}, +] + +[package.dependencies] +typer = ">=0.12.3" + +[package.extras] +standard = ["fastapi", "uvicorn[standard] (>=0.15.0)"] [[package]] name = "h11" @@ -282,13 +201,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.2" +version = "1.0.5" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, - {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, + {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, + {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, ] [package.dependencies] @@ -299,17 +218,65 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.23.0)"] +trio = ["trio (>=0.22.0,<0.26.0)"] + +[[package]] +name = "httptools" +version = "0.6.1" +description = "A collection of framework independent HTTP protocol utils." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"}, + {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"}, + {file = "httptools-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58"}, + {file = "httptools-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185"}, + {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142"}, + {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658"}, + {file = "httptools-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b"}, + {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1"}, + {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0"}, + {file = "httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc"}, + {file = "httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2"}, + {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837"}, + {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d"}, + {file = "httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3"}, + {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0"}, + {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2"}, + {file = "httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90"}, + {file = "httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503"}, + {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84"}, + {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb"}, + {file = "httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949"}, + {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3"}, + {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb"}, + {file = "httptools-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97"}, + {file = "httptools-0.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3"}, + {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4"}, + {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf"}, + {file = "httptools-0.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084"}, + {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3"}, + {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e"}, + {file = "httptools-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d"}, + {file = "httptools-0.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da"}, + {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81"}, + {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a"}, + {file = "httptools-0.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e"}, + {file = "httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a"}, +] + +[package.extras] +test = ["Cython (>=0.29.24,<0.30.0)"] [[package]] name = "httpx" -version = "0.26.0" +version = "0.27.0" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd"}, - {file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf"}, + {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, + {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, ] [package.dependencies] @@ -327,24 +294,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, -] - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -362,15 +318,22 @@ files = [ colors = ["colorama (>=0.4.6)"] [[package]] -name = "logging" -version = "0.4.9.6" -description = "A logging module for Python" +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "logging-0.4.9.6.tar.gz", hash = "sha256:26f6b50773f085042d301085bd1bf5d9f3735704db9f37c1ce6d8b85c38f2417"}, + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, ] +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + [[package]] name = "loguru" version = "0.7.2" @@ -390,121 +353,129 @@ win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.4.1)", "mypy (==v1.5.1)", "pre-commit (==3.4.0)", "pytest (==6.1.2)", "pytest (==7.4.0)", "pytest-cov (==2.12.1)", "pytest-cov (==4.1.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.0.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.3.0)", "tox (==3.27.1)", "tox (==4.11.0)"] [[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - -[[package]] -name = "motor" -version = "3.3.2" -description = "Non-blocking MongoDB driver for Tornado or asyncio" +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "motor-3.3.2-py3-none-any.whl", hash = "sha256:6fe7e6f0c4f430b9e030b9d22549b732f7c2226af3ab71ecc309e4a1b7d19953"}, - {file = "motor-3.3.2.tar.gz", hash = "sha256:d2fc38de15f1c8058f389c1a44a4d4105c0405c48c061cd492a654496f7bc26a"}, + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, ] [package.dependencies] -pymongo = ">=4.5,<5" +mdurl = ">=0.1,<1.0" [package.extras] -aws = ["pymongo[aws] (>=4.5,<5)"] -encryption = ["pymongo[encryption] (>=4.5,<5)"] -gssapi = ["pymongo[gssapi] (>=4.5,<5)"] -ocsp = ["pymongo[ocsp] (>=4.5,<5)"] -snappy = ["pymongo[snappy] (>=4.5,<5)"] -srv = ["pymongo[srv] (>=4.5,<5)"] -test = ["aiohttp (<3.8.6)", "mockupdb", "motor[encryption]", "pytest (>=7)", "tornado (>=5)"] -zstd = ["pymongo[zstd] (>=4.5,<5)"] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] -name = "mypy" -version = "1.8.0" -description = "Optional static typing for Python" +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, - {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, - {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, - {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, - {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, - {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, - {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, - {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, - {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, - {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, - {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, - {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, - {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, - {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, - {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, - {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, - {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, - {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, - {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] -[package.dependencies] -mypy-extensions = ">=1.0.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=4.1.0" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -install-types = ["pip"] -mypyc = ["setuptools (>=50)"] -reports = ["lxml"] - [[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] [[package]] -name = "outcome" -version = "1.3.0.post0" -description = "Capture the outcome of Python function calls." +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" optional = false python-versions = ">=3.7" files = [ - {file = "outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b"}, - {file = "outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8"}, + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] -[package.dependencies] -attrs = ">=19.2.0" - [[package]] -name = "packaging" -version = "23.2" -description = "Core utilities for Python packages" +name = "nodeenv" +version = "1.9.1" +description = "Node.js virtual environment builder" optional = false -python-versions = ">=3.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] [[package]] @@ -524,207 +495,191 @@ bcrypt = ["bcrypt (>=3.1.0)"] build-docs = ["cloud-sptheme (>=1.10.1)", "sphinx (>=1.6)", "sphinxcontrib-fulltoc (>=1.2.0)"] totp = ["cryptography"] -[[package]] -name = "pika" -version = "1.3.2" -description = "Pika Python AMQP Client Library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pika-1.3.2-py3-none-any.whl", hash = "sha256:0779a7c1fafd805672796085560d290213a465e4f6f76a6fb19e378d8041a14f"}, - {file = "pika-1.3.2.tar.gz", hash = "sha256:b2a327ddddf8570b4965b3576ac77091b850262d34ce8c1d8cb4e4146aa4145f"}, -] - -[package.extras] -gevent = ["gevent"] -tornado = ["tornado"] -twisted = ["twisted"] - [[package]] name = "platformdirs" -version = "4.1.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -optional = false -python-versions = ">=3.8" -files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, -] - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] - -[[package]] -name = "pluggy" -version = "1.4.0" -description = "plugin and hook calling mechanisms for python" +version = "4.2.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, ] [package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] [[package]] name = "pyasn1" -version = "0.5.1" +version = "0.6.0" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -files = [ - {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, - {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, -] - -[[package]] -name = "pycparser" -version = "2.21" -description = "C parser in Python" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"}, + {file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"}, ] [[package]] name = "pydantic" -version = "2.6.0" +version = "2.8.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.0-py3-none-any.whl", hash = "sha256:1440966574e1b5b99cf75a13bec7b20e3512e8a61b894ae252f56275e2c465ae"}, - {file = "pydantic-2.6.0.tar.gz", hash = "sha256:ae887bd94eb404b09d86e4d12f93893bdca79d766e738528c6fa1c849f3c6bcf"}, + {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, + {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.16.1" -typing-extensions = ">=4.6.1" +pydantic-core = "2.20.1" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] [package.extras] email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.16.1" -description = "" +version = "2.20.1" +description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.16.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:300616102fb71241ff477a2cbbc847321dbec49428434a2f17f37528721c4948"}, - {file = "pydantic_core-2.16.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5511f962dd1b9b553e9534c3b9c6a4b0c9ded3d8c2be96e61d56f933feef9e1f"}, - {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98f0edee7ee9cc7f9221af2e1b95bd02810e1c7a6d115cfd82698803d385b28f"}, - {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9795f56aa6b2296f05ac79d8a424e94056730c0b860a62b0fdcfe6340b658cc8"}, - {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c45f62e4107ebd05166717ac58f6feb44471ed450d07fecd90e5f69d9bf03c48"}, - {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:462d599299c5971f03c676e2b63aa80fec5ebc572d89ce766cd11ca8bcb56f3f"}, - {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ebaa4bf6386a3b22eec518da7d679c8363fb7fb70cf6972161e5542f470798"}, - {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:99f9a50b56713a598d33bc23a9912224fc5d7f9f292444e6664236ae471ddf17"}, - {file = "pydantic_core-2.16.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8ec364e280db4235389b5e1e6ee924723c693cbc98e9d28dc1767041ff9bc388"}, - {file = "pydantic_core-2.16.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:653a5dfd00f601a0ed6654a8b877b18d65ac32c9d9997456e0ab240807be6cf7"}, - {file = "pydantic_core-2.16.1-cp310-none-win32.whl", hash = "sha256:1661c668c1bb67b7cec96914329d9ab66755911d093bb9063c4c8914188af6d4"}, - {file = "pydantic_core-2.16.1-cp310-none-win_amd64.whl", hash = "sha256:561be4e3e952c2f9056fba5267b99be4ec2afadc27261505d4992c50b33c513c"}, - {file = "pydantic_core-2.16.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:102569d371fadc40d8f8598a59379c37ec60164315884467052830b28cc4e9da"}, - {file = "pydantic_core-2.16.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:735dceec50fa907a3c314b84ed609dec54b76a814aa14eb90da31d1d36873a5e"}, - {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e83ebbf020be727d6e0991c1b192a5c2e7113eb66e3def0cd0c62f9f266247e4"}, - {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:30a8259569fbeec49cfac7fda3ec8123486ef1b729225222f0d41d5f840b476f"}, - {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:920c4897e55e2881db6a6da151198e5001552c3777cd42b8a4c2f72eedc2ee91"}, - {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5247a3d74355f8b1d780d0f3b32a23dd9f6d3ff43ef2037c6dcd249f35ecf4c"}, - {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d5bea8012df5bb6dda1e67d0563ac50b7f64a5d5858348b5c8cb5043811c19d"}, - {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ed3025a8a7e5a59817b7494686d449ebfbe301f3e757b852c8d0d1961d6be864"}, - {file = "pydantic_core-2.16.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06f0d5a1d9e1b7932477c172cc720b3b23c18762ed7a8efa8398298a59d177c7"}, - {file = "pydantic_core-2.16.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:150ba5c86f502c040b822777e2e519b5625b47813bd05f9273a8ed169c97d9ae"}, - {file = "pydantic_core-2.16.1-cp311-none-win32.whl", hash = "sha256:d6cbdf12ef967a6aa401cf5cdf47850559e59eedad10e781471c960583f25aa1"}, - {file = "pydantic_core-2.16.1-cp311-none-win_amd64.whl", hash = "sha256:afa01d25769af33a8dac0d905d5c7bb2d73c7c3d5161b2dd6f8b5b5eea6a3c4c"}, - {file = "pydantic_core-2.16.1-cp311-none-win_arm64.whl", hash = "sha256:1a2fe7b00a49b51047334d84aafd7e39f80b7675cad0083678c58983662da89b"}, - {file = "pydantic_core-2.16.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f478ec204772a5c8218e30eb813ca43e34005dff2eafa03931b3d8caef87d51"}, - {file = "pydantic_core-2.16.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1936ef138bed2165dd8573aa65e3095ef7c2b6247faccd0e15186aabdda7f66"}, - {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99d3a433ef5dc3021c9534a58a3686c88363c591974c16c54a01af7efd741f13"}, - {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd88f40f2294440d3f3c6308e50d96a0d3d0973d6f1a5732875d10f569acef49"}, - {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fac641bbfa43d5a1bed99d28aa1fded1984d31c670a95aac1bf1d36ac6ce137"}, - {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72bf9308a82b75039b8c8edd2be2924c352eda5da14a920551a8b65d5ee89253"}, - {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb4363e6c9fc87365c2bc777a1f585a22f2f56642501885ffc7942138499bf54"}, - {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:20f724a023042588d0f4396bbbcf4cffd0ddd0ad3ed4f0d8e6d4ac4264bae81e"}, - {file = "pydantic_core-2.16.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fb4370b15111905bf8b5ba2129b926af9470f014cb0493a67d23e9d7a48348e8"}, - {file = "pydantic_core-2.16.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23632132f1fd608034f1a56cc3e484be00854db845b3a4a508834be5a6435a6f"}, - {file = "pydantic_core-2.16.1-cp312-none-win32.whl", hash = "sha256:b9f3e0bffad6e238f7acc20c393c1ed8fab4371e3b3bc311020dfa6020d99212"}, - {file = "pydantic_core-2.16.1-cp312-none-win_amd64.whl", hash = "sha256:a0b4cfe408cd84c53bab7d83e4209458de676a6ec5e9c623ae914ce1cb79b96f"}, - {file = "pydantic_core-2.16.1-cp312-none-win_arm64.whl", hash = "sha256:d195add190abccefc70ad0f9a0141ad7da53e16183048380e688b466702195dd"}, - {file = "pydantic_core-2.16.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:502c062a18d84452858f8aea1e520e12a4d5228fc3621ea5061409d666ea1706"}, - {file = "pydantic_core-2.16.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d8c032ccee90b37b44e05948b449a2d6baed7e614df3d3f47fe432c952c21b60"}, - {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:920f4633bee43d7a2818e1a1a788906df5a17b7ab6fe411220ed92b42940f818"}, - {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f5d37ff01edcbace53a402e80793640c25798fb7208f105d87a25e6fcc9ea06"}, - {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:399166f24c33a0c5759ecc4801f040dbc87d412c1a6d6292b2349b4c505effc9"}, - {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ac89ccc39cd1d556cc72d6752f252dc869dde41c7c936e86beac5eb555041b66"}, - {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73802194f10c394c2bedce7a135ba1d8ba6cff23adf4217612bfc5cf060de34c"}, - {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8fa00fa24ffd8c31fac081bf7be7eb495be6d248db127f8776575a746fa55c95"}, - {file = "pydantic_core-2.16.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:601d3e42452cd4f2891c13fa8c70366d71851c1593ed42f57bf37f40f7dca3c8"}, - {file = "pydantic_core-2.16.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07982b82d121ed3fc1c51faf6e8f57ff09b1325d2efccaa257dd8c0dd937acca"}, - {file = "pydantic_core-2.16.1-cp38-none-win32.whl", hash = "sha256:d0bf6f93a55d3fa7a079d811b29100b019784e2ee6bc06b0bb839538272a5610"}, - {file = "pydantic_core-2.16.1-cp38-none-win_amd64.whl", hash = "sha256:fbec2af0ebafa57eb82c18c304b37c86a8abddf7022955d1742b3d5471a6339e"}, - {file = "pydantic_core-2.16.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a497be217818c318d93f07e14502ef93d44e6a20c72b04c530611e45e54c2196"}, - {file = "pydantic_core-2.16.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:694a5e9f1f2c124a17ff2d0be613fd53ba0c26de588eb4bdab8bca855e550d95"}, - {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d4dfc66abea3ec6d9f83e837a8f8a7d9d3a76d25c9911735c76d6745950e62c"}, - {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8655f55fe68c4685673265a650ef71beb2d31871c049c8b80262026f23605ee3"}, - {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21e3298486c4ea4e4d5cc6fb69e06fb02a4e22089304308817035ac006a7f506"}, - {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71b4a48a7427f14679f0015b13c712863d28bb1ab700bd11776a5368135c7d60"}, - {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dca874e35bb60ce4f9f6665bfbfad050dd7573596608aeb9e098621ac331dc"}, - {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fa496cd45cda0165d597e9d6f01e36c33c9508f75cf03c0a650018c5048f578e"}, - {file = "pydantic_core-2.16.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5317c04349472e683803da262c781c42c5628a9be73f4750ac7d13040efb5d2d"}, - {file = "pydantic_core-2.16.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:42c29d54ed4501a30cd71015bf982fa95e4a60117b44e1a200290ce687d3e640"}, - {file = "pydantic_core-2.16.1-cp39-none-win32.whl", hash = "sha256:ba07646f35e4e49376c9831130039d1b478fbfa1215ae62ad62d2ee63cf9c18f"}, - {file = "pydantic_core-2.16.1-cp39-none-win_amd64.whl", hash = "sha256:2133b0e412a47868a358713287ff9f9a328879da547dc88be67481cdac529118"}, - {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d25ef0c33f22649b7a088035fd65ac1ce6464fa2876578df1adad9472f918a76"}, - {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:99c095457eea8550c9fa9a7a992e842aeae1429dab6b6b378710f62bfb70b394"}, - {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b49c604ace7a7aa8af31196abbf8f2193be605db6739ed905ecaf62af31ccae0"}, - {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c56da23034fe66221f2208c813d8aa509eea34d97328ce2add56e219c3a9f41c"}, - {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cebf8d56fee3b08ad40d332a807ecccd4153d3f1ba8231e111d9759f02edfd05"}, - {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:1ae8048cba95f382dba56766525abca438328455e35c283bb202964f41a780b0"}, - {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:780daad9e35b18d10d7219d24bfb30148ca2afc309928e1d4d53de86822593dc"}, - {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c94b5537bf6ce66e4d7830c6993152940a188600f6ae044435287753044a8fe2"}, - {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:adf28099d061a25fbcc6531febb7a091e027605385de9fe14dd6a97319d614cf"}, - {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:644904600c15816a1f9a1bafa6aab0d21db2788abcdf4e2a77951280473f33e1"}, - {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87bce04f09f0552b66fca0c4e10da78d17cb0e71c205864bab4e9595122cb9d9"}, - {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:877045a7969ace04d59516d5d6a7dee13106822f99a5d8df5e6822941f7bedc8"}, - {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9c46e556ee266ed3fb7b7a882b53df3c76b45e872fdab8d9cf49ae5e91147fd7"}, - {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4eebbd049008eb800f519578e944b8dc8e0f7d59a5abb5924cc2d4ed3a1834ff"}, - {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:c0be58529d43d38ae849a91932391eb93275a06b93b79a8ab828b012e916a206"}, - {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b1fc07896fc1851558f532dffc8987e526b682ec73140886c831d773cef44b76"}, - {file = "pydantic_core-2.16.1.tar.gz", hash = "sha256:daff04257b49ab7f4b3f73f98283d3dbb1a65bf3500d55c7beac3c66c310fe34"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, + {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, + {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, + {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, + {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, + {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, + {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, + {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, + {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, + {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, + {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, + {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, + {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, + {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, + {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, + {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, + {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, + {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, + {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, + {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, + {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, + {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, + {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, + {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, + {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, + {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, + {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, + {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, + {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, + {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, + {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, + {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, + {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, ] [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +[[package]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + [[package]] name = "pylint" -version = "3.0.3" +version = "3.2.6" description = "python code static checker" optional = false python-versions = ">=3.8.0" files = [ - {file = "pylint-3.0.3-py3-none-any.whl", hash = "sha256:7a1585285aefc5165db81083c3e06363a27448f6b467b3b0f30dbd0ac1f73810"}, - {file = "pylint-3.0.3.tar.gz", hash = "sha256:58c2398b0301e049609a8429789ec6edf3aabe9b6c5fec916acd18639c16de8b"}, + {file = "pylint-3.2.6-py3-none-any.whl", hash = "sha256:03c8e3baa1d9fb995b12c1dbe00aa6c4bcef210c2a2634374aedeb22fb4a8f8f"}, + {file = "pylint-3.2.6.tar.gz", hash = "sha256:a5d01678349454806cff6d886fb072294f56a58c4761278c97fb557d708e1eb3"}, ] [package.dependencies] -astroid = ">=3.0.1,<=3.1.0-dev0" +astroid = ">=3.2.4,<=3.3.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ - {version = ">=0.2", markers = "python_version < \"3.11\""}, {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, ] isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} tomlkit = ">=0.10.1" [package.extras] @@ -733,101 +688,70 @@ testutils = ["gitpython (>3)"] [[package]] name = "pymongo" -version = "4.6.1" +version = "4.8.0" description = "Python driver for MongoDB " optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pymongo-4.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4344c30025210b9fa80ec257b0e0aab5aa1d5cca91daa70d82ab97b482cc038e"}, - {file = "pymongo-4.6.1-cp310-cp310-manylinux1_i686.whl", hash = "sha256:1c5654bb8bb2bdb10e7a0bc3c193dd8b49a960b9eebc4381ff5a2043f4c3c441"}, - {file = "pymongo-4.6.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:eaf2f65190c506def2581219572b9c70b8250615dc918b3b7c218361a51ec42e"}, - {file = "pymongo-4.6.1-cp310-cp310-manylinux2014_i686.whl", hash = "sha256:262356ea5fcb13d35fb2ab6009d3927bafb9504ef02339338634fffd8a9f1ae4"}, - {file = "pymongo-4.6.1-cp310-cp310-manylinux2014_ppc64le.whl", hash = "sha256:2dd2f6960ee3c9360bed7fb3c678be0ca2d00f877068556785ec2eb6b73d2414"}, - {file = "pymongo-4.6.1-cp310-cp310-manylinux2014_s390x.whl", hash = "sha256:ff925f1cca42e933376d09ddc254598f8c5fcd36efc5cac0118bb36c36217c41"}, - {file = "pymongo-4.6.1-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:3cadf7f4c8e94d8a77874b54a63c80af01f4d48c4b669c8b6867f86a07ba994f"}, - {file = "pymongo-4.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55dac73316e7e8c2616ba2e6f62b750918e9e0ae0b2053699d66ca27a7790105"}, - {file = "pymongo-4.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:154b361dcb358ad377d5d40df41ee35f1cc14c8691b50511547c12404f89b5cb"}, - {file = "pymongo-4.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2940aa20e9cc328e8ddeacea8b9a6f5ddafe0b087fedad928912e787c65b4909"}, - {file = "pymongo-4.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:010bc9aa90fd06e5cc52c8fac2c2fd4ef1b5f990d9638548dde178005770a5e8"}, - {file = "pymongo-4.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e470fa4bace5f50076c32f4b3cc182b31303b4fefb9b87f990144515d572820b"}, - {file = "pymongo-4.6.1-cp310-cp310-win32.whl", hash = "sha256:da08ea09eefa6b960c2dd9a68ec47949235485c623621eb1d6c02b46765322ac"}, - {file = "pymongo-4.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:13d613c866f9f07d51180f9a7da54ef491d130f169e999c27e7633abe8619ec9"}, - {file = "pymongo-4.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6a0ae7a48a6ef82ceb98a366948874834b86c84e288dbd55600c1abfc3ac1d88"}, - {file = "pymongo-4.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bd94c503271e79917b27c6e77f7c5474da6930b3fb9e70a12e68c2dff386b9a"}, - {file = "pymongo-4.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d4ccac3053b84a09251da8f5350bb684cbbf8c8c01eda6b5418417d0a8ab198"}, - {file = "pymongo-4.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:349093675a2d3759e4fb42b596afffa2b2518c890492563d7905fac503b20daa"}, - {file = "pymongo-4.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88beb444fb438385e53dc9110852910ec2a22f0eab7dd489e827038fdc19ed8d"}, - {file = "pymongo-4.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8e62d06e90f60ea2a3d463ae51401475568b995bafaffd81767d208d84d7bb1"}, - {file = "pymongo-4.6.1-cp311-cp311-win32.whl", hash = "sha256:5556e306713e2522e460287615d26c0af0fe5ed9d4f431dad35c6624c5d277e9"}, - {file = "pymongo-4.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:b10d8cda9fc2fcdcfa4a000aa10413a2bf8b575852cd07cb8a595ed09689ca98"}, - {file = "pymongo-4.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b435b13bb8e36be11b75f7384a34eefe487fe87a6267172964628e2b14ecf0a7"}, - {file = "pymongo-4.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e438417ce1dc5b758742e12661d800482200b042d03512a8f31f6aaa9137ad40"}, - {file = "pymongo-4.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b47ebd89e69fbf33d1c2df79759d7162fc80c7652dacfec136dae1c9b3afac7"}, - {file = "pymongo-4.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bbed8cccebe1169d45cedf00461b2842652d476d2897fd1c42cf41b635d88746"}, - {file = "pymongo-4.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c30a9e06041fbd7a7590693ec5e407aa8737ad91912a1e70176aff92e5c99d20"}, - {file = "pymongo-4.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8729dbf25eb32ad0dc0b9bd5e6a0d0b7e5c2dc8ec06ad171088e1896b522a74"}, - {file = "pymongo-4.6.1-cp312-cp312-win32.whl", hash = "sha256:3177f783ae7e08aaf7b2802e0df4e4b13903520e8380915e6337cdc7a6ff01d8"}, - {file = "pymongo-4.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:00c199e1c593e2c8b033136d7a08f0c376452bac8a896c923fcd6f419e07bdd2"}, - {file = "pymongo-4.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6dcc95f4bb9ed793714b43f4f23a7b0c57e4ef47414162297d6f650213512c19"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:13552ca505366df74e3e2f0a4f27c363928f3dff0eef9f281eb81af7f29bc3c5"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:77e0df59b1a4994ad30c6d746992ae887f9756a43fc25dec2db515d94cf0222d"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3a7f02a58a0c2912734105e05dedbee4f7507e6f1bd132ebad520be0b11d46fd"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:026a24a36394dc8930cbcb1d19d5eb35205ef3c838a7e619e04bd170713972e7"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:3b287e814a01deddb59b88549c1e0c87cefacd798d4afc0c8bd6042d1c3d48aa"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:9a710c184ba845afb05a6f876edac8f27783ba70e52d5eaf939f121fc13b2f59"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:30b2c9caf3e55c2e323565d1f3b7e7881ab87db16997dc0cbca7c52885ed2347"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff62ba8ff70f01ab4fe0ae36b2cb0b5d1f42e73dfc81ddf0758cd9f77331ad25"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:547dc5d7f834b1deefda51aedb11a7af9c51c45e689e44e14aa85d44147c7657"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1de3c6faf948f3edd4e738abdb4b76572b4f4fdfc1fed4dad02427e70c5a6219"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2831e05ce0a4df10c4ac5399ef50b9a621f90894c2a4d2945dc5658765514ed"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:144a31391a39a390efce0c5ebcaf4bf112114af4384c90163f402cec5ede476b"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33bb16a07d3cc4e0aea37b242097cd5f7a156312012455c2fa8ca396953b11c4"}, - {file = "pymongo-4.6.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b7b1a83ce514700276a46af3d9e481ec381f05b64939effc9065afe18456a6b9"}, - {file = "pymongo-4.6.1-cp37-cp37m-win32.whl", hash = "sha256:3071ec998cc3d7b4944377e5f1217c2c44b811fae16f9a495c7a1ce9b42fb038"}, - {file = "pymongo-4.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2346450a075625c4d6166b40a013b605a38b6b6168ce2232b192a37fb200d588"}, - {file = "pymongo-4.6.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:061598cbc6abe2f382ab64c9caa83faa2f4c51256f732cdd890bcc6e63bfb67e"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d483793a384c550c2d12cb794ede294d303b42beff75f3b3081f57196660edaf"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:f9756f1d25454ba6a3c2f1ef8b7ddec23e5cdeae3dc3c3377243ae37a383db00"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:1ed23b0e2dac6f84f44c8494fbceefe6eb5c35db5c1099f56ab78fc0d94ab3af"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:3d18a9b9b858ee140c15c5bfcb3e66e47e2a70a03272c2e72adda2482f76a6ad"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:c258dbacfff1224f13576147df16ce3c02024a0d792fd0323ac01bed5d3c545d"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:f7acc03a4f1154ba2643edeb13658d08598fe6e490c3dd96a241b94f09801626"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:76013fef1c9cd1cd00d55efde516c154aa169f2bf059b197c263a255ba8a9ddf"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f0e6a6c807fa887a0c51cc24fe7ea51bb9e496fe88f00d7930063372c3664c3"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd1fa413f8b9ba30140de198e4f408ffbba6396864c7554e0867aa7363eb58b2"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d219b4508f71d762368caec1fc180960569766049bbc4d38174f05e8ef2fe5b"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27b81ecf18031998ad7db53b960d1347f8f29e8b7cb5ea7b4394726468e4295e"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56816e43c92c2fa8c11dc2a686f0ca248bea7902f4a067fa6cbc77853b0f041e"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef801027629c5b511cf2ba13b9be29bfee36ae834b2d95d9877818479cdc99ea"}, - {file = "pymongo-4.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d4c2be9760b112b1caf649b4977b81b69893d75aa86caf4f0f398447be871f3c"}, - {file = "pymongo-4.6.1-cp38-cp38-win32.whl", hash = "sha256:39d77d8bbb392fa443831e6d4ae534237b1f4eee6aa186f0cdb4e334ba89536e"}, - {file = "pymongo-4.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:4497d49d785482cc1a44a0ddf8830b036a468c088e72a05217f5b60a9e025012"}, - {file = "pymongo-4.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:69247f7a2835fc0984bbf0892e6022e9a36aec70e187fcfe6cae6a373eb8c4de"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7bb0e9049e81def6829d09558ad12d16d0454c26cabe6efc3658e544460688d9"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6a1810c2cbde714decf40f811d1edc0dae45506eb37298fd9d4247b8801509fe"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:e2aced6fb2f5261b47d267cb40060b73b6527e64afe54f6497844c9affed5fd0"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:d0355cff58a4ed6d5e5f6b9c3693f52de0784aa0c17119394e2a8e376ce489d4"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:3c74f4725485f0a7a3862cfd374cc1b740cebe4c133e0c1425984bcdcce0f4bb"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:9c79d597fb3a7c93d7c26924db7497eba06d58f88f58e586aa69b2ad89fee0f8"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8ec75f35f62571a43e31e7bd11749d974c1b5cd5ea4a8388725d579263c0fdf6"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5e641f931c5cd95b376fd3c59db52770e17bec2bf86ef16cc83b3906c054845"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9aafd036f6f2e5ad109aec92f8dbfcbe76cff16bad683eb6dd18013739c0b3ae"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f2b856518bfcfa316c8dae3d7b412aecacf2e8ba30b149f5eb3b63128d703b9"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ec31adc2e988fd7db3ab509954791bbc5a452a03c85e45b804b4bfc31fa221d"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9167e735379ec43d8eafa3fd675bfbb12e2c0464f98960586e9447d2cf2c7a83"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1461199b07903fc1424709efafe379205bf5f738144b1a50a08b0396357b5abf"}, - {file = "pymongo-4.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3094c7d2f820eecabadae76bfec02669567bbdd1730eabce10a5764778564f7b"}, - {file = "pymongo-4.6.1-cp39-cp39-win32.whl", hash = "sha256:c91ea3915425bd4111cb1b74511cdc56d1d16a683a48bf2a5a96b6a6c0f297f7"}, - {file = "pymongo-4.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:ef102a67ede70e1721fe27f75073b5314911dbb9bc27cde0a1c402a11531e7bd"}, - {file = "pymongo-4.6.1.tar.gz", hash = "sha256:31dab1f3e1d0cdd57e8df01b645f52d43cc1b653ed3afd535d2891f4fc4f9712"}, + {file = "pymongo-4.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f2b7bec27e047e84947fbd41c782f07c54c30c76d14f3b8bf0c89f7413fac67a"}, + {file = "pymongo-4.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c68fe128a171493018ca5c8020fc08675be130d012b7ab3efe9e22698c612a1"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:920d4f8f157a71b3cb3f39bc09ce070693d6e9648fb0e30d00e2657d1dca4e49"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52b4108ac9469febba18cea50db972605cc43978bedaa9fea413378877560ef8"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:180d5eb1dc28b62853e2f88017775c4500b07548ed28c0bd9c005c3d7bc52526"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aec2b9088cdbceb87e6ca9c639d0ff9b9d083594dda5ca5d3c4f6774f4c81b33"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0cf61450feadca81deb1a1489cb1a3ae1e4266efd51adafecec0e503a8dcd84"}, + {file = "pymongo-4.8.0-cp310-cp310-win32.whl", hash = "sha256:8b18c8324809539c79bd6544d00e0607e98ff833ca21953df001510ca25915d1"}, + {file = "pymongo-4.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e5df28f74002e37bcbdfdc5109799f670e4dfef0fb527c391ff84f078050e7b5"}, + {file = "pymongo-4.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6b50040d9767197b77ed420ada29b3bf18a638f9552d80f2da817b7c4a4c9c68"}, + {file = "pymongo-4.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:417369ce39af2b7c2a9c7152c1ed2393edfd1cbaf2a356ba31eb8bcbd5c98dd7"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf821bd3befb993a6db17229a2c60c1550e957de02a6ff4dd0af9476637b2e4d"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9365166aa801c63dff1a3cb96e650be270da06e3464ab106727223123405510f"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc8b8582f4209c2459b04b049ac03c72c618e011d3caa5391ff86d1bda0cc486"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e5019f75f6827bb5354b6fef8dfc9d6c7446894a27346e03134d290eb9e758"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b5802151fc2b51cd45492c80ed22b441d20090fb76d1fd53cd7760b340ff554"}, + {file = "pymongo-4.8.0-cp311-cp311-win32.whl", hash = "sha256:4bf58e6825b93da63e499d1a58de7de563c31e575908d4e24876234ccb910eba"}, + {file = "pymongo-4.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:b747c0e257b9d3e6495a018309b9e0c93b7f0d65271d1d62e572747f4ffafc88"}, + {file = "pymongo-4.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e6a720a3d22b54183352dc65f08cd1547204d263e0651b213a0a2e577e838526"}, + {file = "pymongo-4.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:31e4d21201bdf15064cf47ce7b74722d3e1aea2597c6785882244a3bb58c7eab"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6b804bb4f2d9dc389cc9e827d579fa327272cdb0629a99bfe5b83cb3e269ebf"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f2fbdb87fe5075c8beb17a5c16348a1ea3c8b282a5cb72d173330be2fecf22f5"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd39455b7ee70aabee46f7399b32ab38b86b236c069ae559e22be6b46b2bbfc4"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:940d456774b17814bac5ea7fc28188c7a1338d4a233efbb6ba01de957bded2e8"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:236bbd7d0aef62e64caf4b24ca200f8c8670d1a6f5ea828c39eccdae423bc2b2"}, + {file = "pymongo-4.8.0-cp312-cp312-win32.whl", hash = "sha256:47ec8c3f0a7b2212dbc9be08d3bf17bc89abd211901093e3ef3f2adea7de7a69"}, + {file = "pymongo-4.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e84bc7707492f06fbc37a9f215374d2977d21b72e10a67f1b31893ec5a140ad8"}, + {file = "pymongo-4.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:519d1bab2b5e5218c64340b57d555d89c3f6c9d717cecbf826fb9d42415e7750"}, + {file = "pymongo-4.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:87075a1feb1e602e539bdb1ef8f4324a3427eb0d64208c3182e677d2c0718b6f"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f53429515d2b3e86dcc83dadecf7ff881e538c168d575f3688698a8707b80a"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fdc20cd1e1141b04696ffcdb7c71e8a4a665db31fe72e51ec706b3bdd2d09f36"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:284d0717d1a7707744018b0b6ee7801b1b1ff044c42f7be7a01bb013de639470"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5bf0eb8b6ef40fa22479f09375468c33bebb7fe49d14d9c96c8fd50355188b0"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ecd71b9226bd1d49416dc9f999772038e56f415a713be51bf18d8676a0841c8"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0061af6e8c5e68b13f1ec9ad5251247726653c5af3c0bbdfbca6cf931e99216"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:658d0170f27984e0d89c09fe5c42296613b711a3ffd847eb373b0dbb5b648d5f"}, + {file = "pymongo-4.8.0-cp38-cp38-win32.whl", hash = "sha256:3ed1c316718a2836f7efc3d75b4b0ffdd47894090bc697de8385acd13c513a70"}, + {file = "pymongo-4.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:7148419eedfea9ecb940961cfe465efaba90595568a1fb97585fb535ea63fe2b"}, + {file = "pymongo-4.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8400587d594761e5136a3423111f499574be5fd53cf0aefa0d0f05b180710b0"}, + {file = "pymongo-4.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af3e98dd9702b73e4e6fd780f6925352237f5dce8d99405ff1543f3771201704"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de3a860f037bb51f968de320baef85090ff0bbb42ec4f28ec6a5ddf88be61871"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fc18b3a093f3db008c5fea0e980dbd3b743449eee29b5718bc2dc15ab5088bb"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18c9d8f975dd7194c37193583fd7d1eb9aea0c21ee58955ecf35362239ff31ac"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:408b2f8fdbeca3c19e4156f28fff1ab11c3efb0407b60687162d49f68075e63c"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6564780cafd6abeea49759fe661792bd5a67e4f51bca62b88faab497ab5fe89"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d18d86bc9e103f4d3d4f18b85a0471c0e13ce5b79194e4a0389a224bb70edd53"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9097c331577cecf8034422956daaba7ec74c26f7b255d718c584faddd7fa2e3c"}, + {file = "pymongo-4.8.0-cp39-cp39-win32.whl", hash = "sha256:d5428dbcd43d02f6306e1c3c95f692f68b284e6ee5390292242f509004c9e3a8"}, + {file = "pymongo-4.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:ef7225755ed27bfdb18730c68f6cb023d06c28f2b734597480fb4c0e500feb6f"}, + {file = "pymongo-4.8.0.tar.gz", hash = "sha256:454f2295875744dc70f1881e4b2eb99cdad008a33574bc8aaf120530f66c0cde"}, ] [package.dependencies] dnspython = ">=1.16.0,<3.0.0" [package.extras] -aws = ["pymongo-auth-aws (<2.0.0)"] -encryption = ["certifi", "pymongo[aws]", "pymongocrypt (>=1.6.0,<2.0.0)"] +aws = ["pymongo-auth-aws (>=1.1.0,<2.0.0)"] +docs = ["furo (==2023.9.10)", "readthedocs-sphinx-search (>=0.3,<1.0)", "sphinx (>=5.3,<8)", "sphinx-rtd-theme (>=2,<3)", "sphinxcontrib-shellcheck (>=1,<2)"] +encryption = ["certifi", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.6.0,<2.0.0)"] gssapi = ["pykerberos", "winkerberos (>=0.5.0)"] ocsp = ["certifi", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] snappy = ["python-snappy"] @@ -835,44 +759,22 @@ test = ["pytest (>=7)"] zstd = ["zstandard"] [[package]] -name = "pytest" -version = "7.4.4" -description = "pytest: simple powerful testing with Python" +name = "pyright" +version = "1.1.374" +description = "Command line wrapper for pyright" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pyright-1.1.374-py3-none-any.whl", hash = "sha256:55752bcf7a3646d293cd76710a983b71e16f6128aab2d42468e6eb7e46c0a70d"}, + {file = "pyright-1.1.374.tar.gz", hash = "sha256:d01b2daf864ba5e0362e56b844984865970d7204158e61eb685e2dab7804cb82"}, ] [package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +nodeenv = ">=1.6.0" [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "pytest-asyncio" -version = "0.23.4" -description = "Pytest support for asyncio" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest-asyncio-0.23.4.tar.gz", hash = "sha256:2143d9d9375bf372a73260e4114541485e84fca350b0b6b92674ca56ff5f7ea2"}, - {file = "pytest_asyncio-0.23.4-py3-none-any.whl", hash = "sha256:b0079dfac14b60cd1ce4691fbfb1748fe939db7d0234b5aba97197d10fbe0fef"}, -] - -[package.dependencies] -pytest = ">=7.0.0,<8" - -[package.extras] -docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] -testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] +all = ["twine (>=3.4.1)"] +dev = ["twine (>=3.4.1)"] [[package]] name = "python-dotenv" @@ -923,6 +825,84 @@ files = [ [package.extras] dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"] +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "rich" +version = "13.7.1" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + [[package]] name = "rsa" version = "4.9" @@ -938,29 +918,65 @@ files = [ pyasn1 = ">=0.1.3" [[package]] -name = "ruff" -version = "0.1.15" -description = "An extremely fast Python linter and code formatter, written in Rust." +name = "sentry-sdk" +version = "2.12.0" +description = "Python client for Sentry (https://sentry.io)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "sentry_sdk-2.12.0-py2.py3-none-any.whl", hash = "sha256:7a8d5163d2ba5c5f4464628c6b68f85e86972f7c636acc78aed45c61b98b7a5e"}, + {file = "sentry_sdk-2.12.0.tar.gz", hash = "sha256:8763840497b817d44c49b3fe3f5f7388d083f2337ffedf008b2cdb63b5c86dc6"}, +] + +[package.dependencies] +certifi = "*" +loguru = {version = ">=0.5", optional = true, markers = "extra == \"loguru\""} +urllib3 = ">=1.26.11" + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +anthropic = ["anthropic (>=0.16)"] +arq = ["arq (>=0.23)"] +asyncpg = ["asyncpg (>=0.23)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +celery-redbeat = ["celery-redbeat (>=2)"] +chalice = ["chalice (>=1.16.0)"] +clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] +grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"] +httpx = ["httpx (>=0.16.0)"] +huey = ["huey (>=2)"] +huggingface-hub = ["huggingface-hub (>=0.22)"] +langchain = ["langchain (>=0.0.210)"] +loguru = ["loguru (>=0.5)"] +openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro"] +pure-eval = ["asttokens", "executing", "pure-eval"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +tornado = ["tornado (>=6)"] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5fe8d54df166ecc24106db7dd6a68d44852d14eb0729ea4672bb4d96c320b7df"}, - {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f0bfbb53c4b4de117ac4d6ddfd33aa5fc31beeaa21d23c45c6dd249faf9126f"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d432aec35bfc0d800d4f70eba26e23a352386be3a6cf157083d18f6f5881c8"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9405fa9ac0e97f35aaddf185a1be194a589424b8713e3b97b762336ec79ff807"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66ec24fe36841636e814b8f90f572a8c0cb0e54d8b5c2d0e300d28a0d7bffec"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6f8ad828f01e8dd32cc58bc28375150171d198491fc901f6f98d2a39ba8e3ff5"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86811954eec63e9ea162af0ffa9f8d09088bab51b7438e8b6488b9401863c25e"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd4025ac5e87d9b80e1f300207eb2fd099ff8200fa2320d7dc066a3f4622dc6b"}, - {file = "ruff-0.1.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17b93c02cdb6aeb696effecea1095ac93f3884a49a554a9afa76bb125c114c1"}, - {file = "ruff-0.1.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ddb87643be40f034e97e97f5bc2ef7ce39de20e34608f3f829db727a93fb82c5"}, - {file = "ruff-0.1.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:abf4822129ed3a5ce54383d5f0e964e7fef74a41e48eb1dfad404151efc130a2"}, - {file = "ruff-0.1.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6c629cf64bacfd136c07c78ac10a54578ec9d1bd2a9d395efbee0935868bf852"}, - {file = "ruff-0.1.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1bab866aafb53da39c2cadfb8e1c4550ac5340bb40300083eb8967ba25481447"}, - {file = "ruff-0.1.15-py3-none-win32.whl", hash = "sha256:2417e1cb6e2068389b07e6fa74c306b2810fe3ee3476d5b8a96616633f40d14f"}, - {file = "ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587"}, - {file = "ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360"}, - {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"}, + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, ] [[package]] @@ -976,150 +992,335 @@ files = [ [[package]] name = "sniffio" -version = "1.3.0" +version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, -] - -[[package]] -name = "sortedcontainers" -version = "2.4.0" -description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" -optional = false -python-versions = "*" -files = [ - {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, - {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] [[package]] name = "starlette" -version = "0.27.0" +version = "0.37.2" description = "The little ASGI library that shines." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "starlette-0.27.0-py3-none-any.whl", hash = "sha256:918416370e846586541235ccd38a474c08b80443ed31c578a418e2209b3eef91"}, - {file = "starlette-0.27.0.tar.gz", hash = "sha256:6a6b0d042acb8d469a01eba54e9cda6cbd24ac602c4cd016723117d6a7e73b75"}, + {file = "starlette-0.37.2-py3-none-any.whl", hash = "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee"}, + {file = "starlette-0.37.2.tar.gz", hash = "sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823"}, ] [package.dependencies] anyio = ">=3.4.0,<5" [package.extras] -full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] [[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" +name = "tomlkit" +version = "0.13.0" +description = "Style preserving TOML library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomlkit-0.13.0-py3-none-any.whl", hash = "sha256:7075d3042d03b80f603482d69bf0c8f345c2b30e41699fd8883227f89972b264"}, + {file = "tomlkit-0.13.0.tar.gz", hash = "sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72"}, ] [[package]] -name = "tomlkit" +name = "typer" version = "0.12.3" -description = "Style preserving TOML library" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, - {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, + {file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"}, + {file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"}, ] +[package.dependencies] +click = ">=8.0.0" +rich = ">=10.11.0" +shellingham = ">=1.3.0" +typing-extensions = ">=3.7.4.3" + [[package]] -name = "trio" -version = "0.24.0" -description = "A friendly Python library for async concurrency and I/O" +name = "types-passlib" +version = "1.7.7.20240327" +description = "Typing stubs for passlib" optional = false python-versions = ">=3.8" files = [ - {file = "trio-0.24.0-py3-none-any.whl", hash = "sha256:c3bd3a4e3e3025cd9a2241eae75637c43fe0b9e88b4c97b9161a55b9e54cd72c"}, - {file = "trio-0.24.0.tar.gz", hash = "sha256:ffa09a74a6bf81b84f8613909fb0beaee84757450183a7a2e0b47b455c0cac5d"}, + {file = "types-passlib-1.7.7.20240327.tar.gz", hash = "sha256:4cce6a1a3a6afee9fc4728b4d9784300764ac2be747f5bcc01646d904b85f4bb"}, + {file = "types_passlib-1.7.7.20240327-py3-none-any.whl", hash = "sha256:3a3b7f4258b71034d2e2f4f307d6810f9904f906cdf375514c8bdbdb28a4ad23"}, ] -[package.dependencies] -attrs = ">=20.1.0" -cffi = {version = ">=1.14", markers = "os_name == \"nt\" and implementation_name != \"pypy\""} -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} -idna = "*" -outcome = "*" -sniffio = ">=1.3.0" -sortedcontainers = "*" - [[package]] -name = "types-passlib" -version = "1.7.7.20240106" -description = "Typing stubs for passlib" +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "types-passlib-1.7.7.20240106.tar.gz", hash = "sha256:2231ae83d1dd9e485b7ec6041d81b4f9c66403d1767360e860605a90db48ea27"}, - {file = "types_passlib-1.7.7.20240106-py3-none-any.whl", hash = "sha256:347aa64d4c2bc239f3765fe38fc79dad3d67f9def7b3ea721daaaaa835a91dad"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] -name = "types-pyasn1" -version = "0.5.0.20240106" -description = "Typing stubs for pyasn1" +name = "urllib3" +version = "2.2.2" +description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "types-pyasn1-0.5.0.20240106.tar.gz", hash = "sha256:80e38befb1ddbf90c58b6f9e5ce158df66c42c87764a6564b1b7b6dd340535f7"}, - {file = "types_pyasn1-0.5.0.20240106-py3-none-any.whl", hash = "sha256:e6ad48f5a58afb32019cba86a0529cdd52c315495a19122b4823ba4ad5f3c45b"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + [[package]] -name = "types-python-jose" -version = "3.3.4.20240106" -description = "Typing stubs for python-jose" +name = "uvicorn" +version = "0.30.4" +description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.8" files = [ - {file = "types-python-jose-3.3.4.20240106.tar.gz", hash = "sha256:b18cf8c5080bbfe1ef7c3b707986435d9efca3e90889acb6a06f65e06bc3405a"}, - {file = "types_python_jose-3.3.4.20240106-py3-none-any.whl", hash = "sha256:b515a6c0c61f5e2a53bc93e3a2b024cbd42563e2e19cbde9fd1c2cc2cfe77ccc"}, + {file = "uvicorn-0.30.4-py3-none-any.whl", hash = "sha256:06b00e3087e58c6865c284143c0c42f810b32ff4f265ab19d08c566f74a08728"}, + {file = "uvicorn-0.30.4.tar.gz", hash = "sha256:00db9a9e3711a5fa59866e2b02fac69d8dc70ce0814aaec9a66d1d9e5c832a30"}, ] [package.dependencies] -types-pyasn1 = "*" +click = ">=7.0" +colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} +h11 = ">=0.8" +httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} +python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} + +[package.extras] +standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] [[package]] -name = "typing-extensions" -version = "4.9.0" -description = "Backported and Experimental Type Hints for Python 3.8+" +name = "uvloop" +version = "0.19.0" +description = "Fast implementation of asyncio event loop on top of libuv" optional = false -python-versions = ">=3.8" +python-versions = ">=3.8.0" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"}, + {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"}, + {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8"}, + {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849"}, + {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957"}, + {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd"}, + {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef"}, + {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2"}, + {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1"}, + {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24"}, + {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533"}, + {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12"}, + {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650"}, + {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec"}, + {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc"}, + {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6"}, + {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593"}, + {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3"}, + {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd"}, + {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd"}, + {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be"}, + {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797"}, + {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d"}, + {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7"}, + {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b"}, + {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67"}, + {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7"}, + {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256"}, + {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17"}, + {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5"}, + {file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"}, ] +[package.extras] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] + [[package]] -name = "uvicorn" -version = "0.24.0.post1" -description = "The lightning-fast ASGI server." +name = "watchfiles" +version = "0.22.0" +description = "Simple, modern and high performance file watching and code reload in python." optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.24.0.post1-py3-none-any.whl", hash = "sha256:7c84fea70c619d4a710153482c0d230929af7bcf76c7bfa6de151f0a3a80121e"}, - {file = "uvicorn-0.24.0.post1.tar.gz", hash = "sha256:09c8e5a79dc466bdf28dead50093957db184de356fcdc48697bad3bde4c2588e"}, + {file = "watchfiles-0.22.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:da1e0a8caebf17976e2ffd00fa15f258e14749db5e014660f53114b676e68538"}, + {file = "watchfiles-0.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61af9efa0733dc4ca462347becb82e8ef4945aba5135b1638bfc20fad64d4f0e"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d9188979a58a096b6f8090e816ccc3f255f137a009dd4bbec628e27696d67c1"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2bdadf6b90c099ca079d468f976fd50062905d61fae183f769637cb0f68ba59a"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:067dea90c43bf837d41e72e546196e674f68c23702d3ef80e4e816937b0a3ffd"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbf8a20266136507abf88b0df2328e6a9a7c7309e8daff124dda3803306a9fdb"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1235c11510ea557fe21be5d0e354bae2c655a8ee6519c94617fe63e05bca4171"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2444dc7cb9d8cc5ab88ebe792a8d75709d96eeef47f4c8fccb6df7c7bc5be71"}, + {file = "watchfiles-0.22.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c5af2347d17ab0bd59366db8752d9e037982e259cacb2ba06f2c41c08af02c39"}, + {file = "watchfiles-0.22.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9624a68b96c878c10437199d9a8b7d7e542feddda8d5ecff58fdc8e67b460848"}, + {file = "watchfiles-0.22.0-cp310-none-win32.whl", hash = "sha256:4b9f2a128a32a2c273d63eb1fdbf49ad64852fc38d15b34eaa3f7ca2f0d2b797"}, + {file = "watchfiles-0.22.0-cp310-none-win_amd64.whl", hash = "sha256:2627a91e8110b8de2406d8b2474427c86f5a62bf7d9ab3654f541f319ef22bcb"}, + {file = "watchfiles-0.22.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8c39987a1397a877217be1ac0fb1d8b9f662c6077b90ff3de2c05f235e6a8f96"}, + {file = "watchfiles-0.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a927b3034d0672f62fb2ef7ea3c9fc76d063c4b15ea852d1db2dc75fe2c09696"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052d668a167e9fc345c24203b104c313c86654dd6c0feb4b8a6dfc2462239249"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e45fb0d70dda1623a7045bd00c9e036e6f1f6a85e4ef2c8ae602b1dfadf7550"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c49b76a78c156979759d759339fb62eb0549515acfe4fd18bb151cc07366629c"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a65474fd2b4c63e2c18ac67a0c6c66b82f4e73e2e4d940f837ed3d2fd9d4da"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc0cba54f47c660d9fa3218158b8963c517ed23bd9f45fe463f08262a4adae1"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94ebe84a035993bb7668f58a0ebf998174fb723a39e4ef9fce95baabb42b787f"}, + {file = "watchfiles-0.22.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e0f0a874231e2839abbf473256efffe577d6ee2e3bfa5b540479e892e47c172d"}, + {file = "watchfiles-0.22.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:213792c2cd3150b903e6e7884d40660e0bcec4465e00563a5fc03f30ea9c166c"}, + {file = "watchfiles-0.22.0-cp311-none-win32.whl", hash = "sha256:b44b70850f0073b5fcc0b31ede8b4e736860d70e2dbf55701e05d3227a154a67"}, + {file = "watchfiles-0.22.0-cp311-none-win_amd64.whl", hash = "sha256:00f39592cdd124b4ec5ed0b1edfae091567c72c7da1487ae645426d1b0ffcad1"}, + {file = "watchfiles-0.22.0-cp311-none-win_arm64.whl", hash = "sha256:3218a6f908f6a276941422b035b511b6d0d8328edd89a53ae8c65be139073f84"}, + {file = "watchfiles-0.22.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c7b978c384e29d6c7372209cbf421d82286a807bbcdeb315427687f8371c340a"}, + {file = "watchfiles-0.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd4c06100bce70a20c4b81e599e5886cf504c9532951df65ad1133e508bf20be"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:425440e55cd735386ec7925f64d5dde392e69979d4c8459f6bb4e920210407f2"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68fe0c4d22332d7ce53ad094622b27e67440dacefbaedd29e0794d26e247280c"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8a31bfd98f846c3c284ba694c6365620b637debdd36e46e1859c897123aa232"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc2e8fe41f3cac0660197d95216c42910c2b7e9c70d48e6d84e22f577d106fc1"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b7cc10261c2786c41d9207193a85c1db1b725cf87936df40972aab466179b6"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28585744c931576e535860eaf3f2c0ec7deb68e3b9c5a85ca566d69d36d8dd27"}, + {file = "watchfiles-0.22.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00095dd368f73f8f1c3a7982a9801190cc88a2f3582dd395b289294f8975172b"}, + {file = "watchfiles-0.22.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:52fc9b0dbf54d43301a19b236b4a4614e610605f95e8c3f0f65c3a456ffd7d35"}, + {file = "watchfiles-0.22.0-cp312-none-win32.whl", hash = "sha256:581f0a051ba7bafd03e17127735d92f4d286af941dacf94bcf823b101366249e"}, + {file = "watchfiles-0.22.0-cp312-none-win_amd64.whl", hash = "sha256:aec83c3ba24c723eac14225194b862af176d52292d271c98820199110e31141e"}, + {file = "watchfiles-0.22.0-cp312-none-win_arm64.whl", hash = "sha256:c668228833c5619f6618699a2c12be057711b0ea6396aeaece4ded94184304ea"}, + {file = "watchfiles-0.22.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d47e9ef1a94cc7a536039e46738e17cce058ac1593b2eccdede8bf72e45f372a"}, + {file = "watchfiles-0.22.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:28f393c1194b6eaadcdd8f941307fc9bbd7eb567995232c830f6aef38e8a6e88"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd64f3a4db121bc161644c9e10a9acdb836853155a108c2446db2f5ae1778c3d"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2abeb79209630da981f8ebca30a2c84b4c3516a214451bfc5f106723c5f45843"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cc382083afba7918e32d5ef12321421ef43d685b9a67cc452a6e6e18920890e"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d048ad5d25b363ba1d19f92dcf29023988524bee6f9d952130b316c5802069cb"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:103622865599f8082f03af4214eaff90e2426edff5e8522c8f9e93dc17caee13"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3e1f3cf81f1f823e7874ae563457828e940d75573c8fbf0ee66818c8b6a9099"}, + {file = "watchfiles-0.22.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8597b6f9dc410bdafc8bb362dac1cbc9b4684a8310e16b1ff5eee8725d13dcd6"}, + {file = "watchfiles-0.22.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0b04a2cbc30e110303baa6d3ddce8ca3664bc3403be0f0ad513d1843a41c97d1"}, + {file = "watchfiles-0.22.0-cp38-none-win32.whl", hash = "sha256:b610fb5e27825b570554d01cec427b6620ce9bd21ff8ab775fc3a32f28bba63e"}, + {file = "watchfiles-0.22.0-cp38-none-win_amd64.whl", hash = "sha256:fe82d13461418ca5e5a808a9e40f79c1879351fcaeddbede094028e74d836e86"}, + {file = "watchfiles-0.22.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3973145235a38f73c61474d56ad6199124e7488822f3a4fc97c72009751ae3b0"}, + {file = "watchfiles-0.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:280a4afbc607cdfc9571b9904b03a478fc9f08bbeec382d648181c695648202f"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a0d883351a34c01bd53cfa75cd0292e3f7e268bacf2f9e33af4ecede7e21d1d"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9165bcab15f2b6d90eedc5c20a7f8a03156b3773e5fb06a790b54ccecdb73385"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc1b9b56f051209be458b87edb6856a449ad3f803315d87b2da4c93b43a6fe72"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc1fc25a1dedf2dd952909c8e5cb210791e5f2d9bc5e0e8ebc28dd42fed7562"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc92d2d2706d2b862ce0568b24987eba51e17e14b79a1abcd2edc39e48e743c8"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97b94e14b88409c58cdf4a8eaf0e67dfd3ece7e9ce7140ea6ff48b0407a593ec"}, + {file = "watchfiles-0.22.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96eec15e5ea7c0b6eb5bfffe990fc7c6bd833acf7e26704eb18387fb2f5fd087"}, + {file = "watchfiles-0.22.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:28324d6b28bcb8d7c1041648d7b63be07a16db5510bea923fc80b91a2a6cbed6"}, + {file = "watchfiles-0.22.0-cp39-none-win32.whl", hash = "sha256:8c3e3675e6e39dc59b8fe5c914a19d30029e36e9f99468dddffd432d8a7b1c93"}, + {file = "watchfiles-0.22.0-cp39-none-win_amd64.whl", hash = "sha256:25c817ff2a86bc3de3ed2df1703e3d24ce03479b27bb4527c57e722f8554d971"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b810a2c7878cbdecca12feae2c2ae8af59bea016a78bc353c184fa1e09f76b68"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f7e1f9c5d1160d03b93fc4b68a0aeb82fe25563e12fbcdc8507f8434ab6f823c"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:030bc4e68d14bcad2294ff68c1ed87215fbd9a10d9dea74e7cfe8a17869785ab"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace7d060432acde5532e26863e897ee684780337afb775107c0a90ae8dbccfd2"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5834e1f8b71476a26df97d121c0c0ed3549d869124ed2433e02491553cb468c2"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:0bc3b2f93a140df6806c8467c7f51ed5e55a931b031b5c2d7ff6132292e803d6"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fdebb655bb1ba0122402352b0a4254812717a017d2dc49372a1d47e24073795"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c8e0aa0e8cc2a43561e0184c0513e291ca891db13a269d8d47cb9841ced7c71"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2f350cbaa4bb812314af5dab0eb8d538481e2e2279472890864547f3fe2281ed"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7a74436c415843af2a769b36bf043b6ccbc0f8d784814ba3d42fc961cdb0a9dc"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00ad0bcd399503a84cc688590cdffbe7a991691314dde5b57b3ed50a41319a31"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72a44e9481afc7a5ee3291b09c419abab93b7e9c306c9ef9108cb76728ca58d2"}, + {file = "watchfiles-0.22.0.tar.gz", hash = "sha256:988e981aaab4f3955209e7e28c7794acdb690be1efa7f16f8ea5aba7ffdadacb"}, ] [package.dependencies] -click = ">=7.0" -h11 = ">=0.8" -typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} +anyio = ">=3.0.0" -[package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] +[[package]] +name = "websockets" +version = "12.0" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"}, + {file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"}, + {file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"}, + {file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"}, + {file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"}, + {file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"}, + {file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"}, + {file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"}, + {file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"}, + {file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"}, + {file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"}, + {file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"}, + {file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"}, + {file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"}, + {file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"}, + {file = "websockets-12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438"}, + {file = "websockets-12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2"}, + {file = "websockets-12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7"}, + {file = "websockets-12.0-cp38-cp38-win32.whl", hash = "sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62"}, + {file = "websockets-12.0-cp38-cp38-win_amd64.whl", hash = "sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892"}, + {file = "websockets-12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d"}, + {file = "websockets-12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28"}, + {file = "websockets-12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9"}, + {file = "websockets-12.0-cp39-cp39-win32.whl", hash = "sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6"}, + {file = "websockets-12.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8"}, + {file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"}, + {file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"}, + {file = "websockets-12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2"}, + {file = "websockets-12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468"}, + {file = "websockets-12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611"}, + {file = "websockets-12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370"}, + {file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"}, + {file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"}, +] [[package]] name = "win32-setctime" @@ -1137,5 +1338,5 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "2.0" -python-versions = "^3.10" -content-hash = "4b7866f7f4a26b9e4ea432403c3123ad998b2b831304bd139153c78bb960ef64" +python-versions = "^3.11" +content-hash = "149181c2f94608ce3cb67e7a1449384cdbec6999a34ebaf02790ee210a9468cb" diff --git a/pyproject.toml b/pyproject.toml index 01da3b3..fbe2846 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,31 +6,38 @@ authors = ["Mark Fomin ", "Andrew Cherkashin bool: - """Check what role contains permissions - Args: - role_staff: representation permissions through converted to bits int32 number - - Returns: - True - if role has permission, else False - """ - - for perm in permissions: - if (role_staff >> perm.value) % 2 == 0: - return False - - return True - - -def gen_code_staff_by_permissions(*permissions: Permissions) -> int: - """ - Generate role code by permissions - Args: - *permissions: permissions, which should be contained in role code - Returns: - role code - """ - role_code = 0 - for perm in permissions: - role_code += 1 << perm.value - - return role_code - - -def get_hashed_password(password: str) -> str: - """ - Hashing password - Args: - password: password to hash - - Returns: - hashed password - """ - return password_context.hash(password) - - -def verify_password(password: str, hashed_password: str) -> bool: - """ - Checks what hashed password is password - Args: - password: password - hashed_password: password hash - - Returns: - True if hash(password) equal to hashed_password, else False - """ - return password_context.verify(password, hashed_password) - - -def create_token( - subject: str, is_access=True, expires_delta: int | None = None -) -> str: - """ - Generating JWT by data and expires time - Args: - subject: some useful data to code, like username - is_access: if False generate refresh token with longer expiration time - expires_delta: how long token available - Returns: - JWT in string - """ - - result_expires_delta: datetime - - if expires_delta is not None: - result_expires_delta = datetime.utcnow() + timedelta(minutes=expires_delta) - elif is_access: - result_expires_delta = datetime.utcnow() + timedelta( - minutes=Config.Auth.ACCESS_TOKEN_EXPIRE_MINUTES - ) - else: - result_expires_delta = datetime.utcnow() + timedelta( - minutes=Config.Auth.REFRESH_TOKEN_EXPIRE_MINUTES - ) - - to_encode = {"exp": result_expires_delta, "sub": str(subject)} - encoded_jwt = jwt.encode(to_encode, Config.Auth.JWT_SECRET_KEY, Config.Auth.ALGORITHM) - - return encoded_jwt - - -async def get_current_user(token: str) -> User: - """Get current user by access token or raise HTTPException - Args: - token (str): access token - - Raises: - AuthException: Raise 401 error if access token is invalid - Returns: - User: user object - """ - try: - payload = jwt.decode(token, Config.Auth.JWT_SECRET_KEY, algorithms=[Config.Auth.ALGORITHM]) - token_sub = payload["sub"] - - except ExpiredSignatureError as exc: - raise AuthException( - status="TOKEN_EXPIRED", - status_code=http_status.HTTP_401_UNAUTHORIZED - ) from exc - except Exception as exc: - raise AuthException( - status="VALIDATE_ERROR", - status_code=http_status.HTTP_401_UNAUTHORIZED, - ) from exc - - user = await db.user.get(int(token_sub)) - - if user is None: - raise AuthException( - status="COULD_NOT_FIND_USER", - status_code=http_status.HTTP_401_UNAUTHORIZED, - ) - - return user - - -def auth_user(*permissions: Permissions): - """ - Decorator - Use: - >>> def endpoint(user: User = Depends(auth_user(Permissions.CREATE_ROLE))) - Auth user by permissions. - Args: - *permissions: Permissions, which must contain user roles - Returns: - function, which auth user - Raises: - AuthException: Raise 403 error user hasn`t permissions - """ - - async def wrapper(user: User = Depends(get_current_user)) -> User: - result_mask = 0 - - for role_name in user.roles: - cur_role = await db.role.get(role_name) - if cur_role is not None: - result_mask |= cur_role.role_code - - if not has_role_permissions(result_mask, *permissions): - - required_permissions = [] - - for permission in permissions: - if not has_role_permissions(result_mask, permission): - required_permissions.append(permission) - - raise AuthException( - status="ACCESS_DENIED", - status_code=http_status.HTTP_403_FORBIDDEN, - response={ - "required_permissions": [ - *map(lambda x: str(x).split(".")[1], required_permissions) - ] - } - ) - return user - - return wrapper diff --git a/src/config/__init__.py b/src/config/__init__.py index 68b6d5d..9668026 100644 --- a/src/config/__init__.py +++ b/src/config/__init__.py @@ -1,49 +1,7 @@ -"""Project configuration""" -import os -import sys -from loguru import logger +from .load_config import load_config -from . import config_model +config = load_config() - -_CONFIG_PATH_ENV_VARIABLE_NAME = "ELANTS_CONFIG_FILE_PATH" - -_config_path = os.getenv(_CONFIG_PATH_ENV_VARIABLE_NAME) - -if _config_path is None: # check for existing env variable - logger.error( - f"Environment variable {_CONFIG_PATH_ENV_VARIABLE_NAME} is not set" - ) - sys.exit(1) - -def _check_json_file(file_path: str) -> bool: - """Check that file_path is a json file and exists - - Args: - file_path: file to check - - Returns: - True if file_path is a json file and exists, False otherwise - """ - if os.path.exists(file_path) and os.path.isfile(file_path): - _, file_extension = os.path.splitext(file_path) - if file_extension.lower() == '.json': - return True - return False - -if not _check_json_file(_config_path): # check_json_file - logger.error( - f"File {_config_path} is not a json file or isnt exists" - ) - sys.exit(1) - -def _load_config() -> config_model.Config: - """parse && validate config file""" - with open(_config_path, "r", encoding="utf-8") as config_file: - return config_model.Config.model_validate_json(config_file.read()) - -logger.info(f"Loading configuration from file {_config_path}") -config = _load_config() - -logger.info(f"Successfully loaded configuration from file {_config_path}") -logger.info(f"Current configuration: {config.model_dump_json(indent=4)}") +__all__ = [ + "config" +] diff --git a/src/config/config_model.py b/src/config/config_model.py index 45af3c9..e2f23b6 100644 --- a/src/config/config_model.py +++ b/src/config/config_model.py @@ -1,37 +1,37 @@ -"""Define configuration class""" +"""Entire project configuration model""" from pydantic import BaseModel, SecretStr - +from db.types.common import Email class MongoDBCollections(BaseModel): - """List of all collections in database""" - users: str - domains: str - groups: str - group_roles: str - roles: str + users: str = "Users" + domains: str = "Domains" + groups: str = "Groups" + group_roles: str = "GroupRoles" + roles: str = "Roles" + internal_counters: str = "InternalCounters" + group_members: str = "GroupMembers" + contests: str = "Contests" class DatabaseConfig(BaseModel): - """Database configuration""" connect_url: SecretStr name: str - collections: MongoDBCollections + collections: MongoDBCollections = MongoDBCollections() class AuthConfig(BaseModel): - """Auth configuration""" - algorithm: str - access_token_expire_minutes: int - refresh_token_expire_minutes: int + access_token_expire_minutes: int = 10 + refresh_token_expire_minutes: int = 10080 jwt_access_secret_key: SecretStr jwt_refresh_secret_key: SecretStr -class RabbitMQConfig(BaseModel): - """Config for RabbitMQ""" - connect_url: SecretStr - # TODO: insert other necessary fields later +class SuperUser(BaseModel): + email: Email = "root@gmail.com" + password: SecretStr = SecretStr("root") class Config(BaseModel): - """Entire project configuration""" database: DatabaseConfig - rabbitmq: RabbitMQConfig + super_user: SuperUser = SuperUser() auth: AuthConfig - app_title: str + debug: bool = False + app_title: str = "ELAN MAIN API" + show_config: bool = False + allow_origins: list[str] = ["*"] diff --git a/src/config/load_config.py b/src/config/load_config.py new file mode 100644 index 0000000..f312140 --- /dev/null +++ b/src/config/load_config.py @@ -0,0 +1,36 @@ +import os +import sys +from loguru import logger +from pydantic import ValidationError + +from .config_model import Config + +CONFIG_PATH_ENV_VARIABLE_NAME = "CONFIG_PATH" + +def load_config() -> Config: + config_path = os.getenv(CONFIG_PATH_ENV_VARIABLE_NAME) + + if config_path is None: + logger.error("Environment variable {_CONFIG_PATH_ENV_VARIABLE_NAME} is not set") + sys.exit(1) + + file_exists = False + if os.path.exists(config_path) and os.path.isfile(config_path): + _, file_extension = os.path.splitext(config_path) + if file_extension.lower() == '.json': + file_exists = True + + if not file_exists: + logger.error( + f"File {config_path} is not a json file or isnt exists" + ) + sys.exit(1) + + try: + with open(config_path, "r", encoding="utf-8") as config_file: + return Config.model_validate_json(config_file.read()) + except ValidationError as exception: + logger.error( + f"Failed to load configuration from file {config_path}: {exception}" + ) + sys.exit(1) diff --git a/src/db/__init__.py b/src/db/__init__.py index 6d67ea7..9f285da 100644 --- a/src/db/__init__.py +++ b/src/db/__init__.py @@ -1,16 +1,16 @@ -"""Database interfaces for some parts of database""" -from db.managers.contest_database_manager import ContestDatabaseManager -from db.managers.problem_database_manager import ProblemDatabaseManager -from db.managers.submission_database_manager import SubmissionDatabaseManager -from db.managers.user_database_manager import UserDatabaseManager -from db.managers.group_database_manager import GroupDatabaseManager -from db.managers.domain_router_database_manager import DomainRouterDatabaseManager -from db.managers.role_database_manager import RoleDatabaseManager +""" +Module that allows work with database through implemented methods and models +also it provode project types +""" -user: UserDatabaseManager = UserDatabaseManager() -group: GroupDatabaseManager = GroupDatabaseManager() -domain: DomainRouterDatabaseManager = DomainRouterDatabaseManager() -role: RoleDatabaseManager = RoleDatabaseManager() -contest: ContestDatabaseManager = ContestDatabaseManager() -problem: ProblemDatabaseManager = ProblemDatabaseManager() -submission: SubmissionDatabaseManager = SubmissionDatabaseManager() +from . import types +from . import methods + +from .client import client, close_connection + +__all__ = [ + "types", + "methods", + "client", + "close_connection" +] diff --git a/src/db/client.py b/src/db/client.py new file mode 100644 index 0000000..67a128d --- /dev/null +++ b/src/db/client.py @@ -0,0 +1,32 @@ +"""A module that creates a database connection and exports it""" + +import sys +from pymongo import MongoClient, database +from pymongo.errors import ServerSelectionTimeoutError +from loguru import logger + +from config import config + +# connection to database +logger.info("Connecting to database") + +client: MongoClient = MongoClient(config.database.connect_url.get_secret_value()) + +db: database.Database = client.get_database(config.database.name) + +try: + client.server_info() +except ServerSelectionTimeoutError: + logger.error("Database is not connected (Timeout error)") + sys.exit(1) + +def close_connection(): + """Closing mongodb connection""" + client.close() + + +__all__= [ + "db", + "client", + "close_connection" +] diff --git a/src/db/helpers/abstract_database_manager.py b/src/db/helpers/abstract_database_manager.py deleted file mode 100644 index 7660a9c..0000000 --- a/src/db/helpers/abstract_database_manager.py +++ /dev/null @@ -1,29 +0,0 @@ -"""AbstractDatabaseManager definition""" -from motor.core import AgnosticCollection, AgnosticClient -from utils.singleton import Singleton -from db.mongo_manager import MongoManager - - -class AbstractDatabaseManager(Singleton): - """Abstract DatabaseManager for inheritance""" - - collection_name: str | None = None - - @property - def client(self) -> AgnosticClient: - """ - Get MongoClient - Returns: MongoClient instance - """ - return MongoManager.get_client() - - @property - def collection(self) -> AgnosticCollection: - """ - Get MongoCollection for current collection name - Returns: MongoCollection instance - """ - if self.collection_name is None: - raise NotImplementedError("collection name is not defined") - - return MongoManager.get_db().get_collection(self.collection_name) diff --git a/src/db/helpers/auto_increment_database_interface.py b/src/db/helpers/auto_increment_database_interface.py deleted file mode 100644 index 0693ef9..0000000 --- a/src/db/helpers/auto_increment_database_interface.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Counters internal database manager for auto increment ids""" -from config import Config -from pymongo.errors import DuplicateKeyError -from pydantic import BaseModel -from abc import abstractmethod -from db.mongo_manager import MongoManager - - -class AutoIncrementDatabaseInterface: - """Internal database methods for auto increment ids""" - - __internal_collection_name: str = Config.Collections.internal_counters - - async def _insert_one_with_id(self, - target_collection: str, - document: BaseModel) -> int: - """ - Insert document to the collection with generated id - Args: - target_collection: target collection name - document: the document to insert - Returns: - id for new created element - """ - - internal_database_collection = MongoManager.get_db().get_collection( - self.__internal_collection_name - ) - - if internal_database_collection is None: - raise ConnectionError("Database is not connected") - - while True: - try: - res = await internal_database_collection.find_one_and_update( - {"_id": target_collection}, - {"$inc": {"counter": 1}}, upsert=True, return_document=True - ) - - to_insert = document.model_dump(by_alias=True) - to_insert["_id"] = res["counter"] - - await MongoManager.get_db().get_collection(target_collection).insert_one( - to_insert - ) - return res["counter"] - except DuplicateKeyError: - continue - - @abstractmethod - async def insert_with_id(self, document) -> int: - ... diff --git a/src/db/managers/contest_database_manager.py b/src/db/managers/contest_database_manager.py deleted file mode 100644 index 3e7e53f..0000000 --- a/src/db/managers/contest_database_manager.py +++ /dev/null @@ -1,57 +0,0 @@ -"""Contest database manager definition""" -from db.helpers.abstract_database_manager import AbstractDatabaseManager -from db.models.contest import Contest -from config import Config -from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface -from db.models.annotations import IntIdAnnotation - - -class ContestDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): - """Database methods with contest""" - - collection_name = Config.Collections.contests - - async def get(self, _id: int) -> Contest | None: - """ - Getting contest by id - Args: - _id: mongo object id - Returns: - Group object or None if not found - """ - contest = await self.collection.find_one({"_id": _id}) - if contest is None: - return None - return Contest(**contest) - - async def insert_with_id(self, contest: Contest) -> int: - """ - Insert used with auto increment - Args: - contest: used document to insert - """ - return await self._insert_one_with_id(self.collection_name, contest) - - async def get_all(self) -> list[Contest]: - """ - Returns: returning all contest objects - """ - to_return = [] - cursor = self.collection.find({}) - async for group in cursor: - to_return.append(Contest(**group)) - - return to_return - - async def add_problem(self, contest_id: IntIdAnnotation, problem_id: IntIdAnnotation) -> None: - """ - Adding problem to contest, with target contest id - Args: - contest_id: contest id - problem_id: problem id - """ - - await self.collection.find_one_and_update( - {"_id": contest_id}, - {"$push": {"problems": problem_id}} - ) diff --git a/src/db/managers/domain_router_database_manager.py b/src/db/managers/domain_router_database_manager.py deleted file mode 100644 index 1cb9c74..0000000 --- a/src/db/managers/domain_router_database_manager.py +++ /dev/null @@ -1,84 +0,0 @@ -"""DomainRouterDatabaseManager definition""" -from pymongo.errors import DuplicateKeyError -from loguru import logger -from config import Config -from db.models.entity import Entity -from db.helpers.abstract_database_manager import AbstractDatabaseManager - - -class DomainRouterDatabaseManager(AbstractDatabaseManager): - """Database methods to routing domains""" - - collection_name = Config.Collections.domain_router - - async def resolve(self, domain: str) -> Entity | None: - """ - Resolving domain to entity type and id - Args: - domain: the name to resolve - Returns: - id or None if not found - """ - res = await self.collection.find_one({"_id": domain}) - if res is None: - return None - return Entity(**res) - - async def resolve_id(self, domain: str, entity_type: str) -> int | None: - """ - Resolving entity by domain with type and id - Args: - domain: domain to resolve - entity_type: entity type to resolve - Returns: - entity_id if entity has type == entity_type, else return None - """ - - res = await self.resolve(domain) - if res is None: - return None - if res.entity_type != entity_type: - return None - return res.entity_id - - async def reserve(self, domain: str) -> bool: - """ - Reserving domain for some entity with unknown type and id - Returns: - True if reserve was successful, else False - """ - to_reserve = Entity( - _id=domain, - entity_type="reserve", - ) - - try: - await self.collection.insert_one(to_reserve.model_dump(by_alias=True)) - logger.info(f"Reserved entity <{domain}>") - except DuplicateKeyError: - return False - - return True - - async def attach(self, domain: str, entity_type: str, entity_id: int) -> None: - """ - Attaching entity to existing reserved entity. Defined entity type and id - Args: - domain: Domain attach to - entity_type: attaching entity type - entity_id: attaching entity id - """ - - await self.collection.find_one_and_update({"_id": domain}, {"$set": { - "entity_type": entity_type, - "entity_id": entity_id - }}, upsert=True) - - async def delete(self, domain: str) -> None: - """ - Deleting entity by domain - Args: - domain: domain - """ - await self.collection.delete_one({"_id": domain}) - logger.info(f"Deleted entity <{domain}>") diff --git a/src/db/managers/group_database_manager.py b/src/db/managers/group_database_manager.py deleted file mode 100644 index 4ea4181..0000000 --- a/src/db/managers/group_database_manager.py +++ /dev/null @@ -1,53 +0,0 @@ -"""GroupDatabaseManager definition""" -from db.helpers.abstract_database_manager import AbstractDatabaseManager -from db.models.group import Group -from config import Config -from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface -from db.models.annotations import IntIdAnnotation - - -class GroupDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): - """Database methods with groups""" - - collection_name = Config.Collections.groups - - async def get(self, _id: int) -> Group | None: - """ - Getting group by id - Args: - _id: mongo object id - Returns: - Group object or None if not found - """ - group = await self.collection.find_one({"_id": _id}) - if group is None: - return None - return Group(**group) - - async def insert_with_id(self, group: Group) -> int: - """ - Insert used with auto increment - Args: - group: used document to insert - """ - return await self._insert_one_with_id(self.collection_name, group) - - async def get_all(self) -> list[Group]: - to_return = [] - cursor = self.collection.find({}) - async for group in cursor: - to_return.append(Group(**group)) - - return to_return - - async def add_contest(self, group_id: IntIdAnnotation, contest_id: IntIdAnnotation) -> None: - """ - Inserting new contest id in group contests - Args: - group_id: target group - contest_id: contest to insert - """ - await self.collection.update_one( - {"_id": group_id}, - {"$push": {"contests": contest_id}} - ) diff --git a/src/db/managers/problem_database_manager.py b/src/db/managers/problem_database_manager.py deleted file mode 100644 index be407a2..0000000 --- a/src/db/managers/problem_database_manager.py +++ /dev/null @@ -1,42 +0,0 @@ -"""ProblemDatabaseManager definition""" -from config import Config -from db.helpers.abstract_database_manager import AbstractDatabaseManager -from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface -from db.models.problem import IntIdAnnotation -from db.models.problem import Problem -from db.models.annotations import NameAnnotation - - -class ProblemDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): - """Database methods to work with problems""" - - collection_name = Config.Collections.problems - - async def get(self, problem: IntIdAnnotation) -> Problem | None: - """ - Getting user by id - Args: - problem: the user id - """ - - task = await self.collection.find_one({"_id": problem}) - - if task is None: - return None - return Problem(**task) - - async def insert_with_id(self, problem: Problem) -> int: - """ - Insert used with auto increment - Args: - problem: used document to insert - """ - return await self._insert_one_with_id(self.collection_name, problem) - - async def get_by_name(self, name: NameAnnotation) -> Problem | None: - - problem = await self.collection.find_one({"name": name}) - - if problem is None: - return None - return Problem(**problem) diff --git a/src/db/managers/role_database_manager.py b/src/db/managers/role_database_manager.py deleted file mode 100644 index 72003c4..0000000 --- a/src/db/managers/role_database_manager.py +++ /dev/null @@ -1,32 +0,0 @@ -"""Role database manager.""" - -from db.helpers.abstract_database_manager import AbstractDatabaseManager -from db.models.role import Role -from config import Config - - -class RoleDatabaseManager(AbstractDatabaseManager): - """Role database manager.""" - - collection_name = Config.Collections.roles - - async def insert(self, role: Role) -> None: - """ - Insert new role to database - Args: - role: role to insert - """ - await self.collection.insert_one(role.model_dump(by_alias=True)) - - async def get(self, role_id: str) -> Role | None: - """ - Get role by id - Args: - role_id: Target role id - Returns: - Role or None - """ - result = await self.collection.find_one({"_id": role_id}) - if result is None: - return None - return Role(**result) diff --git a/src/db/managers/submission_database_manager.py b/src/db/managers/submission_database_manager.py deleted file mode 100644 index 4493b12..0000000 --- a/src/db/managers/submission_database_manager.py +++ /dev/null @@ -1,65 +0,0 @@ -"""SubmissionatabaseManager definition""" -from config import Config -from db.helpers.abstract_database_manager import AbstractDatabaseManager -from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface -from db.models.problem import IntIdAnnotation -from db.models.submission import Submission - - -class SubmissionDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): - """Database manager to work with submissions""" - - collection_name = Config.Collections.submissions - - async def get(self, submission_id: IntIdAnnotation) -> Submission | None: - """ - Getting submission by id - Args: - submission_id: the submission id - """ - - submission = await self.collection.find_one({"_id": submission_id}) - - if submission is None: - return None - return Submission(**submission) - - async def insert_with_id(self, submission: Submission) -> int: - """ - Insert submission with auto increment - Args: - submission: submission document to insert - """ - return await self._insert_one_with_id(self.collection_name, submission) - - async def attach_solution_path( - self, - submission_id: IntIdAnnotation, - solution_path: str - ) -> None: - """ - Attaching source code to submission - Args: - submission_id: submission id - solution_path: the source code path - """ - - await self.collection.update_one({"_id": submission_id}, {"$set": { - "solution_path": solution_path - }}) - - async def get_all_submission_for_user_in_contest( - self, - user_id: IntIdAnnotation, - contest_id: IntIdAnnotation - ) -> list[Submission]: - result: list[Submission] = [] - cursor = self.collection.find({ - "user_id": user_id, - "contest_id": contest_id - }) - - async for document in cursor: - result.append(Submission(**document)) - - return result diff --git a/src/db/managers/user_database_manager.py b/src/db/managers/user_database_manager.py deleted file mode 100644 index f54767c..0000000 --- a/src/db/managers/user_database_manager.py +++ /dev/null @@ -1,74 +0,0 @@ -"""UserDatabaseManager definition""" -from db.helpers.abstract_database_manager import AbstractDatabaseManager -from db.helpers.auto_increment_database_interface import AutoIncrementDatabaseInterface -from db.models.user import User -from config import Config - - -class UserDatabaseManager(AbstractDatabaseManager, AutoIncrementDatabaseInterface): - """Database methods to work with users""" - - collection_name = Config.Collections.users - - async def get(self, user_id: int) -> User | None: - """ - Getting user by id - Args: - user_id: the user id - - Returns: - User object or None, if not found - """ - - user = await self.collection.find_one({"_id": user_id}) - if user is None: - return None - return User(**user) - - async def get_by_email(self, email: str) -> User | None: - """ - Getting user by email - Args: - email: the email - - Returns: - User object or None, if not found - """ - - user = await self.collection.find_one({"email": email}) - if user is None: - return None - return User(**user) - - async def add_role(self, user_id: int, role_id: str) -> None: - """ - Adding role to user - Args: - user_id: the user - role_id: the role - """ - - await self.collection.update_one( - {"_id": user_id}, - {"$push": {"roles": role_id}} - ) - - async def delete_role(self, user_id: int, role_id: str) -> None: - """ - Deleting role to user - Args: - user_id: target user - role_id: role to delete - """ - await self.collection.update_one( - {"_id": user_id}, - {"$pull": {"roles": role_id}} - ) - - async def insert_with_id(self, user: User) -> int: - """ - Insert used with auto increment - Args: - user: used document to insert - """ - return await self._insert_one_with_id(self.collection_name, user) diff --git a/src/db/methods/__init__.py b/src/db/methods/__init__.py new file mode 100644 index 0000000..854a5e9 --- /dev/null +++ b/src/db/methods/__init__.py @@ -0,0 +1,9 @@ +from . import users +from . import roles +from . import domains + +__all__ = [ + "users", + "roles", + "domains" +] diff --git a/src/db/methods/collections/__init__.py b/src/db/methods/collections/__init__.py new file mode 100644 index 0000000..9602801 --- /dev/null +++ b/src/db/methods/collections/__init__.py @@ -0,0 +1,20 @@ +"""This module for working with collections""" + +from . collections import users, \ + roles, \ + domains, \ + contests, \ + group_roles, \ + group_members, \ + internal_counters + + +__all__ = [ + "users", + "roles", + "domains", + "contests", + "group_roles", + "group_members", + "internal_counters" +] diff --git a/src/db/methods/collections/collections.py b/src/db/methods/collections/collections.py new file mode 100644 index 0000000..0502c4c --- /dev/null +++ b/src/db/methods/collections/collections.py @@ -0,0 +1,21 @@ +""" +The module that receives all collections by the configured name and exports them +Moreover this module create indexes +""" + +from db.client import db +from config import config + + +roles = db.get_collection(config.database.collections.roles) +users = db.get_collection(config.database.collections.users) +groups = db.get_collection(config.database.collections.groups) +domains = db.get_collection(config.database.collections.domains) +contests = db.get_collection(config.database.collections.contests) +group_roles = db.get_collection(config.database.collections.group_roles) +group_members = db.get_collection(config.database.collections.group_members) +internal_counters = db.get_collection(config.database.collections.internal_counters) + + +users.create_index([("email", 1)], unique=True, name="email") +domains.create_index([("target_id", 1)], unique=True, name="target_id") diff --git a/src/db/methods/domains.py b/src/db/methods/domains.py new file mode 100644 index 0000000..93ad98d --- /dev/null +++ b/src/db/methods/domains.py @@ -0,0 +1,43 @@ +from pymongo.errors import DuplicateKeyError + +from db import types +from db.types.common import IntegerId, DomainName +from .collections import domains + + +def reserve_entity(domain: DomainName) -> bool: + """Creates entity with type None for domain + Returns: + True if ok, else False (domain already used) + """ + try: + domains.insert_one({ + "_id": domain, + }) + except DuplicateKeyError: + return False + return True + +def attach_to_entity( + domain: DomainName, + target_id: IntegerId, + target_type: types.domain.TargetType +) -> None: + domains.find_one_and_update( + {"_id": domain}, + {"$set": { + "target_id": target_id, + "target_type": target_type + }}, + upsert=True + ) + +def resolve_id( + domain: DomainName, + target_type: types.domain.TargetType +) -> IntegerId | None: + entity = domains.find_one({"_id": domain, "target_type": target_type}) + + if entity is None: + return None + return types.domain.Entity(**entity).target_id diff --git a/src/db/methods/helpers.py b/src/db/methods/helpers.py new file mode 100644 index 0000000..6149002 --- /dev/null +++ b/src/db/methods/helpers.py @@ -0,0 +1,26 @@ +from typing import Any +from pymongo.collection import Collection +from pymongo.errors import DuplicateKeyError +from .collections import internal_counters + + +def insert_with_auto_increment_id( + collection: Collection[Any], + document: dict[str, Any] +) -> int: + while True: + try: + result_id = internal_counters.find_one_and_update( + {"_id": collection.name}, + {"$inc": {"counter": 1}}, upsert=True, return_document=True + )["counter"] + document["_id"] = result_id + collection.insert_one(document) + return result_id + except DuplicateKeyError as e: + if ( + e.details is None or + (key_pattern := e.details.get("keyPattern")) is None or + key_pattern.get("_id") is None + ): + raise e diff --git a/src/db/methods/roles.py b/src/db/methods/roles.py new file mode 100644 index 0000000..d380550 --- /dev/null +++ b/src/db/methods/roles.py @@ -0,0 +1,20 @@ +from pymongo.errors import DuplicateKeyError +from db.types.role import Role +from .collections import roles + +def get(role_name: str) -> Role | None: + role = roles.find_one({"_id": role_name}) + + if role is None: + return None + return Role(**role) + +def insert(role: Role) -> bool: + """ + Returns: False - if DuplicateKeyError, else - True + """ + try: + roles.insert_one(role.model_dump()) + except DuplicateKeyError: + return False + return True diff --git a/src/db/methods/users.py b/src/db/methods/users.py new file mode 100644 index 0000000..c9ed40e --- /dev/null +++ b/src/db/methods/users.py @@ -0,0 +1,36 @@ +from typing import Any +from pymongo.errors import DuplicateKeyError + +from db.types.common import IntegerId, Email +from db.types.user import User +from .collections import users +from .helpers import insert_with_auto_increment_id + + +def get(user_id: IntegerId) -> User | None: + user = users.find_one({ + "_id": user_id + }) + if user is None: + return None + return User(**user) + +def get_by_email(email: Email): + user = users.find_one({ + "email": email + }) + if user is None: + return None + return User(**user) + +def insert_user_document_with_id(user_document: dict[str, Any]) -> IntegerId | None: + """ + Returns: None if DuplicateKeyError. Else - inserted_user_id + """ + try: + return insert_with_auto_increment_id( + users, + user_document + ) + except DuplicateKeyError: + return None diff --git a/src/db/models/__init__.py b/src/db/models/__init__.py deleted file mode 100644 index d9338b0..0000000 --- a/src/db/models/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Base models for database and fastapi""" -from . import user -from . import group -from . import role -from . import entity -from . import annotations - -__all__ = ["user", "group", "role", "entity", "annotations"] diff --git a/src/db/models/annotations/__init__.py b/src/db/models/annotations/__init__.py deleted file mode 100644 index b355c6f..0000000 --- a/src/db/models/annotations/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -"""Annotations for BaseModels fields""" -from typing import Annotated -from pydantic import AfterValidator -from db.models.annotations import validators - -IntIdAnnotation = Annotated[int, AfterValidator(validators.positive_number)] -EmailAnnotation = Annotated[str, AfterValidator(validators.email_string)] -DomainAnnotation = Annotated[str, AfterValidator(validators.domain_name)] -NameAnnotation = Annotated[str, AfterValidator(validators.name_string)] -DescriptionAnnotation = Annotated[str, AfterValidator(validators.description_string)] -RoleCodeAnnotation = Annotated[int, AfterValidator(validators.not_negative_number)] -StrIdAnnotation = Annotated[str, AfterValidator(validators.string_id)] -StrIntIdAnnotation = Annotated[str, AfterValidator(validators.string_positive_number)] diff --git a/src/db/models/annotations/validators.py b/src/db/models/annotations/validators.py deleted file mode 100644 index eaa0a36..0000000 --- a/src/db/models/annotations/validators.py +++ /dev/null @@ -1,124 +0,0 @@ -"""Validating functions for the application""" -import re - - -def email_string(email: str) -> str: - """Check if given string is email - - Args: - email: string to check - Returns: - email - Raises: - ValueError: If string is not a valid email - """ - pattern = r"^[a-zA-Z0-9_\.]+@[a-zA-Z0-9_\.]+\.[a-z]{2,5}" - if re.fullmatch(pattern, email) is None: - raise ValueError(f"String {email} is not a valid email") - return email - - -def positive_number(number: int) -> int: - """Check if given integer is positive - Args: - number: number to check - Returns: - number - Raises: - ValueError: If number not positive - """ - - if number <= 0: - raise ValueError(f"Number {number} must be a positive number") - return number - - -def domain_name(domain: str) -> str: - """ - Check if given domain is valid domain - Args: - domain: domain to check - Returns: - Domain - Raises: - ValueError: If domain is not valid - """ - return domain # TODO: define behaviour - - -def name_string(name: str) -> str: - """ - Check if given name is valid name - Args: - name: name to check - Returns: - name - Raises: - ValueError: is name is not valid - """ - return name # TODO: define behaviour - - -def description_string(description: str) -> str: - """ - Check if given description is valid description - Args: - description: description to check - Returns: - description - Raises: - ValueError: is description is not valid - """ - return description # TODO: define behaviour - - -def not_negative_number(number: int) -> int: - """ - Check if given number is not negative - Args: - number: number to check - Returns: - number - Raises: - ValueError: is number is negative - """ - - if number < 0: - raise ValueError(f"Number {number} must be a positive number") - return number - - -def string_id(string: str) -> str: - """ - Check if given string is valid id - Args: - string: string to validate - Returns: - string - Raises: - ValueError: is string is not valid - """ - pattern = r"[a-z]+(?:_[a-z]+)*" - if re.fullmatch(pattern, string) is None: - raise ValueError("String is not valid") - return string - - -def string_positive_number(string: str) -> str: - """ - Check if given string is a number and positive number - Args: - string: string to check - Returns: - string - Raises: - ValueError: if given string is not a positive number - """ - num = 0 - try: - num = int(string) - except Exception as e: - raise ValueError("string is not a number") from e - if num <= 0: - raise ValueError("String is not a positive number") - return string diff --git a/src/db/models/contest.py b/src/db/models/contest.py deleted file mode 100644 index f142c98..0000000 --- a/src/db/models/contest.py +++ /dev/null @@ -1,50 +0,0 @@ -"""Group definition""" -from datetime import datetime - -from pydantic import BaseModel, Field -from db.models.annotations import IntIdAnnotation, NameAnnotation, DescriptionAnnotation, \ - DomainAnnotation, RoleCodeAnnotation, StrIdAnnotation - - -class Submission(BaseModel): - """User submission""" - - # id: IntIdAnnotation = Field(alias="") - upload_time: datetime - code_text: str - status: str | None = None - target_problem_id: IntIdAnnotation - - -class Contest(BaseModel): - """Group representation in database""" - id: IntIdAnnotation = Field(alias='_id') - """Group id""" - - name: NameAnnotation - """Group name""" - - description: DescriptionAnnotation = Field("") - """Group description""" - - domain: DomainAnnotation | None = Field(None) - """Group domain""" - - linked_group: IntIdAnnotation - """Linked group""" - - problems: list[IntIdAnnotation] = Field([]) - - submissions: list[Submission] = Field([]) - - -class ContestToCreate(BaseModel): - """Group to create template""" - - name: NameAnnotation - - description: DescriptionAnnotation = Field("") - - domain: DomainAnnotation | None = Field(None) - - linked_group: IntIdAnnotation diff --git a/src/db/models/entity.py b/src/db/models/entity.py deleted file mode 100644 index 7ef0e82..0000000 --- a/src/db/models/entity.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Domain router representation in the database""" -from typing import Literal -from pydantic import BaseModel, Field -from db.models.annotations import IntIdAnnotation, DomainAnnotation - - -class Entity(BaseModel): - """Domain router representation in the database""" - - id: DomainAnnotation = Field(alias='_id') - """Domain router domain""" - - entity_type: Literal["group"] | Literal["user"] | Literal["reserve"] - """Type of the linked entity""" - - entity_id: IntIdAnnotation | None = None - """ID of the linked entity""" diff --git a/src/db/models/group.py b/src/db/models/group.py deleted file mode 100644 index 433d4bb..0000000 --- a/src/db/models/group.py +++ /dev/null @@ -1,71 +0,0 @@ -"""Group definition""" -from pydantic import BaseModel, Field -from db.models.annotations import IntIdAnnotation, NameAnnotation, DescriptionAnnotation, \ - DomainAnnotation, RoleCodeAnnotation, StrIdAnnotation - - -class GroupRole(BaseModel): - """Group role""" - - id: StrIdAnnotation = Field(alias="_id") - """Group role id""" - - name: NameAnnotation - """Role name""" - - role_code: RoleCodeAnnotation - """role code""" - - description: DescriptionAnnotation = Field("") - """role description""" - - -class GroupMember(BaseModel): - """The user's access value generated by several fields""" - id: IntIdAnnotation = Field(alias="_id") - """Connected user id""" - - permissions: RoleCodeAnnotation - """Result role code, that represents final permissions""" - - roles: list[StrIdAnnotation] = Field([]) - """Roles, which member has""" - - -class Group(BaseModel): - """Group representation in database""" - id: IntIdAnnotation = Field(alias='_id') - """Group id""" - - name: NameAnnotation - """Group name""" - - description: DescriptionAnnotation = Field("") - """Group description""" - - domain: DomainAnnotation | None = Field(None) - """Group domain""" - - members: list[GroupMember] = Field([]) - """Group members""" - - owner: IntIdAnnotation - """User ID of group owner""" - - roles: list[GroupRole] = Field([]) - """List of names group roles in group""" - - contests: list[IntIdAnnotation] = Field([]) - - -class GroupToCreate(BaseModel): - """Group to create template""" - - name: NameAnnotation - - description: DescriptionAnnotation = Field("") - - domain: DomainAnnotation | None = Field(None) - - members: list[IntIdAnnotation] = Field([]) - """Who will be in group""" diff --git a/src/db/models/problem.py b/src/db/models/problem.py deleted file mode 100644 index 5aa58b5..0000000 --- a/src/db/models/problem.py +++ /dev/null @@ -1,12 +0,0 @@ -from pydantic import BaseModel, Field -from db.models.annotations import IntIdAnnotation, NameAnnotation - - -class Problem(BaseModel): - """Problem representation""" - - id: IntIdAnnotation = Field(alias='_id') - - name: NameAnnotation - - # TODO: add tags and other diff --git a/src/db/models/role.py b/src/db/models/role.py deleted file mode 100644 index 5fd39e3..0000000 --- a/src/db/models/role.py +++ /dev/null @@ -1,20 +0,0 @@ -"""Role definition""" -from pydantic import BaseModel, Field -from db.models.annotations import NameAnnotation, DescriptionAnnotation, \ - RoleCodeAnnotation, StrIdAnnotation - - -class Role(BaseModel): - """Role representation in database""" - - id: StrIdAnnotation = Field(alias='_id') - """Short string ID (e.g. 'admin'))""" - - name: NameAnnotation - """Role name""" - - description: DescriptionAnnotation - """Role description""" - - role_code: RoleCodeAnnotation - """Role representation in integer""" diff --git a/src/db/models/submission.py b/src/db/models/submission.py deleted file mode 100644 index f6e3323..0000000 --- a/src/db/models/submission.py +++ /dev/null @@ -1,31 +0,0 @@ -from datetime import datetime -from typing import Annotated - -from pydantic import BaseModel, Field, AfterValidator -from db.models.annotations import IntIdAnnotation - - -class SubmissionToCreate(BaseModel): - - problem_id: IntIdAnnotation - - contest_id: IntIdAnnotation - - solution: str - - -class Submission(BaseModel): - - id: IntIdAnnotation = Field(alias="_id") - - problem_id: IntIdAnnotation - - contest_id: IntIdAnnotation - - user_id: IntIdAnnotation - - solution_path: str | None = None - - status: str | None = None - - upload_time: str diff --git a/src/db/models/user.py b/src/db/models/user.py deleted file mode 100644 index fd9546a..0000000 --- a/src/db/models/user.py +++ /dev/null @@ -1,33 +0,0 @@ -"""User definition and some useful stuff about user""" -from pydantic import BaseModel, Field -from db.models.annotations import IntIdAnnotation, DomainAnnotation, EmailAnnotation, \ - StrIdAnnotation - - -class User(BaseModel): - """User representation in database""" - id: IntIdAnnotation = Field(alias='_id') - email: EmailAnnotation - domain: DomainAnnotation | None = Field(None) - password_hash: str - first_name: str - last_name: str - mid_name: str | None = Field(None) - roles: list[StrIdAnnotation] = Field([]) - """List of global roles, which user have""" - - -class UserSignup(BaseModel): - """Data for Signup user""" - domain: DomainAnnotation | None = Field(None) - password: str - first_name: str - last_name: str - mid_name: str | None = Field(None) - email: EmailAnnotation - - -class UserSignin(BaseModel): - """Data for user signin""" - login: str - password: str diff --git a/src/db/mongo_manager.py b/src/db/mongo_manager.py deleted file mode 100644 index 72374e7..0000000 --- a/src/db/mongo_manager.py +++ /dev/null @@ -1,66 +0,0 @@ -"""Core database mongo manager""" - -from loguru import logger -from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase -from motor.core import AgnosticClient - - -class MongoManager: - """The main class for communicate with database""" - - _db: AsyncIOMotorDatabase | None = None - _client: AgnosticClient | None = None - - @classmethod - def get_db(cls) -> AsyncIOMotorDatabase: - """ - Get database - Returns: database - """ - - if cls._db is None: - logger.error("Database not initialized") - raise ConnectionError("Database not initialized") - - return cls._db - - @classmethod - def get_client(cls) -> AgnosticClient: - """ - Get mongo client - Returns: mongo client - """ - - if cls._client is None: - logger.error("Client not initialized") - raise ConnectionError("Client not initialized") - - return cls._client - - @classmethod - def connect(cls, url: str, db_name: str) -> None: - """ - Connect to database - Args: - url: path to database - db_name: name for target database - """ - cls._client = AsyncIOMotorClient(url) - cls._db = cls._client.get_database(db_name) - logger.info(f"Connecting to database: {db_name} by pass {url}") - - if cls._db is None: - logger.error("Database is not connected") - raise ConnectionError("Database is not connected") - logger.info("Successfully connected to MongoDB.") - - @classmethod - def disconnect(cls) -> None: - """ - Disconnect from database - """ - if cls._client is None: - return - logger.info("Closing connection with MongoDB.") - cls._client.close() - logger.info("Successfully closed connection with MongoDB.") diff --git a/src/db/types/__init__.py b/src/db/types/__init__.py new file mode 100644 index 0000000..c2b534f --- /dev/null +++ b/src/db/types/__init__.py @@ -0,0 +1,13 @@ +from . import auth +from . import user +from . import common +from . import domain +from . import role + +__all__ = [ + "auth", + "user", + "common", + "domain", + "role" +] diff --git a/src/db/types/auth.py b/src/db/types/auth.py new file mode 100644 index 0000000..19b2180 --- /dev/null +++ b/src/db/types/auth.py @@ -0,0 +1,23 @@ +from pydantic import model_validator + +from utils.schemas import BaseModel +from db.types.common import IntegerId, DomainName, Email + + +class JWTPair(BaseModel): + access: str + refresh: str + +class SignInInput(BaseModel): + id: IntegerId | None = None + domain: DomainName | None = None + email: Email | None = None + password: str + + @model_validator(mode="after") + def check_only_one_field(self): + assert (self.id is None) + \ + (self.domain is None) + \ + (self.email is None) == 2, \ + "You must provide exactly one of the fields: email, domain, user_id" + return self diff --git a/src/db/types/common.py b/src/db/types/common.py new file mode 100644 index 0000000..64add75 --- /dev/null +++ b/src/db/types/common.py @@ -0,0 +1,47 @@ +"""Common project types""" +import re +from typing import Annotated +from pydantic import AfterValidator + + + +def _is_email(email: str) -> str: + pattern = r"^[a-zA-Z0-9_\.]+@[a-zA-Z0-9_\.]+\.[a-z]{2,5}" + assert re.fullmatch(pattern, email) is not None, f"String {email} is not a valid email" + return email +Email = Annotated[str, AfterValidator(_is_email)] + +def _is_positive_number(number: int) -> int: + """Check if given integer is positive + Args: + number: number to check + Returns: + number + """ + + assert number > 0, f"Number {number} must be a positive number" + return number +IntegerId = Annotated[int, AfterValidator(_is_positive_number)] + +def _is_domain_name(domain: str) -> str: + return domain # TODO: define behaviour +DomainName = Annotated[str, AfterValidator(_is_domain_name)] + +def _is_object_name(name: str) -> str: + return name # TODO: define behaviour +ObjectName = Annotated[str, AfterValidator(_is_object_name)] + +def _is_object_description(description: str) -> str: + return description # TODO: define behaviour +ObjectDescription = Annotated[str, AfterValidator(_is_object_description)] + +def _is_role_code(number: int) -> int: + assert number >= 0, "Role code can not be negative" + return number +RoleCode = Annotated[int, AfterValidator(_is_role_code)] + +def _string_id(string: str) -> str: + pattern = r"[a-z]+(?:_[a-z]+)*" + assert re.fullmatch(pattern, string) is not None, "String id is not valid" + return string +StringId = Annotated[str, AfterValidator(_string_id)] diff --git a/src/db/types/contest.py b/src/db/types/contest.py new file mode 100644 index 0000000..aebe419 --- /dev/null +++ b/src/db/types/contest.py @@ -0,0 +1,22 @@ +import datetime +from pydantic import Field + +from utils.schemas import BaseModel +from .common import IntegerId, ObjectName, DomainName, ObjectDescription + + +class Contest(BaseModel): + """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-375""" + + id: IntegerId = Field(alias='_id') + name: ObjectName + domain: DomainName | None = None + local_domain: DomainName | None = None + description: ObjectDescription = "" + submissions: list[IntegerId] + members: list[IntegerId] + creators: list[IntegerId] + begin_time: datetime.datetime + duration: datetime.datetime + after_work: bool + group_id: IntegerId diff --git a/src/db/types/contest_member.py b/src/db/types/contest_member.py new file mode 100644 index 0000000..50afdb5 --- /dev/null +++ b/src/db/types/contest_member.py @@ -0,0 +1,11 @@ +from pydantic import Field + +from utils.schemas import BaseModel +from .common import IntegerId + + +class ContestMember(BaseModel): + """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-435""" + + id: IntegerId = Field(alias="_id") + contest_id: IntegerId diff --git a/src/db/types/domain.py b/src/db/types/domain.py new file mode 100644 index 0000000..1f28c59 --- /dev/null +++ b/src/db/types/domain.py @@ -0,0 +1,14 @@ +from typing import Literal +from pydantic import Field + +from utils.schemas import BaseModel +from .common import IntegerId, DomainName + +TargetType = Literal["user", "group", "contest"] + +class Entity(BaseModel): + """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-395""" + + id: DomainName = Field(alias='_id') + target_type: TargetType | None = None + target_id: IntegerId | None = None diff --git a/src/db/types/group.py b/src/db/types/group.py new file mode 100644 index 0000000..cbaede8 --- /dev/null +++ b/src/db/types/group.py @@ -0,0 +1,15 @@ +from pydantic import Field + +from utils.schemas import BaseModel +from .common import IntegerId, ObjectName, DomainName, StringId, ObjectDescription + +class Group(BaseModel): + """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-335""" + + id: IntegerId = Field(alias='_id') + name: ObjectName + domain: DomainName | None = None + description: ObjectDescription + members: list[IntegerId] = [] + owner: IntegerId + roles: list[StringId] = [] diff --git a/src/db/types/group_member.py b/src/db/types/group_member.py new file mode 100644 index 0000000..2d3ada7 --- /dev/null +++ b/src/db/types/group_member.py @@ -0,0 +1,13 @@ +from pydantic import Field + +from utils.schemas import BaseModel +from .common import IntegerId, RoleCode + + +class GroupMember(BaseModel): + """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-415""" + + id: IntegerId = Field(alias="_id") + group_id: IntegerId + custom_permissions: RoleCode + roles: list[IntegerId] diff --git a/src/db/types/group_role.py b/src/db/types/group_role.py new file mode 100644 index 0000000..a5afbc9 --- /dev/null +++ b/src/db/types/group_role.py @@ -0,0 +1,13 @@ +from pydantic import Field + +from utils.schemas import BaseModel +from .common import StringId, ObjectName, ObjectDescription, IntegerId, RoleCode + +class GroupRole(BaseModel): + """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-495""" + + id: StringId = Field(alias='_id') + name: ObjectName + description: ObjectDescription + group_id: IntegerId + role_code: RoleCode diff --git a/src/db/types/problem.py b/src/db/types/problem.py new file mode 100644 index 0000000..4f0a87a --- /dev/null +++ b/src/db/types/problem.py @@ -0,0 +1,10 @@ +from pydantic import Field + +from utils.schemas import BaseModel +from .common import IntegerId, ObjectName + +class Problem(BaseModel): + """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-455""" + + id: IntegerId = Field(alias='_id') + name: ObjectName diff --git a/src/db/types/role.py b/src/db/types/role.py new file mode 100644 index 0000000..dd6adab --- /dev/null +++ b/src/db/types/role.py @@ -0,0 +1,12 @@ +from pydantic import Field + +from utils.schemas import BaseModel +from .common import StringId, ObjectName, ObjectDescription, RoleCode + +class Role(BaseModel): + """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-315""" + + id: StringId = Field(alias='_id') + name: ObjectName + description: ObjectDescription = "" + code: RoleCode diff --git a/src/db/types/submission.py b/src/db/types/submission.py new file mode 100644 index 0000000..ce7ac31 --- /dev/null +++ b/src/db/types/submission.py @@ -0,0 +1,17 @@ +import datetime +from typing import Literal +from pydantic import Field + +from utils.schemas import BaseModel +from .common import IntegerId + + +class Submission(BaseModel): + """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-475""" + id: IntegerId = Field(alias="_id") + problem_id: IntegerId + contest_id: IntegerId + user_id: IntegerId + solution_path: str | None = None + status: Literal["Testing", "OK"] + upload_time: datetime.datetime diff --git a/src/db/types/user.py b/src/db/types/user.py new file mode 100644 index 0000000..1e1ea27 --- /dev/null +++ b/src/db/types/user.py @@ -0,0 +1,23 @@ +from pydantic import Field + +from utils.schemas import BaseModel +from .common import IntegerId, DomainName, Email, StringId + +class User(BaseModel): + """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-295""" + + id: IntegerId = Field(alias='_id') + domain: DomainName | None = Field(None) + first_name: str | None = Field(None) + last_name: str | None = Field(None) + mid_name: str | None = Field(None) + groups: list[IntegerId] = [] + roles: list[StringId] = [] + hashed_password: str + email: Email + + +class UserSignup(BaseModel): + domain: DomainName | None = Field(None) + email: Email + password: str diff --git a/src/main.py b/src/main.py index c4a0303..7107997 100644 --- a/src/main.py +++ b/src/main.py @@ -1,64 +1,59 @@ -"""Main project file""" - from contextlib import asynccontextmanager +from loguru import logger from fastapi import FastAPI +from fastapi.exceptions import RequestValidationError from starlette.middleware.cors import CORSMiddleware -from auth.utils import AuthException -from utils.handlers import auth_exception_handler +import db +import utils.handlers +import utils.response +import utils.auth +import utils.misc from config import config -import routers.auth_router -from db.mongo_manager import MongoManager -import routers.contests_router -import routers.problems_router -import routers.submissions_router +import routers @asynccontextmanager async def lifespan(_app: FastAPI): - """Application lifespan (see https://fastapi.tiangolo.com/advanced/events/) - In the application lifespan we need to connect and close connection to - the database. - Args: - _app (FastAPI): application object. It is not using right now - """ + logger.info("Starting application") - # on startup - MongoManager.connect( - config.database.connect_url.get_secret_value(), - config.database.name - ) + utils.misc.create_super_user() yield - # on shutdown - MongoManager.disconnect() + db.close_connection() + logger.info("Shutting down application") -app = FastAPI(title=config.app_title, debug=True, lifespan=lifespan) +app = FastAPI(title=config.app_title, debug=config.debug, lifespan=lifespan) +app.include_router(routers.users.router, prefix="/api/users") +app.include_router(routers.auth.router, prefix="/api/auth") +app.include_router(routers.roles.router, prefix="/api/roles") +app.include_router(routers.groups.router, prefix="/api/groups") +app.include_router(routers.contests.router, prefix="/api/contests") +app.include_router(routers.problems.router, prefix="/api/problems") +app.include_router(routers.submissions.router, prefix="/api/submissions") +app.include_router(routers.service.router, prefix="/api/service") -origins = [ - "http://localhost", - "http://localhost:8080", - "http://localhost:5173", - "http://localhost:3000", -] app.add_middleware( CORSMiddleware, - allow_origins=origins, - allow_credentials=True, + allow_origins=config.allow_origins, + allow_credentials=config.debug, allow_methods=["*"], allow_headers=["*"], ) -# routers -app.include_router(routers.users_router.router, prefix="/api/users") -app.include_router(routers.auth_router.router, prefix="/api/auth") -app.include_router(routers.roles_router.router, prefix="/api/roles") -app.include_router(routers.groups_router.router, prefix="/api/groups") -app.include_router(routers.contests_router.router, prefix="/api/contests") -app.include_router(routers.problems_router.router, prefix="/api/problems") -app.include_router(routers.submissions_router.router, prefix="/api/submissions") +app.add_exception_handler( + RequestValidationError, + utils.handlers.request_validation_exception_handler +) -# exception handlers -app.add_exception_handler(AuthException, auth_exception_handler) +app.add_exception_handler( + utils.response.ErrorResponse, + utils.handlers.error_response_handler +) + +app.add_exception_handler( + 500, + utils.handlers.internal_exception_handler +) diff --git a/src/producer.py b/src/producer.py deleted file mode 100644 index c16eb6a..0000000 --- a/src/producer.py +++ /dev/null @@ -1,17 +0,0 @@ -import pika -from config import Config -from loguru import logger -from db.models.annotations import IntIdAnnotation - - -def produce_submission(submission_id: IntIdAnnotation): - with pika.BlockingConnection(pika.ConnectionParameters( - host='localhost')) as connection: - channel = connection.channel() - - channel.queue_declare(queue=Config.rabbitmq_main_queue) - - channel.basic_publish(exchange="", - routing_key=Config.rabbitmq_main_queue, - body=f"{submission_id}") - logger.info(f'Published submission with id {submission_id}') diff --git a/src/routers/__init__.py b/src/routers/__init__.py index 87e41bd..292670b 100644 --- a/src/routers/__init__.py +++ b/src/routers/__init__.py @@ -1,6 +1,22 @@ """Module to manage routers""" -from . import users_router -from . import roles_router -from . import groups_router -# from . import domain_router -__all__ = ["users_router", "roles_router", "groups_router"] + +from . import auth +from . import users +from . import roles +from . import groups +from . import service +from . import problems +from . import contests +from . import submissions + + +__all__ = [ + "auth", + "users", + "roles", + "groups", + "service", + "problems", + "contests", + "submissions" +] diff --git a/src/routers/auth.py b/src/routers/auth.py new file mode 100644 index 0000000..878e0d2 --- /dev/null +++ b/src/routers/auth.py @@ -0,0 +1,74 @@ +from fastapi import APIRouter + +import utils.auth +from utils.response import SuccessfulResponse, ErrorCodes, ErrorResponse +from db import methods +from db import types + + +router = APIRouter() + + +@router.post("/signup", response_model=SuccessfulResponse[types.auth.JWTPair]) +async def signup( + user_signup: types.user.UserSignup +): + if user_signup.domain is not None: + if not methods.domains.reserve_entity(user_signup.domain): + raise ErrorResponse( + code=ErrorCodes.NAME_ALREADY_TAKEN, + message="Domain already taken" + ) + + password_hash = utils.auth.hash_password(user_signup.password) + + inserted_user_id = methods.users.insert_user_document_with_id({ + "email": user_signup.email, + "domain": user_signup.domain, + "hashed_password": password_hash + }) + + if inserted_user_id is None: + raise ErrorResponse( + code=ErrorCodes.NAME_ALREADY_TAKEN, + message="There is user with identical email" + ) + + if user_signup.domain is not None: + methods.domains.attach_to_entity( + user_signup.domain, + inserted_user_id, + "user" + ) + + return utils.auth.create_jwt_pair_by_user_id(inserted_user_id) + +@router.post("/signin", response_model=SuccessfulResponse[types.auth.JWTPair]) +async def signin( + siginin_input: types.auth.SignInInput +): + user: types.user.User | None = None + if siginin_input.id: + user = methods.users.get(siginin_input.id) + elif siginin_input.domain: + user_id = methods.domains.resolve_id(siginin_input.domain, "user") + if user_id: + user = methods.users.get(user_id) + elif siginin_input.email: + user = methods.users.get_by_email(siginin_input.email) + + if user is None: + raise ErrorResponse( + code=ErrorCodes.ENTITY_NOT_FOUND, + http_status_code=404, + message="User not found" + ) + + if not utils.auth.verify_password(siginin_input.password, user.hashed_password): + raise ErrorResponse( + code=ErrorCodes.ACCESS_DENIED, + http_status_code=403, + message="Incorrect password" + ) + + return utils.auth.create_jwt_pair_by_user_id(user.id) diff --git a/src/routers/auth_router.py b/src/routers/auth_router.py deleted file mode 100644 index 93fce20..0000000 --- a/src/routers/auth_router.py +++ /dev/null @@ -1,123 +0,0 @@ -"""All auth methods and some useful stuff""" -from typing import Literal - - -import db -from db.models.user import UserSignup, User -from auth.utils import get_hashed_password -from auth.utils import verify_password, create_token, auth_user -from auth.token_schema import TokenSchema -from utils.response_utils import get_error_response, get_response_model, get_error_schema, \ - get_response -from fastapi import APIRouter, Depends -from db.models.annotations import RoleCodeAnnotation - -router = APIRouter() - - -@router.get( - "/signin", - response_model=get_response_model(TokenSchema), - responses={ - 400: get_error_schema("Failed to signin with provided credentials.") - } -) -async def signin(login: str, password: str, login_type: Literal["email", "domain", "id"]): - """Auth user and generate JWT""" - user = None - match login_type: - case "email": - user = await db.user.get_by_email(login) - case "domain": - entity = await db.domain.resolve(login) - if entity is not None and entity.entity_type == "user" and entity.entity_id is not None: - user = await db.user.get(entity.entity_id) - case "id": - user = await db.user.get(int(login)) - if user is None: - return get_error_response("INVALID_LOGIN") - - if not verify_password(password, user.password_hash): - return get_error_response("INVALID_PASSWORD") - - return get_response({ - "access_token": create_token(str(user.id)), - "refresh_token": create_token(str(user.id), False), - }) - - -@router.post( - "/signup", - response_model=get_response_model(User), - responses={ - 400: get_error_schema("Signup failed") - } -) -async def signup(user: UserSignup): - """Creating new user""" - - password_hash = get_hashed_password(user.password) - - user_to_create = { - **user.model_dump(), - "password_hash": password_hash, - "_id": 1 # not used - } - - user_with_exact_email = await db.user.get_by_email(user.email) - if user_with_exact_email is not None: - return get_error_response("EMAIL_IN_USE") - - if user.domain is not None: - status = await db.domain.reserve(user.domain) - if status is False: - return get_error_response("DOMAIN_IN_USE") - - try: - created_user_id = await db.user.insert_with_id( - User(**user_to_create) - ) - except Exception as e: - if user.domain is not None: - await db.domain.delete(user.domain) # deleting reserved entity - raise e - - if user.domain is not None: - await db.domain.attach(user.domain, "user", created_user_id) - - created_user = await db.user.get(created_user_id) - return get_response(created_user) - - -@router.get( - "/refresh", - response_model=get_response_model(TokenSchema), - responses={ - 400: get_error_schema("Failed to refresh") - } -) -async def refresh_token(_current_user: User = Depends(auth_user())): - """Refresh tokens""" - - return get_response({ - "access_token": create_token(str(_current_user.id)), - "refresh_token": create_token(str(_current_user.id), False), - }) - -@router.get( - "/user_permissions", - responses={ - 400: get_error_schema("Failed to get user permissions") - } -) -async def user_permissions(_current_user: User = Depends(auth_user())) -> RoleCodeAnnotation: - """Get user permissions""" - - result_mask = 0 - - for role_name in _current_user.roles: - cur_role = await db.role.get(role_name) - if cur_role is not None: - result_mask |= cur_role.role_code - return result_mask - diff --git a/src/routers/contests.py b/src/routers/contests.py new file mode 100644 index 0000000..e6f2f82 --- /dev/null +++ b/src/routers/contests.py @@ -0,0 +1,4 @@ +from fastapi import APIRouter + + +router = APIRouter() diff --git a/src/routers/contests_router.py b/src/routers/contests_router.py deleted file mode 100644 index 2f500a0..0000000 --- a/src/routers/contests_router.py +++ /dev/null @@ -1,119 +0,0 @@ -"""Groups endpoints""" -import tempfile -from typing import Any - -from fastapi import APIRouter, Depends, UploadFile -from pydantic import BaseModel - -from auth.utils import auth_user -from auth.permissions import Permissions, ALL_PERMISSIONS_ROLE_CODE -from utils.response_utils import get_error_response, get_response, get_response_model, \ - get_error_schema -from db.models.contest import Contest, ContestToCreate -from db.models.problem import Problem -from db.models.user import User -import db -from db.models.annotations import NameAnnotation, IntIdAnnotation - -router = APIRouter() - - -@router.post( - "/create", - response_model=get_response_model(Contest), - responses={ - 400: get_error_schema("Failed to create contest") - } -) -async def create_contest(contest_to_create: ContestToCreate, - _current_user: User = Depends( - auth_user())) -> Any: # TODO: set permissions - """Creating new contest""" - - # check existing for all members - - linked_group = await db.group.get(contest_to_create.linked_group) - - if linked_group is None: - return get_error_response("LINKED_GROUP_NOT_FOUND") - - if _current_user.id != linked_group.owner: - return get_error_response("USER_NOT_GROUP_OWNER", - status_code=401) # TODO: make group permissions and roles - - if contest_to_create.domain is not None: - status = await db.domain.reserve(contest_to_create.domain) - if status is False: - return get_error_response("DOMAIN_IN_USE") - - try: - - # result group - contest = Contest( - _id=1, # not used - name=contest_to_create.name, - description=contest_to_create.description, - domain=contest_to_create.domain, - linked_group=contest_to_create.linked_group, - problems=[] - ) - - created_contest_id = await db.contest.insert_with_id(contest) - - await db.group.add_contest(contest.linked_group, created_contest_id) - - if contest.domain is not None: - await db.domain.attach(contest.domain, "user", created_contest_id) - - created_contest = await db.contest.get(created_contest_id) - - return get_response(created_contest) - - except Exception as e: - if contest_to_create.domain is not None: - await db.domain.delete( - contest_to_create.domain - ) # if error occurs delete reserved entity - raise e - - -@router.get( - "/get", - response_model=get_response_model(Contest), - responses={ - 400: get_error_schema("Failed to retrieve contest") - } -) -async def get_contest(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())) -> Any: - """Return a contest by id""" - - contest = await db.contest.get(_id) - - if contest is None: - return get_error_schema("CONTEST_NOT_FOUND") - - return get_response(contest) - - -@router.post( - "/add_problem", - response_model=get_response_model(), - responses={ - 400: get_error_schema("Failed to add task to contest") - } -) -async def add_problem_to_contest( - problem_id: IntIdAnnotation, - contest_id: IntIdAnnotation, - _current_user: User = Depends( - auth_user() -)) -> Any: - """Add a problem to contest""" - problem = await db.problem.get(problem_id) - - if problem is None: - return get_error_schema("PROBLEM_NOT_FOUND") - - await db.contest.add_problem(contest_id, problem_id) - - return get_response() diff --git a/src/routers/groups.py b/src/routers/groups.py new file mode 100644 index 0000000..01800de --- /dev/null +++ b/src/routers/groups.py @@ -0,0 +1,4 @@ +from fastapi import APIRouter + + +router = APIRouter() diff --git a/src/routers/groups_router.py b/src/routers/groups_router.py deleted file mode 100644 index 99aab6e..0000000 --- a/src/routers/groups_router.py +++ /dev/null @@ -1,140 +0,0 @@ -"""Groups endpoints""" -from typing import Any -from fastapi import APIRouter, Depends -from auth.utils import auth_user -from auth.permissions import Permissions, ALL_PERMISSIONS_ROLE_CODE -from db.models.contest import Contest -from utils.response_utils import get_error_response, get_response, get_response_model, \ - get_error_schema -from db.models.group import Group, GroupToCreate, GroupRole, GroupMember -from db.models.user import User -import db -from db.models.annotations import IntIdAnnotation -from pydantic import BaseModel - -router = APIRouter() - -class ListContests(BaseModel): - contests: list[Contest] - -@router.post( - "/create", - response_model=get_response_model(Group), - responses={ - 400: get_error_schema("Failed to create group") - } -) -async def create_group(group_to_create: GroupToCreate, - _current_user: User = Depends(auth_user( - Permissions.CREATE_GROUP - ))) -> Any: - """Creating new group""" - - # check existing for all members - for member_id in group_to_create.members: - member = await db.user.get(member_id) - if member is None: - return get_error_response("MEMBER_NOT_FOUND", data={ - "target_member_id": member_id - }) - - if group_to_create.domain is not None: - status = await db.domain.reserve(group_to_create.domain) - if status is False: - return get_error_response("DOMAIN_IN_USE") - - try: - members: list[GroupMember] = [] - - # creating start group roles - starter_roles: list[GroupRole] = [ - GroupRole( - _id="admin", - name="Admin", - description="Admin", - role_code=ALL_PERMISSIONS_ROLE_CODE - ) - ] # TODO: create here basic member role - - # generating members with roles - for member_id in group_to_create.members: - members.append( - GroupMember( - _id=member_id, - permissions=0, # TODO: add here basic member role - roles=[] - ) - ) - - # result group - group = Group( - _id=1, # not used - owner=_current_user.id, - name=group_to_create.name, - description=group_to_create.description, - domain=group_to_create.domain, - members=members, - roles=starter_roles, - contests=[] - ) - - created_group_id = await db.group.insert_with_id(group) - - created_group = await db.group.get(created_group_id) - - if group.domain is not None: - await db.domain.attach(group.domain, "group", created_group_id) - - return get_response(created_group) - - except Exception as e: - if group_to_create.domain is not None: - await db.domain.delete(group_to_create.domain) # if error occurs delete reserved entity - raise e - - -@router.get( - "/get", - response_model=get_response_model(Group), - responses={ - 400: get_error_schema("Failed to retreive group") - } -) -async def get_group(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())) -> Any: - """Retreive group by id""" - - group = await db.group.get(_id) - - if group is None: - return get_error_response("GROUP_NOT_FOUND") - - return get_response(group) - - -@router.get( - "/get_contests", - response_model=get_response_model(ListContests), - responses={ - 400: get_error_schema("Failed to retreive contests") - } -) -async def get_contests( - group_id: IntIdAnnotation, - _current_user: User = Depends(auth_user()) -) -> Any: - """Retreive contests by group id""" - - group = await db.group.get(group_id) - - if group is None: - return get_error_response("GROUP_NOT_FOUND") - - result = ListContests(contests=[]) - - for contest_id in group.contests: - contest = await db.contest.get(contest_id) - if contest is None: - continue - result.contests.append(contest) - - return get_response(result) \ No newline at end of file diff --git a/src/routers/problems.py b/src/routers/problems.py new file mode 100644 index 0000000..e6f2f82 --- /dev/null +++ b/src/routers/problems.py @@ -0,0 +1,4 @@ +from fastapi import APIRouter + + +router = APIRouter() diff --git a/src/routers/problems_router.py b/src/routers/problems_router.py deleted file mode 100644 index 9e18b1a..0000000 --- a/src/routers/problems_router.py +++ /dev/null @@ -1,165 +0,0 @@ -import tempfile -from typing import Any - -from fastapi import APIRouter, Depends, UploadFile -from pydantic import BaseModel -from starlette.responses import FileResponse - -from auth.utils import auth_user -from utils.response_utils import get_error_response, get_response, get_response_model, \ - get_error_schema -from db.models.problem import Problem -from db.models.user import User -import db -from db.models.annotations import NameAnnotation, IntIdAnnotation -from config import Config - -import os - -router = APIRouter() - - -class Addproblem(BaseModel): - created_problem_id: IntIdAnnotation - - -@router.post( - "/create", - response_model=get_response_model(Addproblem) -) -async def create_problem(name: NameAnnotation, problem_archive: UploadFile, _current_user: User = Depends( - auth_user() -)) -> Any: - """Add a problem to contest by zip""" - - # TODO: add creating directory for problems - # with tempfile.NamedTemporaryFile() as file_object: - # with open(file_object.name, "wb") as file_object1: - # file_object1.write(await problem_archive.read()) - # with ZipFile(file_object1.name, "r") as zip_file: - # with zip_file.open("css/tokens.css", "r") as theme_file: - # print(str(theme_file.read())) - - # creating problem object - problem_to_create = Problem( - _id=1, # not used - name=name - ) - created_problem_id = await db.problem.insert_with_id(problem_to_create) - response = Addproblem(created_problem_id=created_problem_id) - return get_response(response) - - -@router.get( - "/get_legend" -) -async def get_problem_legend(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): - """Retreive problem legend""" - - try: - to_return = FileResponse(path=f'{Config.elan_path}/problems/problem{_id}/legend.mdx', filename="legend.mdx", - media_type='multipart/form-data') - print(to_return) - return to_return - except Exception as e: - print("Exception", e) - return get_error_response("FILE_NOT_FOUND") - - -@router.get( - "/get_input" -) -async def get_problem_input(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): - """Retreive problem legend""" - - try: - to_return = FileResponse(path=f'{Config.elan_path}/problems/problem{_id}/input.mdx', filename="input.mdx", - media_type='multipart/form-data') - return to_return - except Exception: - return get_error_response("FILE_NOT_FOUND") - - -@router.get( - "/get_output" -) -async def get_problem_output(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): - """Retreive problem legend""" - - try: - to_return = FileResponse(path=f'{Config.elan_path}/problems/problem{_id}/output.mdx', filename="output.mdx", - media_type='multipart/form-data') - return to_return - except Exception: - return get_error_response("FILE_NOT_FOUND") - - -@router.get( - "/get_scoring" -) -async def get_problem_scoring(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): - """Retreive problem legend""" - - try: - to_return = FileResponse(path=f'{Config.elan_path}/problems/problem{_id}/scoring.mdx', filename="scoring.mdx", - media_type='multipart/form-data') - return to_return - except Exception: - return get_error_response("FILE_NOT_FOUND") - - -@router.get( - "/get_notes" -) -async def get_notes(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())): - """Retreive problem legend""" - - try: - to_return = FileResponse(path=f'{Config.elan_path}/problems/problem{_id}/notes.mdx', filename="notes.mdx", - media_type='multipart/form-data') - return to_return - except Exception: - return get_error_response("FILE_NOT_FOUND") - - -@router.get( - "/get_name" -) -async def get_name(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())) -> Any: - """Retreive problem name by problem id""" - - problem = await db.problem.get(_id) - - if problem is None: - return get_error_response("PROBLEM_NOT_FOUND") - - return problem.name - - -class Examples(BaseModel): - - input: list[str] - output: list[str] - -@router.get( - "/get_examples", - response_model=get_response_model(Examples), - responses={ - 400: get_error_schema("Failed to retreive problem examples.") - } -) -async def get_examples(_id: IntIdAnnotation, _current_user: User = Depends(auth_user())) -> Any: - directory = f"{Config.elan_path}/problems/problem{_id}/" - - result = Examples(input=[], output=[]) - - for filename in os.scandir(directory): - if filename.is_file(): - if filename.name.startswith("example") and not filename.name.endswith(".a"): - with open(filename.path, "r") as file: - result.input.append(file.read()) - with open(filename.path+".a", "r") as file: - result.output.append(file.read()) - - return get_response(result) - diff --git a/src/routers/roles.py b/src/routers/roles.py new file mode 100644 index 0000000..01800de --- /dev/null +++ b/src/routers/roles.py @@ -0,0 +1,4 @@ +from fastapi import APIRouter + + +router = APIRouter() diff --git a/src/routers/roles_router.py b/src/routers/roles_router.py deleted file mode 100644 index e9c2b50..0000000 --- a/src/routers/roles_router.py +++ /dev/null @@ -1,43 +0,0 @@ -"""Roles endpoints""" -from loguru import logger -from fastapi import APIRouter, Depends -from db.models.user import User -from db.models.role import Role -from auth.utils import auth_user, Permissions -from utils.response_utils import get_error_schema, get_error_response, get_response, \ - get_response_model -import db - -router = APIRouter() - - -@router.post( - "/create", - response_model=get_response_model(Role), - responses={ - 400: get_error_schema("Failed to create role") - } -) -async def create(role: Role, - _current_user: User = Depends(auth_user( - Permissions.CREATE_ROLE - ))): - """ - Role creation - Args: - role: role to create - _current_user: current user which created the role - Returns: - Created role - """ - - if await db.role.get(role.id) is not None: - logger.info(f"Role with id <{role.id}> already exists") - return get_error_response("ROLE_ALREADY_EXISTS") - - await db.role.insert(Role( - **role.model_dump(by_alias=True) - )) - result_role = await db.role.get(role.id) - - return get_response(result_role) diff --git a/src/routers/service.py b/src/routers/service.py new file mode 100644 index 0000000..dfe638a --- /dev/null +++ b/src/routers/service.py @@ -0,0 +1,9 @@ +from fastapi import APIRouter + + +router = APIRouter() + + +@router.get("/ping") +async def ping(): + return "pong" diff --git a/src/routers/submissions.py b/src/routers/submissions.py new file mode 100644 index 0000000..e6f2f82 --- /dev/null +++ b/src/routers/submissions.py @@ -0,0 +1,4 @@ +from fastapi import APIRouter + + +router = APIRouter() diff --git a/src/routers/submissions_router.py b/src/routers/submissions_router.py deleted file mode 100644 index b84a84f..0000000 --- a/src/routers/submissions_router.py +++ /dev/null @@ -1,111 +0,0 @@ -import tempfile -from typing import Any - -from _pytest.main import Session -from fastapi import APIRouter, Depends, UploadFile -from pathlib import Path # FIXME КОСТЫЛЬ!!! - -from pydantic import BaseModel - -from auth.utils import auth_user -from db.models.annotations import IntIdAnnotation -from utils.response_utils import get_error_response, get_response, get_response_model, \ - get_error_schema -from db.models.problem import Problem -from db.models.submission import Submission, SubmissionToCreate -from db.models.user import User -import db -from config import Config -from loguru import logger -from datetime import datetime -from producer import produce_submission - -router = APIRouter() - - -@router.post( - "/create", - response_model=get_response_model() -) -async def create_submission( - to_create: SubmissionToCreate, - _current_user: User = Depends(auth_user()) -) -> Any: - """Creating submission and sent it to rabbitMQ""" - - contest = await db.contest.get(to_create.contest_id) - if contest is None: - return get_error_response("CONTEST_NOT_FOUND") - - if await db.problem.get(to_create.problem_id) is None: - return get_error_response("PROBLEM_NOT_FOUND") - - submission = Submission( - _id=1, # not used FIXME - contest_id=to_create.contest_id, - problem_id=to_create.problem_id, - user_id=_current_user.id, - status=None, - solution_path=None, - upload_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S") - ) - - created_submission_id = await db.submission.insert_with_id(submission) - - solution_directory = Config.elan_path + (f"/submissions" - f"/contest{contest.id}" - f"/submission{created_submission_id}") - - Path(solution_directory).mkdir(parents=True, exist_ok=True) - - solution_path = solution_directory + "/solution.cpp" # FIXME it only cpp making banana - - with open(solution_path, "w") as solution: - solution.write(to_create.solution) - - await db.submission.attach_solution_path(created_submission_id, solution_path) - - produce_submission(created_submission_id) - - return get_response(await db.submission.get(created_submission_id)) - - -class UserContestSubmissions(BaseModel): - result: list[Submission] - problem_names: list[str] # FIXME set name annotation - - -@router.get( - "/get_user_contest_submissions", - response_model=get_response_model(UserContestSubmissions), - responses={ - 400: get_error_schema("Failed to retreive submissions") - } -) -async def get_user_contest_submissions( - user_id: IntIdAnnotation, - contest_id: IntIdAnnotation, - _current_user: User = Depends(auth_user()) -) -> Any: - contest = await db.contest.get(contest_id) - - if contest is None: - return get_error_response("CONTEST_NOT_FOUND") - - user = db.user.get(user_id) - - if user is None: - return get_error_response("USER_NOT_FOUND") - - result = await db.submission.get_all_submission_for_user_in_contest(user_id, contest_id) - - problem_names: list[str] = [] # FIXME set name annotation - - for submission in result: - problem = await db.problem.get(submission.problem_id) - if problem is None: - problem_names.append("undefined") - else: - problem_names.append(problem.name) - - return get_response(UserContestSubmissions(result=result, problem_names=problem_names)) diff --git a/src/routers/users.py b/src/routers/users.py new file mode 100644 index 0000000..01800de --- /dev/null +++ b/src/routers/users.py @@ -0,0 +1,4 @@ +from fastapi import APIRouter + + +router = APIRouter() diff --git a/src/routers/users_router.py b/src/routers/users_router.py deleted file mode 100644 index ee86969..0000000 --- a/src/routers/users_router.py +++ /dev/null @@ -1,121 +0,0 @@ -"""Users endpoints""" -from typing import List, Any - -from fastapi import APIRouter, Depends -from starlette.responses import JSONResponse - -from db.models.user import User -import db -from utils.response_utils import get_error_response, get_response_model, get_error_schema, \ - get_response -from auth.utils import auth_user -from auth.utils import Permissions -from db.models.annotations import IntIdAnnotation - -router = APIRouter() - - -@router.post( - "/add_role", - response_model=get_response_model(), - responses={ - 400: get_error_schema("Failed to add role") - } -) -async def add_role(user_id: int, role_id: str, - _current_user: User = Depends(auth_user( - Permissions.CHANGE_USER_ROLES - ))): - """Add a role to the user""" - user_to_add = await db.user.get(user_id) - - if user_to_add is None: - return get_error_response("USER_NOT_FOUND") - - role_to_add = await db.role.get(role_id) - - if role_to_add is None: - return get_error_response("ROLE_NOT_FOUND") - - if role_id in user_to_add.roles: - return get_error_response("ROLE_ALREADY_EXISTS") - - await db.user.add_role(user_id, role_id) - - return get_response() - - -@router.post( - "/delete_role", - response_model=get_response_model(), - responses={ - 400: get_error_schema("Failed to delete role from user") - } -) -async def delete_role(user_id: int, role_id: str, - _current_user: User = Depends(auth_user( - Permissions.CHANGE_USER_ROLES - ))): - """Delete a role from the user""" - - user_to_delete = await db.user.get(user_id) - - if user_to_delete is None: - return get_error_response("USER_NOT_FOUND") - - role_to_delete = await db.role.get(role_id) - - if role_to_delete is None: - return get_error_response("ROLE_NOT_FOUND") - - if role_id not in user_to_delete.roles: - return get_error_response("ROLE_NOT_EXISTS") - - await db.user.delete_role(user_id, role_id) - - return get_response() - - -@router.get( - "/get_current", - response_model=get_response_model(User), - responses={ - 400: get_error_schema("Failed to retrieve current user") - } -) -async def get_current_user(_current_user: User = Depends(auth_user())): - """Get current user""" - return get_response(_current_user) - - -@router.get( - "/get_groups", - responses={ - 400: get_error_schema("Failed to retrieve groups") - } -) -async def get_groups( - _id: IntIdAnnotation, - _current_user: User = Depends(auth_user()) -) -> Any | IntIdAnnotation: - """Retrieve all groups thet has user""" - - user = await db.user.get(_id) - - if user is None: - return get_error_response("USER_NOT_FOUND") - - groups = await db.group.get_all() - - result = [] - - for group in groups: - if group.owner == _id: - result.append(group.id) - continue - for member in group.members: - if member.id == _id: - result.append(group.id) - break - - return get_response({"result": result}) diff --git a/src/utils/__init__.py b/src/utils/__init__.py deleted file mode 100644 index 1c8764c..0000000 --- a/src/utils/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Helpers for the project""" -from . import response_utils -from . import singleton - -__all__ = ["response_utils", "singleton"] diff --git a/src/utils/auth/__init__.py b/src/utils/auth/__init__.py new file mode 100644 index 0000000..18a9696 --- /dev/null +++ b/src/utils/auth/__init__.py @@ -0,0 +1,17 @@ +from .auth import ( + auth_user, + hash_password, + verify_password, + create_jwt, + create_jwt_pair_by_user_id +) +from . import permissions + +__all__ = [ + "auth_user", + "create_jwt", + "verify_password", + "hash_password", + "permissions", + "create_jwt_pair_by_user_id", +] diff --git a/src/utils/auth/auth.py b/src/utils/auth/auth.py new file mode 100644 index 0000000..c5b0bf1 --- /dev/null +++ b/src/utils/auth/auth.py @@ -0,0 +1,184 @@ +import datetime +from typing import Literal +import jose.jwt +from passlib.context import CryptContext +from fastapi import Header +from starlette import status as http_status + +from db import methods +from db.types.auth import JWTPair +from db.types.user import User +from db.types.common import IntegerId, RoleCode +from utils import response +from config import config +from .permissions import Permissions + + +password_context = CryptContext(schemes=["bcrypt"], deprecated="auto") + + +def get_auth_header_credentials( + header: str, + prefix: Literal["Bearer", "Service"] +) -> str: + credentials = header.split() + + error_message = f"Incorrect authorization header format. Format: {prefix} " + + if len(credentials) != 2: + raise response.ErrorResponse( + code=response.ErrorCodes.INCORRECT_AUTH_HEADER_FOMAT, + http_status_code=http_status.HTTP_422_UNPROCESSABLE_ENTITY, + message=error_message + ) + + current_prefix, token = credentials[0], credentials[1] + + if current_prefix != prefix: + raise response.ErrorResponse( + code=response.ErrorCodes.INCORRECT_AUTH_HEADER_FOMAT, + http_status_code=http_status.HTTP_422_UNPROCESSABLE_ENTITY, + message=error_message + ) + + return token + +def convert_role_code_to_permissions(role_code: RoleCode) -> list[int]: + permissions = [] + i = 0 + while 1 << i <= role_code: + if role_code >> i & 1 == 1: + permissions.append(i) + i += 1 + return permissions + +def convert_permissions_to_role_code(permissions: list[int]) -> RoleCode: + role_code = 0 + for permission in permissions: + role_code += 1 << permission + return role_code + +def hash_password(password: str) -> str: + return password_context.hash(password) + +def verify_password(password: str, hashed_password: str) -> bool: + return password_context.verify(password, hashed_password) + +def create_jwt( + subject: str, + expiration_time_minutes: int, + secret_key: str +) -> str: + expiration_time = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta( + minutes=expiration_time_minutes + ) + + data_to_encode = { + "exp": expiration_time, + "subject": subject + } + + jwt = jose.jwt.encode( + data_to_encode, + secret_key + ) + return jwt + +def decode_jwt( + jwt: str, + secret_key: str +) -> dict[Literal["subject"], str]: + """ + ### Raises: + - `ValueError`: If there is no subject field in decoded jwt + - `response.ErrorResponse`: *TOKEN_EXPIRED* + - `response.ErrorResponse`: *TOKEN_VALIDATION_FAILED* + """ + try: + payload = jose.jwt.decode( + jwt, + secret_key, + # ! algorithms=["HS256"] + ) + + subject = payload.get("subject", None) + if subject is None: + raise ValueError("There is no field in jwt") + + return { + "subject": subject + } + except jose.ExpiredSignatureError as exc: + raise response.ErrorResponse( + code=response.ErrorCodes.TOKEN_EXPIRED, + message="Token signature expired", + http_status_code=http_status.HTTP_401_UNAUTHORIZED, + ) from exc + except Exception as exc: + raise response.ErrorResponse( + code=response.ErrorCodes.TOKEN_VALIDATION_FAILED, + message="Token validation failed", + http_status_code=http_status.HTTP_401_UNAUTHORIZED, + ) from exc + +def create_jwt_pair_by_user_id(user_id: IntegerId) -> JWTPair: + return JWTPair( + access=create_jwt( + str(user_id), + expiration_time_minutes=config.auth.access_token_expire_minutes, + secret_key=config.auth.jwt_access_secret_key.get_secret_value() + ), + refresh=create_jwt( + str(user_id), + expiration_time_minutes=config.auth.refresh_token_expire_minutes, + secret_key=config.auth.jwt_refresh_secret_key.get_secret_value() + ) + ) + +def auth_user(*permissions: Permissions): + """ + Dependency, that authorize user with given permissions by **access** jwt token in + Authorization header. + + Usage example: + >>> def endpoint(user: User = Depends(auth_user(Permissions.CREATE_ROLE))) + Args: + permissions: Permissions, which must contain user roles + Returns: + Function that auth user by given permissions and auth header + """ + + def wrapper(authorization: str = Header()) -> User: + token = get_auth_header_credentials(authorization, "Bearer") + + subject = decode_jwt(token, config.auth.jwt_access_secret_key.get_secret_value())["subject"] + + if subject.isnumeric(): + user_id = int(subject) + + user = methods.users.get(user_id) + + if user is not None: + general_role_code = 0 + for role_name in user.roles: + role = methods.roles.get(role_name) + if role is None: + continue + general_role_code |= role.code + + user_permissions = convert_role_code_to_permissions(general_role_code) + + for permission in permissions: + if permission.value not in user_permissions: + raise response.ErrorResponse( + code=response.ErrorCodes.ACCESS_DENIED, + http_status_code=http_status.HTTP_403_FORBIDDEN + ) + return user + + raise response.ErrorResponse( + code=response.ErrorCodes.ENTITY_NOT_FOUND, + http_status_code=http_status.HTTP_401_UNAUTHORIZED, + message="Could not found user by token" + ) + return wrapper diff --git a/src/utils/auth/permissions.py b/src/utils/auth/permissions.py new file mode 100644 index 0000000..4b0cf30 --- /dev/null +++ b/src/utils/auth/permissions.py @@ -0,0 +1,11 @@ +"""Global Permissions""" +from enum import Enum + +ALL_PERMISSIONS_ROLE_CODE: int = 2 ** 63 - 1 + + +class Permissions(Enum): + CREATE_GROUP = 1 + CREATE_ROLE = 2 + CHANGE_USER_ROLES = 3 + DELETE_USER = 4 diff --git a/src/utils/handlers.py b/src/utils/handlers.py index 50a9f4f..40f5540 100644 --- a/src/utils/handlers.py +++ b/src/utils/handlers.py @@ -1,13 +1,75 @@ """This file contains some helper handler functions""" + from fastapi import Request -from auth.utils import AuthException -from utils.response_utils import get_error_response +from fastapi.responses import JSONResponse +from fastapi.exceptions import RequestValidationError +from loguru import logger +from . import response + + +async def request_validation_exception_handler( + _request: Request, + exc: Exception +) -> JSONResponse: + """Unprocessable entity exception handler for make response consistent""" + + if not isinstance(exc, RequestValidationError): + raise ValueError("Unexpected error: get wrong exception type") + + def detail_part_to_string(part: dict[str, str]): + return ( + f"Type: {part.get('type', 'none')}; " + f"Location: {', '.join(part.get('loc', 'none'))}; " + f"Message: {part.get('msg', 'none')}; " + f"Input: {part.get('input', 'none')}" + ) + + errors = "Unprocessable entity exception. Errors: " + \ + '; '.join([detail_part_to_string(error) for error in exc.errors()]) + return JSONResponse( + content={ + "ok": False, + "error": { + "code": response.ErrorCodes.UNPROCESSABLE_ENTITY.value, + "message": errors + } + }, + status_code=422 + ) + +async def error_response_handler( + _request: Request, + exc: Exception +) -> JSONResponse: + """Handle response with error code""" + + if not isinstance(exc, response.ErrorResponse): + raise ValueError("Unexpected error: get wrong exception type") -async def auth_exception_handler(_request: Request, exc: AuthException): - """Authentication exception handler for make response consistent""" - return get_error_response( - status=exc.status, - status_code=exc.status_code, - data=exc.response + content: dict = { + "ok": False, + "error": { + "code": exc.code.value, + } + } + + if exc.message is not None: + content["error"]["message"] = exc.message + elif exc.auto_message: + content["error"]["message"] = exc.code.name + + return JSONResponse( + content=content, + status_code=exc.http_status_code ) + +async def internal_exception_handler(_request: Request, exc: Exception): + logger.exception(exc) + return JSONResponse(status_code=500, content={ + "ok": False, + "error": { + "code": response.ErrorCodes.INTERNAL_SERVER_ERROR.value, + "message": "Internal Server Error" + } + }) diff --git a/src/utils/misc.py b/src/utils/misc.py new file mode 100644 index 0000000..9804b40 --- /dev/null +++ b/src/utils/misc.py @@ -0,0 +1,30 @@ +from loguru import logger + +import db +import utils.auth +from config import config + + +def create_super_user(): + admin_role = db.types.role.Role( + _id="admin", + name="Admin", + code=utils.auth.permissions.ALL_PERMISSIONS_ROLE_CODE, + description="The most powerful thing besides database access credentials))" + ) + if db.methods.roles.insert(admin_role): + logger.info("Created admin role") + + result = db.methods.users.insert_user_document_with_id({ + "email": config.super_user.email, + "hashed_password": utils.auth.hash_password(config.super_user.password.get_secret_value()), + "roles": ["admin"] + }) + if result is not None: + logger.info("Created a new super user") + + super_user = db.methods.users.get_by_email(config.super_user.email) + if super_user is None: + logger.warning("There is no super user in the system") + else: + logger.info(f"Current super user: id={super_user.id}, email={super_user.email}") diff --git a/src/utils/response.py b/src/utils/response.py new file mode 100644 index 0000000..efde699 --- /dev/null +++ b/src/utils/response.py @@ -0,0 +1,64 @@ +from enum import Enum +from typing import Any, Generic, Literal, TypeVar + +from pydantic import BaseModel, model_validator, model_serializer + + +class ErrorCodes(Enum): + """ + Enum of response error codes. + For description see documentation + TODO: set documentation url + """ + INTERNAL_SERVER_ERROR = 1 + UNPROCESSABLE_ENTITY = 2 + TOKEN_EXPIRED = 3 + TOKEN_VALIDATION_FAILED = 4 + ENTITY_NOT_FOUND = 5 + INCORRECT_AUTH_HEADER_FOMAT = 6 + ACCESS_DENIED = 7 + NAME_ALREADY_TAKEN = 8 + +class ErrorResponse(Exception): + """Response with custom error code""" + + code: ErrorCodes + message: str | None + http_status_code: int + auto_message: bool + """If main message is None, it makes message be error code representation""" + + def __init__( + self, + code: ErrorCodes, + message: str | None = None, + http_status_code: int = 400, + auto_message: bool = False + ): + self.code = code + self.message = message + self.http_status_code = http_status_code + self.auto_message = auto_message + + +T = TypeVar("T", bound=BaseModel | None) + +class SuccessfulResponse(BaseModel, Generic[T]): + @model_validator(mode="before") + @classmethod + def before_validation(cls, data) -> dict[str, Any]: + return {"proxy": data} + + @model_serializer + def serialize_model(self) -> dict[str, Any]: + if self.proxy is None: + return { + "ok": self.ok + } + return { + "ok": self.ok, + **self.proxy.model_dump() + } + + ok: Literal[True] = True + proxy: T diff --git a/src/utils/response_utils.py b/src/utils/response_utils.py deleted file mode 100644 index 892ce01..0000000 --- a/src/utils/response_utils.py +++ /dev/null @@ -1,93 +0,0 @@ -"""Some useful stuff""" - -from typing import Literal -from typing import Any, Type -from pydantic import BaseModel -from starlette.responses import JSONResponse - - -def get_error_schema(description: str): - """ - Args: - description: error description - - Returns: - special error schema in special format - """ - return {"description": description, - "content": { - "application/json": { - "example": { - "status": "some status", - "response": { - "first_data": "example first", - "second_data": "example second" - } - }, - } - }} - - -def get_error_response(status: str, data: dict[str, Any] | BaseModel | None = None, - status_code: int = 400) -> JSONResponse: - """ - Args: - status: error status - data: some useful data for error response. It may be a base model - status_code: return status code - - Returns: JSONResponse, with exit code and message in special format - """ - if data is None: - data = {} - - if isinstance(data, BaseModel): - data = data.model_dump(by_alias=True) - - response = JSONResponse( - status_code=status_code, - content={ - "status": status, - "response": data - } - ) - return response - - -def get_response_model(model: Type[BaseModel] | Type[dict[str, Any]] = - dict[str, Any]) -> Type[BaseModel]: - """ - Return a pydantic custom model for response model. - Use without argument to make response empty. - Args: - model: target template model - """ - name = model.__name__ - - response_model: Type[BaseModel] = type(f"ResponseModel{name}", (BaseModel,), { - "__annotations__": { - "status": Literal["OK"], - "response": model - } - }) - - return response_model - - -def get_response(model: BaseModel | dict[str, Any] | None = None) -> JSONResponse: - """ - Returns an object that should return API method - Args: - model: model that provides response form - Returns: - Object that should return API method - """ - if model is None: - model = {} - if isinstance(model, BaseModel): - model = model.model_dump(by_alias=True) - - return JSONResponse(status_code=200, content={ - "status": "OK", - "response": model - }) diff --git a/src/utils/schemas.py b/src/utils/schemas.py new file mode 100644 index 0000000..fda0bdb --- /dev/null +++ b/src/utils/schemas.py @@ -0,0 +1,7 @@ +from typing import Any +import pydantic + + +class BaseModel(pydantic.BaseModel): + def model_dump(self, by_alias=True, **kwargs) -> dict[str, Any]: + return super().model_dump(by_alias=by_alias, **kwargs) diff --git a/src/utils/singleton.py b/src/utils/singleton.py deleted file mode 100644 index 01ecb86..0000000 --- a/src/utils/singleton.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Definition singleton class""" - - -class Singleton: - """Base class for singletons""" - __instance = None - - def __new__(cls, *args, **kwargs): - if cls.__instance is None: - cls.__instance = super().__new__(cls, *args, **kwargs) - return cls.__instance diff --git a/testing/Dockerfile b/testing/Dockerfile deleted file mode 100644 index 23dae0e..0000000 --- a/testing/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM python:3.12.1-alpine3.19 - -COPY ../pyproject.toml ./pyproject.toml - -RUN pip3 install poetry -RUN poetry install - -COPY ./src ./src -COPY ./testing ./testing - -WORKDIR ./testing - -CMD ["poetry", "run", "pytest", "-vv"] diff --git a/testing/core_db_test.py b/testing/core_db_test.py deleted file mode 100644 index 4e07184..0000000 --- a/testing/core_db_test.py +++ /dev/null @@ -1,29 +0,0 @@ -"""File to test core database methods""" -import pytest -from config import Config -from db.mongo_manager import MongoManager -from database_fixtures import setup_and_teardown - - -@pytest.mark.asyncio -async def test_db_connection(): - """Checking connection to db""" - await MongoManager.get_db().get_collection(Config.Collections.users).insert_one( - {"test": "test"}) - - num_documents = await MongoManager.get_db().get_collection( - Config.Collections.users).count_documents( - {"test": "test"} - ) - - assert num_documents == 1 - - await MongoManager.get_db().get_collection(Config.Collections.users).insert_one( - {"test": "test"}) - - num_documents = await MongoManager.get_db().get_collection( - Config.Collections.users).count_documents( - {"test": "test"} - ) - - assert num_documents == 2 diff --git a/testing/database_fixtures.py b/testing/database_fixtures.py deleted file mode 100644 index 340dc91..0000000 --- a/testing/database_fixtures.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Main fixtures -""" -from loguru import logger -import pytest_asyncio -from motor.core import AgnosticDatabase - -from config import Config -from db.mongo_manager import MongoManager -import asyncio -import time - - -@pytest_asyncio.fixture(autouse=True) -async def setup_and_teardown(): - """Base fixture, that setting up database and start fastapi client""" - - # connection to database - # AbstractDatabaseManager.connect_to_database(url=Config.db_connect_url) - # Database.db = AbstractDatabaseManager.get_db() - MongoManager.connect(Config.db_connect_url, Config.db_name) - await MongoManager.get_client().drop_database(Config.db_name) - - yield - - # await asyncio.sleep(5) - MongoManager.disconnect() diff --git a/testing/database_test/group_test.py b/testing/database_test/group_test.py deleted file mode 100644 index 6cfd180..0000000 --- a/testing/database_test/group_test.py +++ /dev/null @@ -1,83 +0,0 @@ -"""File to test core database methods""" -import pytest -from config import Config -import pytest_asyncio -from testing.database_fixtures import setup_and_teardown -from db.helpers.abstract_database_manager import AbstractDatabaseManager -import db -from db.models.group import Group -from db.mongo_manager import MongoManager - - -@pytest.mark.asyncio -async def test_autoincrement_simple(): - """Testing autoincrement technology for group""" - - group_first = Group( - _id=1, # not used - name="first", - owner=1 - ) - - group_second = Group( - _id=1, # not used - name="second", - owner=1 - ) - - group_third = Group( - _id=1, # not used - name="third", - owner=1 - ) - - collection = MongoManager.get_db().get_collection(Config.Collections.groups) - - await db.group.insert_with_id(group_first) - - assert await collection.count_documents({"name": "first"}) == 1 - - temp_user = await collection.find_one({"name": "first"}) - - assert temp_user["_id"] == 1 - - await db.group.insert_with_id(group_second) - - assert await collection.count_documents({"name": "second"}) == 1 - - assert await collection.count_documents({}) == 2 - - temp_user = await collection.find_one({"name": "second"}) - - assert temp_user["_id"] == 2 - - # deleting first user - - await collection.delete_one({"name": "first"}) - - assert await collection.count_documents({"name": "first"}) == 0 - - await db.group.insert_with_id(group_third) - - assert await collection.count_documents({"name": "third"}) == 1 - - temp_user = await collection.find_one({"name": "third"}) - - assert temp_user["_id"] == 3 - - -@pytest.mark.asyncio -async def test_autoincrement_stress(): - collection = MongoManager.get_db().get_collection(Config.Collections.groups) - for i in range(100): - current_user = Group( - _id=1, # not used - name=str(i + 1), - owner=1 - ) - - await db.group.insert_with_id(current_user) - - temp_user = await collection.find_one({"name": str(i + 1)}) - - assert temp_user["_id"] == i + 1 diff --git a/testing/database_test/user_test.py b/testing/database_test/user_test.py deleted file mode 100644 index 46da822..0000000 --- a/testing/database_test/user_test.py +++ /dev/null @@ -1,98 +0,0 @@ -"""File to test core database methods""" -import pytest -from config import Config -import pytest_asyncio -from testing.database_fixtures import setup_and_teardown -from db.helpers.abstract_database_manager import AbstractDatabaseManager -from loguru import logger -import db as db -from db.models.user import User -from db.mongo_manager import MongoManager - - -@pytest.mark.asyncio -async def test_autoincrement_simple(): - """Testing autoincrement technology for user""" - - user_first = User( - _id=1, # not used - first_name="first", - last_name="user", - email="test@gmail.com", - password_hash="test_hash" - ) - - user_second = User( - _id=1, # not used - first_name="second", - last_name="user", - email="test@gmail.com", - password_hash="test_hash" - ) - - user_third = User( - _id=1, # not used - first_name="third", - last_name="user", - email="test@gmail.com", - password_hash="test_hash" - ) - - logger.info("Created all users") - - collection = MongoManager.get_db().get_collection(Config.Collections.users) - - await db.user.insert_with_id(user_first) - - assert await collection.count_documents({"first_name": "first"}) == 1 - logger.info("First user added to database") - - temp_user = await collection.find_one({"first_name": "first"}) - - assert temp_user["_id"] == 1 - logger.info("Firstly added user has id = 1") - - await db.user.insert_with_id(user_second) - - assert await collection.count_documents({"first_name": "second"}) == 1 - logger.info("Second user added to database") - - assert await collection.count_documents({}) == 2 - - temp_user = await collection.find_one({"first_name": "second"}) - - assert temp_user["_id"] == 2 - logger.info("Secondly added user has id = 2") - - # deleting first user - - await collection.delete_one({"first_name": "first"}) - - assert await collection.count_documents({"first_name": "first"}) == 0 - - await db.user.insert_with_id(user_third) - - assert await collection.count_documents({"first_name": "third"}) == 1 - - temp_user = await collection.find_one({"first_name": "third"}) - - assert temp_user["_id"] == 3 - - -@pytest.mark.asyncio -async def test_autoincrement_stress(): - collection = MongoManager.get_db().get_collection(Config.Collections.users) - - for i in range(100): - current_user = User( - _id=1, # not used - first_name=str(i + 1), - last_name="user", - email="test@gmail.com", - password_hash="test_hash" - ) - await db.user.insert_with_id(current_user) - - temp_user = await collection.find_one({"first_name": str(i + 1)}) - - assert temp_user["_id"] == i + 1 diff --git a/testing/pytest.ini b/testing/pytest.ini deleted file mode 100644 index 9d40ed8..0000000 --- a/testing/pytest.ini +++ /dev/null @@ -1,4 +0,0 @@ -[pytest] -;addopts = src/ - -pythonpath = . src \ No newline at end of file diff --git a/testing/testing.env b/testing/testing.env deleted file mode 100644 index c61f1e8..0000000 --- a/testing/testing.env +++ /dev/null @@ -1,22 +0,0 @@ -# database -DB_CONNECT_URL=mongodb://127.0.0.1:27017 -DB_NAME=ELANDBTESTING - -# auth -ACCESS_TOKEN_EXPIRE_MINUTES=30 -REFRESH_TOKEN_EXPIRE_MINUTES=10080 -ALGORITHM=HS256 -JWT_SECRET_KEY=jwt_secret_key123 -JWT_REFRESH_SECRET_KEY=jwt_refresh_secret_key123 - -# misc -APP_TITLE="Testing ELAN api" - -# collections -COLLECTION_USERS=Users -COLLECTION_ROLES=Roles -COLLECTION_GROUP_ROLES=GroupRoles -COLLECTION_GROUPS=Groups -COLLECTION_DOMAIN=Domains -COLLECTION_INTERNAL_COUNTERS=InternalCounters - diff --git a/testing/util_test.py b/testing/util_test.py deleted file mode 100644 index 571ed22..0000000 --- a/testing/util_test.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Testing micro util functions -""" -import pytest -from auth.utils import has_role_permissions, \ - gen_code_staff_by_permissions -from auth.utils import Permissions - - -@pytest.mark.parametrize("data", [ - (Permissions.CREATE_ROLE,), - (), - (Permissions.CHANGE_USER_ROLES, Permissions.CREATE_ROLE), -]) -def test_has_role_permission(data: tuple[Permissions]): - """ - Parametrize test, testing `has_role_permission` function - Args: - data: input data - """ - - role_code = gen_code_staff_by_permissions(*data) - - assert has_role_permissions(role_code, *data) - - if len(data) != 0: - data1 = list(data) - data1.pop(-1) - - role_code2 = gen_code_staff_by_permissions(*data1) - - assert not has_role_permissions(role_code2, *data) diff --git a/tests/.dockerignore b/tests/.dockerignore new file mode 100644 index 0000000..7cd53fd --- /dev/null +++ b/tests/.dockerignore @@ -0,0 +1 @@ +**/node_modules/ diff --git a/tests/Dockerfile b/tests/Dockerfile new file mode 100644 index 0000000..42a9df8 --- /dev/null +++ b/tests/Dockerfile @@ -0,0 +1,11 @@ +FROM node:19-alpine + +WORKDIR /app + +COPY package.json package-lock.json ./ + +RUN npm install + +COPY . ./ + +CMD npm run test diff --git a/tests/jest.config.js b/tests/jest.config.js new file mode 100644 index 0000000..a08ba25 --- /dev/null +++ b/tests/jest.config.js @@ -0,0 +1,4 @@ +export default { + preset: 'ts-jest', + testEnvironment: 'node', +}; diff --git a/tests/package-lock.json b/tests/package-lock.json new file mode 100644 index 0000000..17172df --- /dev/null +++ b/tests/package-lock.json @@ -0,0 +1,4720 @@ +{ + "name": "integration_tests", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "integration_tests", + "version": "1.0.0", + "dependencies": { + "extended-eventsource": "^1.4.9", + "pactum": "^3.6.9" + }, + "devDependencies": { + "@shelf/jest-mongodb": "^4.3.2", + "jest": "^29.7.0", + "ts-jest": "^29.1.3", + "typescript": "^5.4.5" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@arr/every": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@arr/every/-/every-1.0.1.tgz", + "integrity": "sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/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/@babel/highlight/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/@babel/parser": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.2" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", + "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", + "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==", + "license": "MIT" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", + "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@polka/url": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz", + "integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==", + "license": "MIT" + }, + "node_modules/@shelf/jest-mongodb": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@shelf/jest-mongodb/-/jest-mongodb-4.3.2.tgz", + "integrity": "sha512-LL7NBaT04sJspoOZXqw3HGLw0+XnZNlIV72x2ymzyuloqIKXwgUl8eL1XKDUh4Ud8dUBRMrOngCQBcHKjWnrHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4.3.4", + "mongodb-memory-server": "9.2.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "jest-environment-node": "28.x || 29.x", + "mongodb": "3.x.x || 4.x || 5.x || 6.x" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", + "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.13.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-mutex": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.4.1.tgz", + "integrity": "sha512-WfoBo4E/TbCX1G95XTjbWTE3X2XLG0m1Xbv2cwOtuPdyH9CZvnaA5nCt1ucjaKEgW2A5IF71hxrRhr83Je5xjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", + "dev": true, + "license": "Apache-2.0", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/bson": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", + "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001647", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001647.tgz", + "integrity": "sha512-n83xdNiyeNcHpzWY+1aFbqCK7LuLfBricc4+alSQL2Xb6OR3XpnQAmlDG+pQcdTfiHRuLcQ96VOfrPSGiNJYSg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/centra": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", + "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-override": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/deep-override/-/deep-override-1.0.2.tgz", + "integrity": "sha512-+bAuLuYqaVVUWPaq8rmU8NLTX85p4I5k5/cVdhBioEfH7k+5NlGdv4NoJVQcJRByqzzTWWzTpih+pU1wBTmMow==", + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", + "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/extended-eventsource": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/extended-eventsource/-/extended-eventsource-1.4.9.tgz", + "integrity": "sha512-x0SMAw57jEaiBKLQWTatVBZkT/PRuL5hdiEP6s8GKqeQOapBRwnohI6e8zGM0XStolQrQe+L6Wvin8G0UthRbw==", + "license": "MIT" + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "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/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-cache-dir/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data-lite": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/form-data-lite/-/form-data-lite-1.0.3.tgz", + "integrity": "sha512-P7xPqAiOPKzC9Q9aywAZJCQq4QOE5WokPb3HrcWRh7C57RKytueJzoORZAVgHBNvK/lL7E+FxjQjd4X/zbecEQ==", + "license": "ISC", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-lite": "^1.0.3" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "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==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-query": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json-query/-/json-query-2.2.2.tgz", + "integrity": "sha512-y+IcVZSdqNmS4fO8t1uZF6RMMs0xh3SrTjJr9bp1X3+v0Q13+7Cyv12dSmKwDswp/H427BVtpkLWhGxYu3ZWRA==", + "engines": { + "node": "*" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lightcookie": { + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/lightcookie/-/lightcookie-1.0.25.tgz", + "integrity": "sha512-SrY/+eBPaKAMnsn7mCsoOMZzoQyCyHHHZlFCu2fjo28XxSyCLjlooKiTxyrXTg8NPaHp1YzWi0lcGG1gDi6KHw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "SEE LICENSE IN LICENSE.md" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/matchit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/matchit/-/matchit-1.1.0.tgz", + "integrity": "sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==", + "license": "MIT", + "dependencies": { + "@arr/every": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-lite": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mime-lite/-/mime-lite-1.0.3.tgz", + "integrity": "sha512-V85l97zJSTG8FEvmdTlmNYb0UMrVBwvRjw7bWTf/aT6KjFwtz3iTz8D2tuFIp7lwiaO2C5ecnrEmSkkMRCrqVw==", + "license": "MIT" + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mongodb": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz", + "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, + "node_modules/mongodb-memory-server": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-9.2.0.tgz", + "integrity": "sha512-w/usKdYtby5EALERxmA0+et+D0brP0InH3a26shNDgGefXA61hgl6U0P3IfwqZlEGRZdkbZig3n57AHZgDiwvg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "mongodb-memory-server-core": "9.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.20.1" + } + }, + "node_modules/mongodb-memory-server-core": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-9.2.0.tgz", + "integrity": "sha512-9SWZEy+dGj5Fvm5RY/mtqHZKS64o4heDwReD4SsfR7+uNgtYo+JN41kPCcJeIH3aJf04j25i5Dia2s52KmsMPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-mutex": "^0.4.0", + "camelcase": "^6.3.0", + "debug": "^4.3.4", + "find-cache-dir": "^3.3.2", + "follow-redirects": "^1.15.6", + "https-proxy-agent": "^7.0.4", + "mongodb": "^5.9.1", + "new-find-package-json": "^2.0.0", + "semver": "^7.6.0", + "tar-stream": "^3.1.7", + "tslib": "^2.6.2", + "yauzl": "^3.1.3" + }, + "engines": { + "node": ">=14.20.1" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/bson": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", + "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14.20.1" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/mongodb": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz", + "integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bson": "^5.5.0", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=14.20.1" + }, + "optionalDependencies": { + "@mongodb-js/saslprep": "^1.1.0" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.0.0", + "kerberos": "^1.0.0 || ^2.0.0", + "mongodb-client-encryption": ">=2.3.0 <3", + "snappy": "^7.2.2" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + } + } + }, + "node_modules/mongodb-memory-server-core/node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/new-find-package-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/new-find-package-json/-/new-find-package-json-2.0.0.tgz", + "integrity": "sha512-lDcBsjBSMlj3LXH2v/FW3txlh2pYTjmbOXPYJD93HI5EwuLzI11tdHSIpUMmfq/IOsldj4Ps8M8flhm+pCK4Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openapi-fuzzer-core": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/openapi-fuzzer-core/-/openapi-fuzzer-core-1.0.6.tgz", + "integrity": "sha512-FJNJIfgUFuv4NmVGq9MYdoKra2GrkDy2uhIjE2YGlw30UA1glf4SXLMhI4UwdcJ8jisKdIxi7lXrfej8GvNW5w==", + "license": "ISC", + "dependencies": { + "klona": "^2.0.4" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pactum": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/pactum/-/pactum-3.7.1.tgz", + "integrity": "sha512-r+R1dMy2MfRCQpAHohMyICusiMz14t0E+bhnLDScl2x4lXJKQAvQUGV/WWKUUxN2DS0Jdm0PUj6KjblfcSk1GA==", + "license": "MIT", + "dependencies": { + "@exodus/schemasafe": "^1.3.0", + "deep-override": "^1.0.2", + "form-data-lite": "^1.0.3", + "json-query": "^2.2.2", + "klona": "^2.0.6", + "lightcookie": "^1.0.25", + "openapi-fuzzer-core": "^1.0.6", + "pactum-matchers": "^1.1.7", + "parse-graphql": "^1.0.0", + "phin": "^3.7.0", + "polka": "^0.5.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pactum-matchers": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/pactum-matchers/-/pactum-matchers-1.1.7.tgz", + "integrity": "sha512-RqwewcUje6vhcYQGbPfdSXkcp/Vtwn4WmmTWLSmqp0CGxBroCEqRg3JMIjkjQTZCd2VmG+tTcQw+n4P/iuqv3Q==", + "license": "MIT" + }, + "node_modules/parse-graphql": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-graphql/-/parse-graphql-1.0.0.tgz", + "integrity": "sha512-NjvQHHaiPCxPZrhm/kKnorxOv7r/eA+tE0VW5E8iJMH9wTqFA1V0YK/7nbpxVu3JdXUxyWTKMez9lsHUtAwa0w==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/phin": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", + "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", + "license": "MIT", + "dependencies": { + "centra": "^2.7.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/polka": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/polka/-/polka-0.5.2.tgz", + "integrity": "sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==", + "license": "MIT", + "dependencies": { + "@polka/url": "^0.5.0", + "trouter": "^2.0.1" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/streamx": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", + "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", + "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/trouter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/trouter/-/trouter-2.0.1.tgz", + "integrity": "sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==", + "license": "MIT", + "dependencies": { + "matchit": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ts-jest": { + "version": "29.2.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.4.tgz", + "integrity": "sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "0.x", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.1.3.tgz", + "integrity": "sha512-JCCdmlJJWv7L0q/KylOekyRaUrdEoUxWkWVcgorosTROCFWiS9p2NNPE9Yb91ak7b1N5SxAZEliWpspbZccivw==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/tests/package.json b/tests/package.json new file mode 100644 index 0000000..3d0599a --- /dev/null +++ b/tests/package.json @@ -0,0 +1,18 @@ +{ + "name": "tests", + "version": "1.0.0", + "type": "module", + "scripts": { + "test": "node --no-warnings --experimental-vm-modules ./node_modules/.bin/jest" + }, + "author": "", + "devDependencies": { + "@shelf/jest-mongodb": "^4.3.2", + "jest": "^29.7.0", + "ts-jest": "^29.1.3", + "typescript": "^5.4.5" + }, + "dependencies": { + "pactum": "^3.6.9" + } +} diff --git a/tests/src/auth.test.ts b/tests/src/auth.test.ts new file mode 100644 index 0000000..cdfc25a --- /dev/null +++ b/tests/src/auth.test.ts @@ -0,0 +1,116 @@ +import pactum from "pactum"; +import {describe, test, expect} from "@jest/globals"; +import { GlobalCounter } from "./helpers/scripts"; +import {ErrorCodes, SuperUser as SuperUserCredentials} from "./helpers/constants"; + +pactum.request.setBaseUrl("http://api_test:4242"); + + +describe("Basic auth", () => { + const first_email = GlobalCounter.getNextEmail(); + const second_email = GlobalCounter.getNextEmail(); + const third_domain = GlobalCounter.getNextString(); + const third_email = GlobalCounter.getNextEmail(); + test("Registration", async () => { + await pactum.spec() + .post("/api/auth/signup") + .withBody({ + email: first_email, + password: "1234" + }) + .expectJsonLike({ok: true}); + await pactum.spec() + .post("/api/auth/signup") + .withBody({ + email: second_email, + password: "1234" + }) + .expectJsonLike({ok: true}); + + await pactum.spec() + .post("/api/auth/signup") + .withBody({ + email: second_email, + password: "1234" + }) + .expectJsonLike({ + ok: false, + error: { + code: ErrorCodes.NAME_ALREADY_TAKEN + } + }); + + await pactum.spec() + .post("/api/auth/signup") + .withBody({ + email: third_email, + domain: third_domain, + password: "1234" + }) + .expectStatus(200) + + await pactum.spec() + .post("/api/auth/signup") + .withBody({ + email: GlobalCounter.getNextEmail(), + domain: third_domain, + password: "1234" + }) + .expectJsonLike({ + ok: false, + error: { + code: ErrorCodes.NAME_ALREADY_TAKEN + } + }); + }); + + test("Auth", async () => { + await pactum.spec() + .post("/api/auth/signin") + .withBody({ + email: first_email, + password: "1234" + }) + .expectJsonLike({ok: true}); + + await pactum.spec() + .post("/api/auth/signin") + .withBody({ + email: first_email, + password: "incorrect_password" + }) + .expectJsonLike({ + ok: false, + error: { + code: ErrorCodes.ACCESS_DENIED + } + }); + + const access_token = await pactum.spec() + .post("/api/auth/signin") + .withBody({ + domain: third_domain, + password: "1234" + }) + .expectJsonLike({ok: true}) + .returns((ctx) => { + return ctx.res.body.access + }); + + await pactum.spec() + .post("/api/auth/signin") + .withBody({ + domain: third_domain, + password: "incorrect_password" + }) + .expectJsonLike({ok: false}); + }); + + test("Super user", async () => { + const access_token = await pactum.spec() + .post("/api/auth/signin") + .withBody(SuperUserCredentials) + .expectJsonLike({ok: true}) + .returns(ctx => ctx.res.body.access); + }); +}); diff --git a/tests/src/helpers/constants.ts b/tests/src/helpers/constants.ts new file mode 100644 index 0000000..c235b7a --- /dev/null +++ b/tests/src/helpers/constants.ts @@ -0,0 +1,17 @@ +const ErrorCodes = { + INTERNAL_SERVER_ERROR: 1, + UNPROCESSABLE_ENTITY: 2, + TOKEN_EXPIRED: 3, + TOKEN_VALIDATION_FAILED: 4, + ENTITY_NOT_FOUND: 5, + INCORRECT_AUTH_HEADER_FOMAT: 6, + ACCESS_DENIED: 7, + NAME_ALREADY_TAKEN: 8 +} + +const SuperUser = { + email: "root@gmail.com", + password: "root" +} + +export {SuperUser, ErrorCodes}; diff --git a/tests/src/helpers/scripts.ts b/tests/src/helpers/scripts.ts new file mode 100644 index 0000000..1052036 --- /dev/null +++ b/tests/src/helpers/scripts.ts @@ -0,0 +1,15 @@ +export class GlobalCounter { + static counter: number = 0; + + static getNextNumber(): number { + return ++GlobalCounter.counter; + } + + static getNextEmail(): string { + return GlobalCounter.getNextNumber() + '.email@gmail.com'; + } + + static getNextString(): string { + return GlobalCounter.getNextNumber().toString(); + } +} diff --git a/tests/src/service.test.ts b/tests/src/service.test.ts new file mode 100644 index 0000000..8a73a1d --- /dev/null +++ b/tests/src/service.test.ts @@ -0,0 +1,13 @@ +import pactum from "pactum"; +import {describe, test, expect} from "@jest/globals"; + +pactum.request.setBaseUrl("http://api_test:4242"); + +describe("Test methods", () => { + test("Ping", async () => { + await pactum.spec() + .get("/api/service/ping") + .expectStatus(200) + .expectBody("pong") + }); +}); diff --git a/tests/tsconfig.json b/tests/tsconfig.json new file mode 100644 index 0000000..acd1d9a --- /dev/null +++ b/tests/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "outDir": "./dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules/"] +} From b11bf5711c098f836177dba0b33ac1c4f21fd63a Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 15:39:22 +0200 Subject: [PATCH 28/94] fix(CI): merge pyright and pylint --- .github/workflows/pylint.yaml | 38 ++++++++++++++++++++++++++++++---- .github/workflows/pyright.yaml | 37 --------------------------------- 2 files changed, 34 insertions(+), 41 deletions(-) delete mode 100644 .github/workflows/pyright.yaml diff --git a/.github/workflows/pylint.yaml b/.github/workflows/pylint.yaml index 4ad5acb..9f44eef 100644 --- a/.github/workflows/pylint.yaml +++ b/.github/workflows/pylint.yaml @@ -1,13 +1,13 @@ -name: Pylint python check +name: Python Linting on: push: branches: - - master # Замените "main" на вашу основную ветку + - master jobs: pylint: - name: Run Pylint + name: Pylint runs-on: ubuntu-latest steps: @@ -17,7 +17,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: 3.11 + python-version: 3.12 - name: Install dependencies run: pip3 install pylint @@ -34,3 +34,33 @@ jobs: echo "Pylint issues found!" exit 1 fi + pyright: + name: Pyright + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.12 + + - name: Install poetry + uses: abatilo/actions-poetry@v2 + + - name: Install dependencies + run: poetry install + + - name: Run Pyright + run: poetry run pyright > pyright_output.txt + continue-on-error: true + + - name: Check Pyright results + run: | + cat pyright_output.txt + if ! grep -q "0 errors, 0 warnings" pyright_output.txt; then + echo "Pyright issues found!" + exit 1 + fi diff --git a/.github/workflows/pyright.yaml b/.github/workflows/pyright.yaml deleted file mode 100644 index 2e51c53..0000000 --- a/.github/workflows/pyright.yaml +++ /dev/null @@ -1,37 +0,0 @@ -name: Pyright python check - -on: - push: - branches: - - master - -jobs: - pyright: - runs-on: ubuntu-latest - - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: 3.11 - - - name: Install poetry - uses: abatilo/actions-poetry@v2 - - - name: Install dependencies - run: poetry install - - - name: Run Pyright - run: poetry run pyright > pyright_output.txt - continue-on-error: true - - - name: Check Pyright results - run: | - cat pyright_output.txt - if ! grep -q "0 errors, 0 warnings" pyright_output.txt; then - echo "Pyright issues found!" - exit 1 - fi From 00a71fa000eaacf7d349016f329f6a5cac1d688a Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 15:40:18 +0200 Subject: [PATCH 29/94] refactor(CI): delete comment --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5e74fd8..34f8c29 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -3,7 +3,7 @@ name: Test API on: push: branches: - - master # Замените "main" на вашу основную ветку + - master jobs: test: From 1783812ecc418bb57707299e9a43d2aee4a3ba1b Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 15:42:44 +0200 Subject: [PATCH 30/94] refactor: remove unused line in gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 07948f0..78fc971 100644 --- a/.gitignore +++ b/.gitignore @@ -170,7 +170,6 @@ src_cache fastapi-async-mongodb .vscode -./data/* configs/main.json mongodb_data/ tests/node_modules/ From 0af53a6a47ffc085baf084b92e954b8e55b0eb24 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 15:59:22 +0200 Subject: [PATCH 31/94] fix: fix poetry --no-root --- Dockerfile | 3 ++- pyproject.toml | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 96ef285..840eced 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,10 +3,11 @@ FROM python:3.12.1-alpine3.19 ARG CONFIG_PATH COPY ./pyproject.toml ./pyproject.toml +COPY ./poetry.lock ./poetry.lock RUN pip3 install poetry -RUN poetry install --no-root +RUN poetry install COPY ./src ./src COPY $CONFIG_PATH /config.json diff --git a/pyproject.toml b/pyproject.toml index fbe2846..3e2520e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,7 @@ name = "elansbackend" version = "0.1.0" description = "" authors = ["Mark Fomin ", "Andrew Cherkashin "] +package-mode = false readme = "README.md" [tool.poetry.dependencies] @@ -27,9 +28,6 @@ build-backend = "poetry.core.masonry.api" disable="fixme,no-self-argument,missing-class-docstring,import-error,no-name-in-module,too-few-public-methods,missing-function-docstring,missing-module-docstring" enable="wildcard-import" -[tool.pylint."BASIC"] -docstring-min-length=-1 - [tool.pylint."MASTER"] init-hook='import sys; sys.path.append("./src/")' From 8060ac1d219cec53f7bb57da47ec839aaee4d73b Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 16:01:37 +0200 Subject: [PATCH 32/94] refactor: remove garbage credentials --- configs/test.json | 2 +- docker-compose.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/configs/test.json b/configs/test.json index be1166e..7cefbf8 100644 --- a/configs/test.json +++ b/configs/test.json @@ -1,6 +1,6 @@ { "database": { - "connect_url": "mongodb://bulo4ka:ZOVSVO@db_test", + "connect_url": "mongodb://admin:admin@db_test", "name": "ELANDB" }, "auth": { diff --git a/docker-compose.yml b/docker-compose.yml index 66fbce1..abd36b6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,8 +7,8 @@ services: volumes: - ./mongodb_data:/data/db environment: - - MONGO_INITDB_ROOT_USERNAME=bulo4ka - - MONGO_INITDB_ROOT_PASSWORD=ZOVSVO + - MONGO_INITDB_ROOT_USERNAME=admin + - MONGO_INITDB_ROOT_PASSWORD=admin networks: - main_network api: @@ -29,8 +29,8 @@ services: container_name: elan_db_test image: mongo environment: - - MONGO_INITDB_ROOT_USERNAME=bulo4ka - - MONGO_INITDB_ROOT_PASSWORD=ZOVSVO + - MONGO_INITDB_ROOT_USERNAME=admin + - MONGO_INITDB_ROOT_PASSWORD=admin networks: - test_network ports: From ba6379a47f00f1e4a116e2368d4ce202a33f2802 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 16:02:25 +0200 Subject: [PATCH 33/94] refactor: remove container names --- docker-compose.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index abd36b6..8f216d3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,6 @@ version: "3" services: db: - container_name: elan_db image: mongo volumes: - ./mongodb_data:/data/db @@ -12,7 +11,6 @@ services: networks: - main_network api: - container_name: elan_api build: context: ./ dockerfile: Dockerfile @@ -26,7 +24,6 @@ services: - main_network db_test: - container_name: elan_db_test image: mongo environment: - MONGO_INITDB_ROOT_USERNAME=admin @@ -36,7 +33,6 @@ services: ports: - "27017:27017" api_test: - container_name: elan_api_test build: context: ./ dockerfile: Dockerfile @@ -52,7 +48,6 @@ services: timeout: 10m retries: 3 test: - container_name: integration_test build: context: ./tests dockerfile: ./Dockerfile From 1be502ccbf470a6df2795262f06674dc0423ad1e Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 16:07:15 +0200 Subject: [PATCH 34/94] refactor: remove Dockerfile from build docker compose --- docker-compose.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8f216d3..8c93681 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,6 @@ services: api: build: context: ./ - dockerfile: Dockerfile args: - CONFIG_PATH=./configs/main.json ports: @@ -35,7 +34,6 @@ services: api_test: build: context: ./ - dockerfile: Dockerfile args: - CONFIG_PATH=./configs/test.json depends_on: @@ -50,7 +48,6 @@ services: test: build: context: ./tests - dockerfile: ./Dockerfile networks: - test_network depends_on: From 71ab6ed26c823fee2d5f35be51f9bfcef7ee014a Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 17:01:04 +0200 Subject: [PATCH 35/94] chore: change python version to 3.12 --- poetry.lock | 24 +++++++++++------------- pyproject.toml | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index ff9f758..453bab7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -173,20 +173,21 @@ all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" [[package]] name = "fastapi-cli" -version = "0.0.4" +version = "0.0.5" description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi_cli-0.0.4-py3-none-any.whl", hash = "sha256:a2552f3a7ae64058cdbb530be6fa6dbfc975dc165e4fa66d224c3d396e25e809"}, - {file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"}, + {file = "fastapi_cli-0.0.5-py3-none-any.whl", hash = "sha256:e94d847524648c748a5350673546bbf9bcaeb086b33c24f2e82e021436866a46"}, + {file = "fastapi_cli-0.0.5.tar.gz", hash = "sha256:d30e1239c6f46fcb95e606f02cdda59a1e2fa778a54b64686b3ff27f6211ff9f"}, ] [package.dependencies] typer = ">=0.12.3" +uvicorn = {version = ">=0.15.0", extras = ["standard"]} [package.extras] -standard = ["fastapi", "uvicorn[standard] (>=0.15.0)"] +standard = ["uvicorn[standard] (>=0.15.0)"] [[package]] name = "h11" @@ -673,10 +674,7 @@ files = [ [package.dependencies] astroid = ">=3.2.4,<=3.3.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = [ - {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, -] +dill = {version = ">=0.3.7", markers = "python_version >= \"3.12\""} isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" @@ -1087,13 +1085,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.30.4" +version = "0.30.5" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.30.4-py3-none-any.whl", hash = "sha256:06b00e3087e58c6865c284143c0c42f810b32ff4f265ab19d08c566f74a08728"}, - {file = "uvicorn-0.30.4.tar.gz", hash = "sha256:00db9a9e3711a5fa59866e2b02fac69d8dc70ce0814aaec9a66d1d9e5c832a30"}, + {file = "uvicorn-0.30.5-py3-none-any.whl", hash = "sha256:b2d86de274726e9878188fa07576c9ceeff90a839e2b6e25c917fe05f5a6c835"}, + {file = "uvicorn-0.30.5.tar.gz", hash = "sha256:ac6fdbd4425c5fd17a9fe39daf4d4d075da6fdc80f653e5894cdc2fd98752bee"}, ] [package.dependencies] @@ -1338,5 +1336,5 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "2.0" -python-versions = "^3.11" -content-hash = "149181c2f94608ce3cb67e7a1449384cdbec6999a34ebaf02790ee210a9468cb" +python-versions = "^3.12" +content-hash = "22076e8400b99aaf62dba1a7943923993f026cbe8bc78297400c309d6a447940" diff --git a/pyproject.toml b/pyproject.toml index 3e2520e..8df36bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ package-mode = false readme = "README.md" [tool.poetry.dependencies] -python = "^3.11" +python = "^3.12" fastapi = "^0.111.1" loguru = "^0.7.2" python-jose = "^3.3.0" From 7f1aca01a5847bb6096841e639a6e6d53bcf7d82 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 17:01:49 +0200 Subject: [PATCH 36/94] refactor: fix pylint config --- pyproject.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8df36bb..81197cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,11 +28,9 @@ build-backend = "poetry.core.masonry.api" disable="fixme,no-self-argument,missing-class-docstring,import-error,no-name-in-module,too-few-public-methods,missing-function-docstring,missing-module-docstring" enable="wildcard-import" -[tool.pylint."MASTER"] -init-hook='import sys; sys.path.append("./src/")' [tool.pylint."FORMAT"] -max-line-length=100 +max-line-length=120 indent-string=" " indent-after-paren=4 expected-line-ending-format="" From 8fed1aab09160736c7f8ce16d869e3c977d8d091 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 17:03:04 +0200 Subject: [PATCH 37/94] refactor: calculations instead of constants --- src/config/config_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/config_model.py b/src/config/config_model.py index e2f23b6..e5f15ad 100644 --- a/src/config/config_model.py +++ b/src/config/config_model.py @@ -19,7 +19,7 @@ class DatabaseConfig(BaseModel): class AuthConfig(BaseModel): access_token_expire_minutes: int = 10 - refresh_token_expire_minutes: int = 10080 + refresh_token_expire_minutes: int = 7 * 24 * 60 jwt_access_secret_key: SecretStr jwt_refresh_secret_key: SecretStr From 80928215bbce7c5c884496541ff1c44ba496574f Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 17:04:21 +0200 Subject: [PATCH 38/94] refactor: fix env variable name --- src/config/load_config.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/config/load_config.py b/src/config/load_config.py index f312140..0350280 100644 --- a/src/config/load_config.py +++ b/src/config/load_config.py @@ -5,13 +5,12 @@ from .config_model import Config -CONFIG_PATH_ENV_VARIABLE_NAME = "CONFIG_PATH" def load_config() -> Config: - config_path = os.getenv(CONFIG_PATH_ENV_VARIABLE_NAME) + config_path = os.getenv("CONFIG_PATH") if config_path is None: - logger.error("Environment variable {_CONFIG_PATH_ENV_VARIABLE_NAME} is not set") + logger.error("Environment variable CONFIG_PATH is not set") sys.exit(1) file_exists = False From 49af37944300d70fbfcb26f00fc693db4e0ca3e3 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 17:10:46 +0200 Subject: [PATCH 39/94] refactor: fix import style && remove comments --- src/db/__init__.py | 8 +------- src/db/client.py | 9 --------- src/db/methods/__init__.py | 8 +++++--- src/db/methods/collections/__init__.py | 16 +++++++++------- 4 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/db/__init__.py b/src/db/__init__.py index 9f285da..be86f3d 100644 --- a/src/db/__init__.py +++ b/src/db/__init__.py @@ -1,10 +1,4 @@ -""" -Module that allows work with database through implemented methods and models -also it provode project types -""" - -from . import types -from . import methods +from . import types, methods from .client import client, close_connection diff --git a/src/db/client.py b/src/db/client.py index 67a128d..b9d4011 100644 --- a/src/db/client.py +++ b/src/db/client.py @@ -7,7 +7,6 @@ from config import config -# connection to database logger.info("Connecting to database") client: MongoClient = MongoClient(config.database.connect_url.get_secret_value()) @@ -21,12 +20,4 @@ sys.exit(1) def close_connection(): - """Closing mongodb connection""" client.close() - - -__all__= [ - "db", - "client", - "close_connection" -] diff --git a/src/db/methods/__init__.py b/src/db/methods/__init__.py index 854a5e9..2b79c62 100644 --- a/src/db/methods/__init__.py +++ b/src/db/methods/__init__.py @@ -1,6 +1,8 @@ -from . import users -from . import roles -from . import domains +from . import ( + users, + roles, + domains +) __all__ = [ "users", diff --git a/src/db/methods/collections/__init__.py b/src/db/methods/collections/__init__.py index 9602801..1adddd5 100644 --- a/src/db/methods/collections/__init__.py +++ b/src/db/methods/collections/__init__.py @@ -1,12 +1,14 @@ """This module for working with collections""" -from . collections import users, \ - roles, \ - domains, \ - contests, \ - group_roles, \ - group_members, \ - internal_counters +from .collections import ( + users, + roles, + domains, + contests, + group_roles, + group_members, + internal_counters +) __all__ = [ From 9854317f66db41b2fd4190ea3052515cf88e5f0e Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 17:13:17 +0200 Subject: [PATCH 40/94] style: fix pyproject.toml --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 81197cf..a0dc809 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,6 @@ build-backend = "poetry.core.masonry.api" disable="fixme,no-self-argument,missing-class-docstring,import-error,no-name-in-module,too-few-public-methods,missing-function-docstring,missing-module-docstring" enable="wildcard-import" - [tool.pylint."FORMAT"] max-line-length=120 indent-string=" " From 8a206bafdda97862e48764e93c7fc8701d2aca1c Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 17:16:01 +0200 Subject: [PATCH 41/94] refactor: remove app_title and change default value to cors in config --- src/config/config_model.py | 3 +-- src/main.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/config/config_model.py b/src/config/config_model.py index e5f15ad..72260eb 100644 --- a/src/config/config_model.py +++ b/src/config/config_model.py @@ -32,6 +32,5 @@ class Config(BaseModel): super_user: SuperUser = SuperUser() auth: AuthConfig debug: bool = False - app_title: str = "ELAN MAIN API" show_config: bool = False - allow_origins: list[str] = ["*"] + allow_origins: list[str] = [] diff --git a/src/main.py b/src/main.py index 7107997..903c520 100644 --- a/src/main.py +++ b/src/main.py @@ -24,7 +24,7 @@ async def lifespan(_app: FastAPI): logger.info("Shutting down application") -app = FastAPI(title=config.app_title, debug=config.debug, lifespan=lifespan) +app = FastAPI(debug=config.debug, lifespan=lifespan) app.include_router(routers.users.router, prefix="/api/users") app.include_router(routers.auth.router, prefix="/api/auth") app.include_router(routers.roles.router, prefix="/api/roles") From a9f7d3fc4ede4856602d18a1d134d9a49d83759f Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 19:37:35 +0200 Subject: [PATCH 42/94] Merge branch 'master' into total-fix --- .github/ISSUE_TEMPLATE/bug_report.md | 40 ++++++++++++++++++++ .github/workflows/{pylint.yaml => lint.yaml} | 6 ++- README.md | 27 +++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md rename .github/workflows/{pylint.yaml => lint.yaml} (92%) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..8fc6e80 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,40 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug,needs-triage +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**Steps to reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Actual result (AR)** +A clear and concise description of what happened. + +**Expected result (ER)** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. Ubuntu 22.04] + - Python version [e.g. Python 3.11] + - Release version [e.g. v1.0] + +**Additional context** +Add any other context about the problem here. + +**Checkpoints** +- [ ] I am using the latest version of Elan backend. +- [ ] I am running on OS Linux with systemd (check your PID 1) +- [ ] I followed all the instructions in the README file diff --git a/.github/workflows/pylint.yaml b/.github/workflows/lint.yaml similarity index 92% rename from .github/workflows/pylint.yaml rename to .github/workflows/lint.yaml index 9f44eef..e4fb26f 100644 --- a/.github/workflows/pylint.yaml +++ b/.github/workflows/lint.yaml @@ -4,6 +4,8 @@ on: push: branches: - master + pull_request: + types: [opened, reopened] jobs: pylint: @@ -20,7 +22,9 @@ jobs: python-version: 3.12 - name: Install dependencies - run: pip3 install pylint + run: | + pip3 install poetry + poetry install - name: Run pylint run: | diff --git a/README.md b/README.md index 011ff55..694ad96 100644 --- a/README.md +++ b/README.md @@ -1 +1,28 @@ # Elan testing system backend +Elan is a modern platform and testing system for holding programming contests. It is like [ejudge](https://ejudge.ru/) or [Yandex Contest](https://contest.yandex.ru/), but a way better. + +This repository contains API code, please reffer to [another repo](https://github.com/elansteam/runner) for seeing the runner source code. + +## Why Elan? +- **Modern.** Elan has a very nice and intuitive UI based on Google Material Design 3 design system. +- **Powerful.** It supports holding IOI and ICPC contests formats, groups creation (could be useful in schools) and online VS Code-like code editor. +- **Self-hosted and open source.** You can deploy Elan on your own and enjoy all its advantages, storing all your data locally on your servers. Say "bye" to closed-source Codeforces & Yandex Contests :) + +## What does Elan consist of? +### Elan API (backend) +

+ + + + +

+Well-documented JSON API, written on FastAPI Python framework + +### Elan Runner +

+ + +

+Runner is a low-level engine, a subsystem of Elan, which is responsible for safely running isolated processes that are strictly limited in terms of resource consumption: memory, CPU and real-time, number of threads and file descriptors. Runner is based on the Linux kernel cgroups v2 mechanism. It imposes rlimits and ulimits and keeps track of all system calls of the running process. + +Runner is written from scratch on C++, and it has Python API. From 7d3f92e13f0d2a89fd0c02dc3e611621e8e50207 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 19:37:35 +0200 Subject: [PATCH 43/94] Merge branch 'master' into total-fix --- .github/ISSUE_TEMPLATE/bug_report.md | 40 ++++++++++++++++++++ .github/workflows/{pylint.yaml => lint.yaml} | 6 ++- README.md | 27 +++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md rename .github/workflows/{pylint.yaml => lint.yaml} (93%) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..8fc6e80 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,40 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug,needs-triage +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**Steps to reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Actual result (AR)** +A clear and concise description of what happened. + +**Expected result (ER)** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. Ubuntu 22.04] + - Python version [e.g. Python 3.11] + - Release version [e.g. v1.0] + +**Additional context** +Add any other context about the problem here. + +**Checkpoints** +- [ ] I am using the latest version of Elan backend. +- [ ] I am running on OS Linux with systemd (check your PID 1) +- [ ] I followed all the instructions in the README file diff --git a/.github/workflows/pylint.yaml b/.github/workflows/lint.yaml similarity index 93% rename from .github/workflows/pylint.yaml rename to .github/workflows/lint.yaml index 9f44eef..c2969ce 100644 --- a/.github/workflows/pylint.yaml +++ b/.github/workflows/lint.yaml @@ -4,6 +4,8 @@ on: push: branches: - master + pull_request: + types: [opened, reopened] jobs: pylint: @@ -20,8 +22,8 @@ jobs: python-version: 3.12 - name: Install dependencies - run: pip3 install pylint - + run: | + pip3 install pylint - name: Run pylint run: | pylint ${PWD}/src/** > pylint_output.txt diff --git a/README.md b/README.md index 011ff55..694ad96 100644 --- a/README.md +++ b/README.md @@ -1 +1,28 @@ # Elan testing system backend +Elan is a modern platform and testing system for holding programming contests. It is like [ejudge](https://ejudge.ru/) or [Yandex Contest](https://contest.yandex.ru/), but a way better. + +This repository contains API code, please reffer to [another repo](https://github.com/elansteam/runner) for seeing the runner source code. + +## Why Elan? +- **Modern.** Elan has a very nice and intuitive UI based on Google Material Design 3 design system. +- **Powerful.** It supports holding IOI and ICPC contests formats, groups creation (could be useful in schools) and online VS Code-like code editor. +- **Self-hosted and open source.** You can deploy Elan on your own and enjoy all its advantages, storing all your data locally on your servers. Say "bye" to closed-source Codeforces & Yandex Contests :) + +## What does Elan consist of? +### Elan API (backend) +

+ + + + +

+Well-documented JSON API, written on FastAPI Python framework + +### Elan Runner +

+ + +

+Runner is a low-level engine, a subsystem of Elan, which is responsible for safely running isolated processes that are strictly limited in terms of resource consumption: memory, CPU and real-time, number of threads and file descriptors. Runner is based on the Linux kernel cgroups v2 mechanism. It imposes rlimits and ulimits and keeps track of all system calls of the running process. + +Runner is written from scratch on C++, and it has Python API. From 39ba798519fb4c48fae572dadb3fdf6eb579f0a6 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 21:42:53 +0200 Subject: [PATCH 44/94] refactor: remove annotations from regular type hints --- src/db/methods/domains.py | 11 +++++------ src/db/methods/users.py | 7 +++---- src/utils/auth/auth.py | 7 +++---- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/db/methods/domains.py b/src/db/methods/domains.py index 93ad98d..37e4bfc 100644 --- a/src/db/methods/domains.py +++ b/src/db/methods/domains.py @@ -1,11 +1,10 @@ from pymongo.errors import DuplicateKeyError from db import types -from db.types.common import IntegerId, DomainName from .collections import domains -def reserve_entity(domain: DomainName) -> bool: +def reserve_entity(domain: str) -> bool: """Creates entity with type None for domain Returns: True if ok, else False (domain already used) @@ -19,8 +18,8 @@ def reserve_entity(domain: DomainName) -> bool: return True def attach_to_entity( - domain: DomainName, - target_id: IntegerId, + domain: str, + target_id: int, target_type: types.domain.TargetType ) -> None: domains.find_one_and_update( @@ -33,9 +32,9 @@ def attach_to_entity( ) def resolve_id( - domain: DomainName, + domain: str, target_type: types.domain.TargetType -) -> IntegerId | None: +) -> int | None: entity = domains.find_one({"_id": domain, "target_type": target_type}) if entity is None: diff --git a/src/db/methods/users.py b/src/db/methods/users.py index c9ed40e..a5fc5d5 100644 --- a/src/db/methods/users.py +++ b/src/db/methods/users.py @@ -1,13 +1,12 @@ from typing import Any from pymongo.errors import DuplicateKeyError -from db.types.common import IntegerId, Email from db.types.user import User from .collections import users from .helpers import insert_with_auto_increment_id -def get(user_id: IntegerId) -> User | None: +def get(user_id: int) -> User | None: user = users.find_one({ "_id": user_id }) @@ -15,7 +14,7 @@ def get(user_id: IntegerId) -> User | None: return None return User(**user) -def get_by_email(email: Email): +def get_by_email(email: str): user = users.find_one({ "email": email }) @@ -23,7 +22,7 @@ def get_by_email(email: Email): return None return User(**user) -def insert_user_document_with_id(user_document: dict[str, Any]) -> IntegerId | None: +def insert_user_document_with_id(user_document: dict[str, Any]) -> int | None: """ Returns: None if DuplicateKeyError. Else - inserted_user_id """ diff --git a/src/utils/auth/auth.py b/src/utils/auth/auth.py index c5b0bf1..1de70e0 100644 --- a/src/utils/auth/auth.py +++ b/src/utils/auth/auth.py @@ -8,7 +8,6 @@ from db import methods from db.types.auth import JWTPair from db.types.user import User -from db.types.common import IntegerId, RoleCode from utils import response from config import config from .permissions import Permissions @@ -43,7 +42,7 @@ def get_auth_header_credentials( return token -def convert_role_code_to_permissions(role_code: RoleCode) -> list[int]: +def convert_role_code_to_permissions(role_code: int) -> list[int]: permissions = [] i = 0 while 1 << i <= role_code: @@ -52,7 +51,7 @@ def convert_role_code_to_permissions(role_code: RoleCode) -> list[int]: i += 1 return permissions -def convert_permissions_to_role_code(permissions: list[int]) -> RoleCode: +def convert_permissions_to_role_code(permissions: list[int]) -> int: role_code = 0 for permission in permissions: role_code += 1 << permission @@ -121,7 +120,7 @@ def decode_jwt( http_status_code=http_status.HTTP_401_UNAUTHORIZED, ) from exc -def create_jwt_pair_by_user_id(user_id: IntegerId) -> JWTPair: +def create_jwt_pair_by_user_id(user_id: int) -> JWTPair: return JWTPair( access=create_jwt( str(user_id), From 49949b167ed1a56478e274350b6d53d59cc7d1d9 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 22:03:52 +0200 Subject: [PATCH 45/94] refactor(config): fix error logging --- configs/test.json | 3 +-- src/config/config_model.py | 1 - src/config/load_config.py | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/configs/test.json b/configs/test.json index 7cefbf8..c3ed931 100644 --- a/configs/test.json +++ b/configs/test.json @@ -6,6 +6,5 @@ "auth": { "jwt_access_secret_key": "jwt_access_secret_key", "jwt_refresh_secret_key": "jwt_refresh_secret_key" - }, - "show_config": true + } } diff --git a/src/config/config_model.py b/src/config/config_model.py index 72260eb..14f9f83 100644 --- a/src/config/config_model.py +++ b/src/config/config_model.py @@ -32,5 +32,4 @@ class Config(BaseModel): super_user: SuperUser = SuperUser() auth: AuthConfig debug: bool = False - show_config: bool = False allow_origins: list[str] = [] diff --git a/src/config/load_config.py b/src/config/load_config.py index 0350280..bdebf9b 100644 --- a/src/config/load_config.py +++ b/src/config/load_config.py @@ -30,6 +30,6 @@ def load_config() -> Config: return Config.model_validate_json(config_file.read()) except ValidationError as exception: logger.error( - f"Failed to load configuration from file {config_path}: {exception}" + f"Failed to load configuration with errors: {exception.errors()}" ) sys.exit(1) From 365e519cae18b0b1a8fe2619516773dcc7325002 Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 22:08:17 +0200 Subject: [PATCH 46/94] chore: added jobs pylint param --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a0dc809..34850ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,9 @@ pyright = "^1.1.374" requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" +[tool.pylint."MASTER"] +jobs=4 + [tool.pylint."MESSAGES CONTROL"] disable="fixme,no-self-argument,missing-class-docstring,import-error,no-name-in-module,too-few-public-methods,missing-function-docstring,missing-module-docstring" enable="wildcard-import" From 32562e0cec30d9f38e044987a18e33c2c2357a8d Mon Sep 17 00:00:00 2001 From: Spotika Date: Tue, 6 Aug 2024 22:18:31 +0200 Subject: [PATCH 47/94] refactor: remove uneccessary networks --- docker-compose.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8c93681..2e75766 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,8 +8,6 @@ services: environment: - MONGO_INITDB_ROOT_USERNAME=admin - MONGO_INITDB_ROOT_PASSWORD=admin - networks: - - main_network api: build: context: ./ @@ -19,16 +17,12 @@ services: - "4242:4242" depends_on: - db - networks: - - main_network db_test: image: mongo environment: - MONGO_INITDB_ROOT_USERNAME=admin - MONGO_INITDB_ROOT_PASSWORD=admin - networks: - - test_network ports: - "27017:27017" api_test: @@ -38,8 +32,6 @@ services: - CONFIG_PATH=./configs/test.json depends_on: - db_test - networks: - - test_network healthcheck: test: wget --no-verbose --tries=1 --spider http://api_test:4242/api/service/ping || exit 1 interval: 10s @@ -48,14 +40,7 @@ services: test: build: context: ./tests - networks: - - test_network depends_on: api_test: condition: service_healthy tty: true - - -networks: - main_network: - test_network: From a2279009ac463069055f4e4183f2b5fb7296d1d9 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 14:10:39 +0200 Subject: [PATCH 48/94] refactor: refactored commends and add some style --- src/db/client.py | 2 -- src/db/methods/domains.py | 2 +- src/db/methods/roles.py | 3 --- src/db/methods/users.py | 3 ++- src/db/types/__init__.py | 12 +++++++----- src/db/types/auth.py | 8 ++++---- src/db/types/common.py | 1 - src/db/types/submission.py | 1 + src/routers/__init__.py | 20 ++++++++++---------- src/routers/auth.py | 5 +++-- src/utils/handlers.py | 2 -- tests/src/service.test.ts | 13 ------------- 12 files changed, 28 insertions(+), 44 deletions(-) delete mode 100644 tests/src/service.test.ts diff --git a/src/db/client.py b/src/db/client.py index b9d4011..ff54460 100644 --- a/src/db/client.py +++ b/src/db/client.py @@ -1,5 +1,3 @@ -"""A module that creates a database connection and exports it""" - import sys from pymongo import MongoClient, database from pymongo.errors import ServerSelectionTimeoutError diff --git a/src/db/methods/domains.py b/src/db/methods/domains.py index 37e4bfc..e2e84ee 100644 --- a/src/db/methods/domains.py +++ b/src/db/methods/domains.py @@ -5,7 +5,7 @@ def reserve_entity(domain: str) -> bool: - """Creates entity with type None for domain + """ Returns: True if ok, else False (domain already used) """ diff --git a/src/db/methods/roles.py b/src/db/methods/roles.py index d380550..5fe81db 100644 --- a/src/db/methods/roles.py +++ b/src/db/methods/roles.py @@ -10,9 +10,6 @@ def get(role_name: str) -> Role | None: return Role(**role) def insert(role: Role) -> bool: - """ - Returns: False - if DuplicateKeyError, else - True - """ try: roles.insert_one(role.model_dump()) except DuplicateKeyError: diff --git a/src/db/methods/users.py b/src/db/methods/users.py index a5fc5d5..9b4c4b9 100644 --- a/src/db/methods/users.py +++ b/src/db/methods/users.py @@ -24,7 +24,8 @@ def get_by_email(email: str): def insert_user_document_with_id(user_document: dict[str, Any]) -> int | None: """ - Returns: None if DuplicateKeyError. Else - inserted_user_id + Returns: + Inserted user id or None, if error occurred """ try: return insert_with_auto_increment_id( diff --git a/src/db/types/__init__.py b/src/db/types/__init__.py index c2b534f..14f0087 100644 --- a/src/db/types/__init__.py +++ b/src/db/types/__init__.py @@ -1,8 +1,10 @@ -from . import auth -from . import user -from . import common -from . import domain -from . import role +from . import ( + auth, + user, + common, + domain, + role +) __all__ = [ "auth", diff --git a/src/db/types/auth.py b/src/db/types/auth.py index 19b2180..58c1612 100644 --- a/src/db/types/auth.py +++ b/src/db/types/auth.py @@ -16,8 +16,8 @@ class SignInInput(BaseModel): @model_validator(mode="after") def check_only_one_field(self): - assert (self.id is None) + \ - (self.domain is None) + \ - (self.email is None) == 2, \ - "You must provide exactly one of the fields: email, domain, user_id" + error_message = "You must provide exactly one of the fields: email, domain, user_id" + assert ((self.id is None) + + (self.domain is None) + + (self.email is None) == 2), error_message return self diff --git a/src/db/types/common.py b/src/db/types/common.py index 64add75..a8d44f7 100644 --- a/src/db/types/common.py +++ b/src/db/types/common.py @@ -1,4 +1,3 @@ -"""Common project types""" import re from typing import Annotated from pydantic import AfterValidator diff --git a/src/db/types/submission.py b/src/db/types/submission.py index ce7ac31..df491df 100644 --- a/src/db/types/submission.py +++ b/src/db/types/submission.py @@ -8,6 +8,7 @@ class Submission(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-475""" + id: IntegerId = Field(alias="_id") problem_id: IntegerId contest_id: IntegerId diff --git a/src/routers/__init__.py b/src/routers/__init__.py index 292670b..58f6441 100644 --- a/src/routers/__init__.py +++ b/src/routers/__init__.py @@ -1,13 +1,13 @@ -"""Module to manage routers""" - -from . import auth -from . import users -from . import roles -from . import groups -from . import service -from . import problems -from . import contests -from . import submissions +from . import ( + auth, + users, + roles, + groups, + service, + problems, + contests, + submissions +) __all__ = [ diff --git a/src/routers/auth.py b/src/routers/auth.py index 878e0d2..0387e15 100644 --- a/src/routers/auth.py +++ b/src/routers/auth.py @@ -1,4 +1,5 @@ from fastapi import APIRouter +from starlette import status as http_status import utils.auth from utils.response import SuccessfulResponse, ErrorCodes, ErrorResponse @@ -60,14 +61,14 @@ async def signin( if user is None: raise ErrorResponse( code=ErrorCodes.ENTITY_NOT_FOUND, - http_status_code=404, + http_status_code=http_status.HTTP_404_NOT_FOUND, message="User not found" ) if not utils.auth.verify_password(siginin_input.password, user.hashed_password): raise ErrorResponse( code=ErrorCodes.ACCESS_DENIED, - http_status_code=403, + http_status_code=http_status.HTTP_403_FORBIDDEN, message="Incorrect password" ) diff --git a/src/utils/handlers.py b/src/utils/handlers.py index 40f5540..7596549 100644 --- a/src/utils/handlers.py +++ b/src/utils/handlers.py @@ -42,8 +42,6 @@ async def error_response_handler( _request: Request, exc: Exception ) -> JSONResponse: - """Handle response with error code""" - if not isinstance(exc, response.ErrorResponse): raise ValueError("Unexpected error: get wrong exception type") diff --git a/tests/src/service.test.ts b/tests/src/service.test.ts deleted file mode 100644 index 8a73a1d..0000000 --- a/tests/src/service.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import pactum from "pactum"; -import {describe, test, expect} from "@jest/globals"; - -pactum.request.setBaseUrl("http://api_test:4242"); - -describe("Test methods", () => { - test("Ping", async () => { - await pactum.spec() - .get("/api/service/ping") - .expectStatus(200) - .expectBody("pong") - }); -}); From fc39456c4d5cfd5967d7da98dadd24d17f776c83 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 14:13:34 +0200 Subject: [PATCH 49/94] refactor: fix comments --- src/db/types/common.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/db/types/common.py b/src/db/types/common.py index a8d44f7..3ed9992 100644 --- a/src/db/types/common.py +++ b/src/db/types/common.py @@ -11,13 +11,6 @@ def _is_email(email: str) -> str: Email = Annotated[str, AfterValidator(_is_email)] def _is_positive_number(number: int) -> int: - """Check if given integer is positive - Args: - number: number to check - Returns: - number - """ - assert number > 0, f"Number {number} must be a positive number" return number IntegerId = Annotated[int, AfterValidator(_is_positive_number)] From d44a931cd19659cb0804b5f00766f271e3a99544 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 15:30:33 +0200 Subject: [PATCH 50/94] ci: change pull request rules --- .github/workflows/lint.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index c2969ce..3df5af2 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -5,7 +5,9 @@ on: branches: - master pull_request: - types: [opened, reopened] + branches: + - "*" + # types: [opened, reopened] jobs: pylint: From 7fece149cb4c5ab64c669fd628a5ad2a17f38ae6 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 15:40:17 +0200 Subject: [PATCH 51/94] chore: add __init__.py --- src/utils/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/utils/__init__.py diff --git a/src/utils/__init__.py b/src/utils/__init__.py new file mode 100644 index 0000000..e69de29 From b428760d2d8b0ce43ded969fdd03c37dbbb8ddd0 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 16:35:19 +0200 Subject: [PATCH 52/94] refactor: methods --- .github/workflows/lint.yaml | 1 - src/db/methods/domains.py | 14 ++++++-------- src/db/methods/users.py | 10 ++-------- src/routers/auth.py | 4 ++-- 4 files changed, 10 insertions(+), 19 deletions(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 3df5af2..423424a 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -7,7 +7,6 @@ on: pull_request: branches: - "*" - # types: [opened, reopened] jobs: pylint: diff --git a/src/db/methods/domains.py b/src/db/methods/domains.py index e2e84ee..f7b8a56 100644 --- a/src/db/methods/domains.py +++ b/src/db/methods/domains.py @@ -32,11 +32,9 @@ def attach_to_entity( ) def resolve_id( - domain: str, - target_type: types.domain.TargetType -) -> int | None: - entity = domains.find_one({"_id": domain, "target_type": target_type}) - - if entity is None: - return None - return types.domain.Entity(**entity).target_id + domain: str +) -> tuple[int | None, types.domain.TargetType | None]: + if (entity := domains.find_one({"_id": domain})) is None: + return None, None + entity = types.domain.Entity(**entity) + return entity.target_id, entity.target_type diff --git a/src/db/methods/users.py b/src/db/methods/users.py index 9b4c4b9..9ac05c6 100644 --- a/src/db/methods/users.py +++ b/src/db/methods/users.py @@ -7,18 +7,12 @@ def get(user_id: int) -> User | None: - user = users.find_one({ - "_id": user_id - }) - if user is None: + if (user := users.find_one({"_id": user_id})) is None: return None return User(**user) def get_by_email(email: str): - user = users.find_one({ - "email": email - }) - if user is None: + if (user := users.find_one({"email": email})) is None: return None return User(**user) diff --git a/src/routers/auth.py b/src/routers/auth.py index 0387e15..2d249e9 100644 --- a/src/routers/auth.py +++ b/src/routers/auth.py @@ -52,8 +52,8 @@ async def signin( if siginin_input.id: user = methods.users.get(siginin_input.id) elif siginin_input.domain: - user_id = methods.domains.resolve_id(siginin_input.domain, "user") - if user_id: + user_id, target_type = methods.domains.resolve_id(siginin_input.domain) + if user_id and target_type == "user": user = methods.users.get(user_id) elif siginin_input.email: user = methods.users.get_by_email(siginin_input.email) From ab4a822c475c31cb185b6a2d0fcf7734452f16f1 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 16:45:55 +0200 Subject: [PATCH 53/94] refactor: sum instead of + --- .github/workflows/test.yaml | 3 ++- src/db/types/auth.py | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index d4e4285..cdb07da 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -5,7 +5,8 @@ on: branches: - master pull_request: - types: [opened, reopened] + branches: + - "*" jobs: test: diff --git a/src/db/types/auth.py b/src/db/types/auth.py index 58c1612..444551e 100644 --- a/src/db/types/auth.py +++ b/src/db/types/auth.py @@ -17,7 +17,9 @@ class SignInInput(BaseModel): @model_validator(mode="after") def check_only_one_field(self): error_message = "You must provide exactly one of the fields: email, domain, user_id" - assert ((self.id is None) + - (self.domain is None) + - (self.email is None) == 2), error_message + assert sum([x is not None for x in ( + self.id, + self.domain, + self.email + )]) == 1 return self From ab7cd34765d5b08b77e8f209fd384854e9964059 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 17:09:56 +0200 Subject: [PATCH 54/94] replace + by sum --- src/db/types/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/types/auth.py b/src/db/types/auth.py index 444551e..775a795 100644 --- a/src/db/types/auth.py +++ b/src/db/types/auth.py @@ -21,5 +21,5 @@ def check_only_one_field(self): self.id, self.domain, self.email - )]) == 1 + )]) == 1, error_message return self From 2582836a74e42a41c1778aead0b1eb38fe8ab38c Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 21:05:51 +0200 Subject: [PATCH 55/94] feat: remove domain field from signup --- src/db/methods/domains.py | 15 --------------- src/db/methods/users.py | 13 ++++++++++--- src/db/types/domain.py | 4 ++-- src/db/types/user.py | 1 - src/routers/auth.py | 25 +++++-------------------- src/utils/misc.py | 10 +++++----- tests/src/auth.test.ts | 34 ---------------------------------- 7 files changed, 22 insertions(+), 80 deletions(-) diff --git a/src/db/methods/domains.py b/src/db/methods/domains.py index f7b8a56..d26ea14 100644 --- a/src/db/methods/domains.py +++ b/src/db/methods/domains.py @@ -1,22 +1,7 @@ -from pymongo.errors import DuplicateKeyError - from db import types from .collections import domains -def reserve_entity(domain: str) -> bool: - """ - Returns: - True if ok, else False (domain already used) - """ - try: - domains.insert_one({ - "_id": domain, - }) - except DuplicateKeyError: - return False - return True - def attach_to_entity( domain: str, target_id: int, diff --git a/src/db/methods/users.py b/src/db/methods/users.py index 9ac05c6..d8c0382 100644 --- a/src/db/methods/users.py +++ b/src/db/methods/users.py @@ -1,4 +1,3 @@ -from typing import Any from pymongo.errors import DuplicateKeyError from db.types.user import User @@ -16,7 +15,11 @@ def get_by_email(email: str): return None return User(**user) -def insert_user_document_with_id(user_document: dict[str, Any]) -> int | None: +def insert_user_with_id( + email: str, + hashed_password: str, + roles: list[str] | None = None +) -> int | None: """ Returns: Inserted user id or None, if error occurred @@ -24,7 +27,11 @@ def insert_user_document_with_id(user_document: dict[str, Any]) -> int | None: try: return insert_with_auto_increment_id( users, - user_document + { + "email": email, + "hashed_password": hashed_password, + "roles": roles or [] + } ) except DuplicateKeyError: return None diff --git a/src/db/types/domain.py b/src/db/types/domain.py index 1f28c59..4ad38f3 100644 --- a/src/db/types/domain.py +++ b/src/db/types/domain.py @@ -10,5 +10,5 @@ class Entity(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-395""" id: DomainName = Field(alias='_id') - target_type: TargetType | None = None - target_id: IntegerId | None = None + target_type: TargetType + target_id: IntegerId diff --git a/src/db/types/user.py b/src/db/types/user.py index 1e1ea27..1cb48a1 100644 --- a/src/db/types/user.py +++ b/src/db/types/user.py @@ -18,6 +18,5 @@ class User(BaseModel): class UserSignup(BaseModel): - domain: DomainName | None = Field(None) email: Email password: str diff --git a/src/routers/auth.py b/src/routers/auth.py index 2d249e9..e6b981e 100644 --- a/src/routers/auth.py +++ b/src/routers/auth.py @@ -14,20 +14,12 @@ async def signup( user_signup: types.user.UserSignup ): - if user_signup.domain is not None: - if not methods.domains.reserve_entity(user_signup.domain): - raise ErrorResponse( - code=ErrorCodes.NAME_ALREADY_TAKEN, - message="Domain already taken" - ) + hashed_password = utils.auth.hash_password(user_signup.password) - password_hash = utils.auth.hash_password(user_signup.password) - - inserted_user_id = methods.users.insert_user_document_with_id({ - "email": user_signup.email, - "domain": user_signup.domain, - "hashed_password": password_hash - }) + inserted_user_id = methods.users.insert_user_with_id( + user_signup.email, + hashed_password + ) if inserted_user_id is None: raise ErrorResponse( @@ -35,13 +27,6 @@ async def signup( message="There is user with identical email" ) - if user_signup.domain is not None: - methods.domains.attach_to_entity( - user_signup.domain, - inserted_user_id, - "user" - ) - return utils.auth.create_jwt_pair_by_user_id(inserted_user_id) @router.post("/signin", response_model=SuccessfulResponse[types.auth.JWTPair]) diff --git a/src/utils/misc.py b/src/utils/misc.py index 9804b40..d9b54ec 100644 --- a/src/utils/misc.py +++ b/src/utils/misc.py @@ -15,11 +15,11 @@ def create_super_user(): if db.methods.roles.insert(admin_role): logger.info("Created admin role") - result = db.methods.users.insert_user_document_with_id({ - "email": config.super_user.email, - "hashed_password": utils.auth.hash_password(config.super_user.password.get_secret_value()), - "roles": ["admin"] - }) + result = db.methods.users.insert_user_with_id( + config.super_user.email, + utils.auth.hash_password(config.super_user.password.get_secret_value()), + roles=["admin"] + ) if result is not None: logger.info("Created a new super user") diff --git a/tests/src/auth.test.ts b/tests/src/auth.test.ts index cdfc25a..d8972b7 100644 --- a/tests/src/auth.test.ts +++ b/tests/src/auth.test.ts @@ -44,24 +44,9 @@ describe("Basic auth", () => { .post("/api/auth/signup") .withBody({ email: third_email, - domain: third_domain, password: "1234" }) .expectStatus(200) - - await pactum.spec() - .post("/api/auth/signup") - .withBody({ - email: GlobalCounter.getNextEmail(), - domain: third_domain, - password: "1234" - }) - .expectJsonLike({ - ok: false, - error: { - code: ErrorCodes.NAME_ALREADY_TAKEN - } - }); }); test("Auth", async () => { @@ -85,25 +70,6 @@ describe("Basic auth", () => { code: ErrorCodes.ACCESS_DENIED } }); - - const access_token = await pactum.spec() - .post("/api/auth/signin") - .withBody({ - domain: third_domain, - password: "1234" - }) - .expectJsonLike({ok: true}) - .returns((ctx) => { - return ctx.res.body.access - }); - - await pactum.spec() - .post("/api/auth/signin") - .withBody({ - domain: third_domain, - password: "incorrect_password" - }) - .expectJsonLike({ok: false}); }); test("Super user", async () => { From eaf5b4394586cf12a3c52f9105e3099468d572cf Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 21:21:25 +0200 Subject: [PATCH 56/94] fix: fix pylint generator error --- src/db/types/auth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/types/auth.py b/src/db/types/auth.py index 775a795..4e2df66 100644 --- a/src/db/types/auth.py +++ b/src/db/types/auth.py @@ -17,9 +17,9 @@ class SignInInput(BaseModel): @model_validator(mode="after") def check_only_one_field(self): error_message = "You must provide exactly one of the fields: email, domain, user_id" - assert sum([x is not None for x in ( + assert sum(x is not None for x in ( self.id, self.domain, self.email - )]) == 1, error_message + )) == 1, error_message return self From 0ff165b38dfaf0cf60a06482517c34f7e2a6cda4 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 22:03:59 +0200 Subject: [PATCH 57/94] ci: try to fix docker compose --- .github/workflows/test.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index cdb07da..f3b9b70 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -17,13 +17,10 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Set up Docker Compose - run: sudo apt install docker-compose - - name: Build and run Docker Compose run: | - sudo docker-compose up --build -d test - sudo docker-compose logs -f test > test_logs.txt + sudo docker compose up --build -d test + sudo docker compose logs -f test > test_logs.txt continue-on-error: true - name: Check test results From 2e9b42a9c1babf06dc964bc3c04b1d2aa474914c Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 22:06:36 +0200 Subject: [PATCH 58/94] ci: fix docker compose --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f3b9b70..e0dc852 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -33,4 +33,4 @@ jobs: fi - name: Show test logs - run: docker-compose logs --no-log-prefix test + run: docker compose logs --no-log-prefix test From d297c9f134948e5f7b90614f5ddff3561fb82502 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 22:29:53 +0200 Subject: [PATCH 59/94] build: change volumes destination --- .dockerignore | 1 - .gitignore | 10 ---------- docker-compose.yml | 2 +- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/.dockerignore b/.dockerignore index b8499fb..b8721e7 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1 @@ -mongodb_data/ tests/node_modules/ diff --git a/.gitignore b/.gitignore index 78fc971..92b4428 100644 --- a/.gitignore +++ b/.gitignore @@ -160,16 +160,6 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ -./src_cache -./data_cache -./future - -future -data_cache -src_cache -fastapi-async-mongodb - .vscode configs/main.json -mongodb_data/ tests/node_modules/ diff --git a/docker-compose.yml b/docker-compose.yml index 2e75766..9538ec6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: db: image: mongo volumes: - - ./mongodb_data:/data/db + - /var/lib/elan/mongodb_data:/data/db environment: - MONGO_INITDB_ROOT_USERNAME=admin - MONGO_INITDB_ROOT_PASSWORD=admin From 6f66f719f25a768076329e7aaf024251e66450a2 Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 23:09:54 +0200 Subject: [PATCH 60/94] refactor: remove superuser --- src/config/config_model.py | 5 ----- src/main.py | 4 +--- src/utils/misc.py | 30 ------------------------------ tests/src/auth.test.ts | 8 -------- 4 files changed, 1 insertion(+), 46 deletions(-) delete mode 100644 src/utils/misc.py diff --git a/src/config/config_model.py b/src/config/config_model.py index 14f9f83..e81b8c3 100644 --- a/src/config/config_model.py +++ b/src/config/config_model.py @@ -23,13 +23,8 @@ class AuthConfig(BaseModel): jwt_access_secret_key: SecretStr jwt_refresh_secret_key: SecretStr -class SuperUser(BaseModel): - email: Email = "root@gmail.com" - password: SecretStr = SecretStr("root") - class Config(BaseModel): database: DatabaseConfig - super_user: SuperUser = SuperUser() auth: AuthConfig debug: bool = False allow_origins: list[str] = [] diff --git a/src/main.py b/src/main.py index 903c520..a10bf08 100644 --- a/src/main.py +++ b/src/main.py @@ -8,7 +8,6 @@ import utils.handlers import utils.response import utils.auth -import utils.misc from config import config import routers @@ -17,9 +16,8 @@ async def lifespan(_app: FastAPI): logger.info("Starting application") - utils.misc.create_super_user() - yield + db.close_connection() logger.info("Shutting down application") diff --git a/src/utils/misc.py b/src/utils/misc.py deleted file mode 100644 index d9b54ec..0000000 --- a/src/utils/misc.py +++ /dev/null @@ -1,30 +0,0 @@ -from loguru import logger - -import db -import utils.auth -from config import config - - -def create_super_user(): - admin_role = db.types.role.Role( - _id="admin", - name="Admin", - code=utils.auth.permissions.ALL_PERMISSIONS_ROLE_CODE, - description="The most powerful thing besides database access credentials))" - ) - if db.methods.roles.insert(admin_role): - logger.info("Created admin role") - - result = db.methods.users.insert_user_with_id( - config.super_user.email, - utils.auth.hash_password(config.super_user.password.get_secret_value()), - roles=["admin"] - ) - if result is not None: - logger.info("Created a new super user") - - super_user = db.methods.users.get_by_email(config.super_user.email) - if super_user is None: - logger.warning("There is no super user in the system") - else: - logger.info(f"Current super user: id={super_user.id}, email={super_user.email}") diff --git a/tests/src/auth.test.ts b/tests/src/auth.test.ts index d8972b7..e7e4f1d 100644 --- a/tests/src/auth.test.ts +++ b/tests/src/auth.test.ts @@ -71,12 +71,4 @@ describe("Basic auth", () => { } }); }); - - test("Super user", async () => { - const access_token = await pactum.spec() - .post("/api/auth/signin") - .withBody(SuperUserCredentials) - .expectJsonLike({ok: true}) - .returns(ctx => ctx.res.body.access); - }); }); From f8032e30a23d021aad64c8a1220905b460660d9f Mon Sep 17 00:00:00 2001 From: Spotika Date: Wed, 7 Aug 2024 23:12:17 +0200 Subject: [PATCH 61/94] fix: fix pylint --- src/config/config_model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/config/config_model.py b/src/config/config_model.py index e81b8c3..5263e6d 100644 --- a/src/config/config_model.py +++ b/src/config/config_model.py @@ -1,6 +1,5 @@ """Entire project configuration model""" from pydantic import BaseModel, SecretStr -from db.types.common import Email class MongoDBCollections(BaseModel): users: str = "Users" From f4fb241a6a0838ebe4bcec4d9a897934cf63660c Mon Sep 17 00:00:00 2001 From: spotika4 Date: Thu, 8 Aug 2024 16:44:34 +0300 Subject: [PATCH 62/94] chore: remove docker-compose version --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 9538ec6..835b8ec 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3" - services: db: image: mongo @@ -17,6 +15,7 @@ services: - "4242:4242" depends_on: - db + tty: true db_test: image: mongo @@ -37,6 +36,7 @@ services: interval: 10s timeout: 10m retries: 3 + tty: true test: build: context: ./tests From f9b90ee192a72d2ce451025c0f9d591e33c92528 Mon Sep 17 00:00:00 2001 From: spotika4 Date: Thu, 8 Aug 2024 21:36:07 +0300 Subject: [PATCH 63/94] refactor: move load function in config model --- src/config/__init__.py | 4 ++-- src/config/config_model.py | 34 ++++++++++++++++++++++++++++++++++ src/config/load_config.py | 35 ----------------------------------- 3 files changed, 36 insertions(+), 37 deletions(-) delete mode 100644 src/config/load_config.py diff --git a/src/config/__init__.py b/src/config/__init__.py index 9668026..85c2e2a 100644 --- a/src/config/__init__.py +++ b/src/config/__init__.py @@ -1,6 +1,6 @@ -from .load_config import load_config +from .config_model import Config -config = load_config() +config = Config.load() __all__ = [ "config" diff --git a/src/config/config_model.py b/src/config/config_model.py index 5263e6d..4eebd61 100644 --- a/src/config/config_model.py +++ b/src/config/config_model.py @@ -1,5 +1,10 @@ """Entire project configuration model""" +import os +import sys from pydantic import BaseModel, SecretStr +from pydantic import ValidationError +from loguru import logger + class MongoDBCollections(BaseModel): users: str = "Users" @@ -27,3 +32,32 @@ class Config(BaseModel): auth: AuthConfig debug: bool = False allow_origins: list[str] = [] + + @classmethod + def load(cls): + config_path = os.getenv("CONFIG_PATH") + + if config_path is None: + logger.error("Environment variable CONFIG_PATH is not set") + sys.exit(1) + + file_exists = False + if os.path.exists(config_path) and os.path.isfile(config_path): + _, file_extension = os.path.splitext(config_path) + if file_extension.lower() == '.json': + file_exists = True + + if not file_exists: + logger.error( + f"File {config_path} is not a json file or isnt exists" + ) + sys.exit(1) + + try: + with open(config_path, "r", encoding="utf-8") as config_file: + return Config.model_validate_json(config_file.read()) + except ValidationError as exception: + logger.error( + f"Failed to load configuration with errors: {exception.errors()}" + ) + sys.exit(1) diff --git a/src/config/load_config.py b/src/config/load_config.py deleted file mode 100644 index bdebf9b..0000000 --- a/src/config/load_config.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -import sys -from loguru import logger -from pydantic import ValidationError - -from .config_model import Config - - -def load_config() -> Config: - config_path = os.getenv("CONFIG_PATH") - - if config_path is None: - logger.error("Environment variable CONFIG_PATH is not set") - sys.exit(1) - - file_exists = False - if os.path.exists(config_path) and os.path.isfile(config_path): - _, file_extension = os.path.splitext(config_path) - if file_extension.lower() == '.json': - file_exists = True - - if not file_exists: - logger.error( - f"File {config_path} is not a json file or isnt exists" - ) - sys.exit(1) - - try: - with open(config_path, "r", encoding="utf-8") as config_file: - return Config.model_validate_json(config_file.read()) - except ValidationError as exception: - logger.error( - f"Failed to load configuration with errors: {exception.errors()}" - ) - sys.exit(1) From 091b21cf984d0cdea422dad88c05731a929513d3 Mon Sep 17 00:00:00 2001 From: spotika4 Date: Thu, 8 Aug 2024 21:37:27 +0300 Subject: [PATCH 64/94] refactor: refactor auth module --- src/utils/auth/auth.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/utils/auth/auth.py b/src/utils/auth/auth.py index 1de70e0..2cb4a51 100644 --- a/src/utils/auth/auth.py +++ b/src/utils/auth/auth.py @@ -45,8 +45,8 @@ def get_auth_header_credentials( def convert_role_code_to_permissions(role_code: int) -> list[int]: permissions = [] i = 0 - while 1 << i <= role_code: - if role_code >> i & 1 == 1: + while (1 << i) <= role_code: + if (role_code >> i) & 1: permissions.append(i) i += 1 return permissions @@ -96,8 +96,7 @@ def decode_jwt( try: payload = jose.jwt.decode( jwt, - secret_key, - # ! algorithms=["HS256"] + secret_key ) subject = payload.get("subject", None) From 08db157fba16f2fb0b3f51dbcb7ef048a3dbf8c0 Mon Sep 17 00:00:00 2001 From: spotika4 Date: Thu, 8 Aug 2024 21:44:44 +0300 Subject: [PATCH 65/94] refactor: change resolve entity signature --- src/db/methods/domains.py | 9 ++++----- src/routers/auth.py | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/db/methods/domains.py b/src/db/methods/domains.py index d26ea14..6de8841 100644 --- a/src/db/methods/domains.py +++ b/src/db/methods/domains.py @@ -16,10 +16,9 @@ def attach_to_entity( upsert=True ) -def resolve_id( +def resolve_entity( domain: str -) -> tuple[int | None, types.domain.TargetType | None]: +) -> types.domain.Entity | None: if (entity := domains.find_one({"_id": domain})) is None: - return None, None - entity = types.domain.Entity(**entity) - return entity.target_id, entity.target_type + return None + return types.domain.Entity(**entity) diff --git a/src/routers/auth.py b/src/routers/auth.py index e6b981e..0f128f6 100644 --- a/src/routers/auth.py +++ b/src/routers/auth.py @@ -37,9 +37,9 @@ async def signin( if siginin_input.id: user = methods.users.get(siginin_input.id) elif siginin_input.domain: - user_id, target_type = methods.domains.resolve_id(siginin_input.domain) - if user_id and target_type == "user": - user = methods.users.get(user_id) + entity = methods.domains.resolve_entity(siginin_input.domain) + if entity and entity.target_type == "user": + user = methods.users.get(entity.target_id) elif siginin_input.email: user = methods.users.get_by_email(siginin_input.email) From ea3b8133625c29cd877cb5154ef2dfb184bbe962 Mon Sep 17 00:00:00 2001 From: spotika4 Date: Thu, 8 Aug 2024 21:45:32 +0300 Subject: [PATCH 66/94] style --- src/db/types/auth.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/db/types/auth.py b/src/db/types/auth.py index 4e2df66..8d112af 100644 --- a/src/db/types/auth.py +++ b/src/db/types/auth.py @@ -18,8 +18,6 @@ class SignInInput(BaseModel): def check_only_one_field(self): error_message = "You must provide exactly one of the fields: email, domain, user_id" assert sum(x is not None for x in ( - self.id, - self.domain, - self.email + self.id, self.domain, self.email )) == 1, error_message return self From b98cf31b061332e6b1870ea4214c51b3fdaff7ce Mon Sep 17 00:00:00 2001 From: spotika4 Date: Thu, 8 Aug 2024 21:59:36 +0300 Subject: [PATCH 67/94] refactor: remove uneccessary validation in models --- src/db/types/common.py | 1 - src/db/types/contest.py | 19 +++++++++---------- src/db/types/contest_member.py | 5 ++--- src/db/types/domain.py | 6 +++--- src/db/types/group.py | 16 ++++++++-------- src/db/types/group_member.py | 9 ++++----- src/db/types/group_role.py | 12 ++++++------ src/db/types/problem.py | 6 +++--- src/db/types/role.py | 9 ++++----- src/db/types/submission.py | 10 ++++------ src/db/types/user.py | 12 ++++++------ 11 files changed, 49 insertions(+), 56 deletions(-) diff --git a/src/db/types/common.py b/src/db/types/common.py index 3ed9992..9990902 100644 --- a/src/db/types/common.py +++ b/src/db/types/common.py @@ -3,7 +3,6 @@ from pydantic import AfterValidator - def _is_email(email: str) -> str: pattern = r"^[a-zA-Z0-9_\.]+@[a-zA-Z0-9_\.]+\.[a-z]{2,5}" assert re.fullmatch(pattern, email) is not None, f"String {email} is not a valid email" diff --git a/src/db/types/contest.py b/src/db/types/contest.py index aebe419..336566b 100644 --- a/src/db/types/contest.py +++ b/src/db/types/contest.py @@ -2,21 +2,20 @@ from pydantic import Field from utils.schemas import BaseModel -from .common import IntegerId, ObjectName, DomainName, ObjectDescription class Contest(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-375""" - id: IntegerId = Field(alias='_id') - name: ObjectName - domain: DomainName | None = None - local_domain: DomainName | None = None - description: ObjectDescription = "" - submissions: list[IntegerId] - members: list[IntegerId] - creators: list[IntegerId] + id: int = Field(alias='_id') + name: str + domain: str | None = None + local_domain: str | None = None + description: str = "" + submissions: list[int] + members: list[int] + creators: list[int] begin_time: datetime.datetime duration: datetime.datetime after_work: bool - group_id: IntegerId + group_id: int diff --git a/src/db/types/contest_member.py b/src/db/types/contest_member.py index 50afdb5..1172b9c 100644 --- a/src/db/types/contest_member.py +++ b/src/db/types/contest_member.py @@ -1,11 +1,10 @@ from pydantic import Field from utils.schemas import BaseModel -from .common import IntegerId class ContestMember(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-435""" - id: IntegerId = Field(alias="_id") - contest_id: IntegerId + id: int = Field(alias="_id") + contest_id: int diff --git a/src/db/types/domain.py b/src/db/types/domain.py index 4ad38f3..c2751dd 100644 --- a/src/db/types/domain.py +++ b/src/db/types/domain.py @@ -2,13 +2,13 @@ from pydantic import Field from utils.schemas import BaseModel -from .common import IntegerId, DomainName + TargetType = Literal["user", "group", "contest"] class Entity(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-395""" - id: DomainName = Field(alias='_id') + id: str = Field(alias='_id') target_type: TargetType - target_id: IntegerId + target_id: int diff --git a/src/db/types/group.py b/src/db/types/group.py index cbaede8..437812e 100644 --- a/src/db/types/group.py +++ b/src/db/types/group.py @@ -1,15 +1,15 @@ from pydantic import Field from utils.schemas import BaseModel -from .common import IntegerId, ObjectName, DomainName, StringId, ObjectDescription + class Group(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-335""" - id: IntegerId = Field(alias='_id') - name: ObjectName - domain: DomainName | None = None - description: ObjectDescription - members: list[IntegerId] = [] - owner: IntegerId - roles: list[StringId] = [] + id: int = Field(alias='_id') + name: str + domain: str | None = None + description: str + members: list[int] = [] + owner_id: int + roles: list[str] = [] diff --git a/src/db/types/group_member.py b/src/db/types/group_member.py index 2d3ada7..bc0ae44 100644 --- a/src/db/types/group_member.py +++ b/src/db/types/group_member.py @@ -1,13 +1,12 @@ from pydantic import Field from utils.schemas import BaseModel -from .common import IntegerId, RoleCode class GroupMember(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-415""" - id: IntegerId = Field(alias="_id") - group_id: IntegerId - custom_permissions: RoleCode - roles: list[IntegerId] + id: int = Field(alias="_id") + group_id: int + custom_role_code: int + roles: list[int] diff --git a/src/db/types/group_role.py b/src/db/types/group_role.py index a5afbc9..f358a75 100644 --- a/src/db/types/group_role.py +++ b/src/db/types/group_role.py @@ -1,13 +1,13 @@ from pydantic import Field from utils.schemas import BaseModel -from .common import StringId, ObjectName, ObjectDescription, IntegerId, RoleCode + class GroupRole(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-495""" - id: StringId = Field(alias='_id') - name: ObjectName - description: ObjectDescription - group_id: IntegerId - role_code: RoleCode + id: str = Field(alias='_id') + name: str + description: str + group_id: int + role_code: int diff --git a/src/db/types/problem.py b/src/db/types/problem.py index 4f0a87a..2e9e6d4 100644 --- a/src/db/types/problem.py +++ b/src/db/types/problem.py @@ -1,10 +1,10 @@ from pydantic import Field from utils.schemas import BaseModel -from .common import IntegerId, ObjectName + class Problem(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-455""" - id: IntegerId = Field(alias='_id') - name: ObjectName + id: int = Field(alias='_id') + name: str diff --git a/src/db/types/role.py b/src/db/types/role.py index dd6adab..4f48d7c 100644 --- a/src/db/types/role.py +++ b/src/db/types/role.py @@ -1,12 +1,11 @@ from pydantic import Field from utils.schemas import BaseModel -from .common import StringId, ObjectName, ObjectDescription, RoleCode class Role(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-315""" - id: StringId = Field(alias='_id') - name: ObjectName - description: ObjectDescription = "" - code: RoleCode + id: str = Field(alias='_id') + name: str + description: str = "" + code: int diff --git a/src/db/types/submission.py b/src/db/types/submission.py index df491df..ad55ea7 100644 --- a/src/db/types/submission.py +++ b/src/db/types/submission.py @@ -3,16 +3,14 @@ from pydantic import Field from utils.schemas import BaseModel -from .common import IntegerId - class Submission(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-475""" - id: IntegerId = Field(alias="_id") - problem_id: IntegerId - contest_id: IntegerId - user_id: IntegerId + id: int = Field(alias="_id") + problem_id: int + contest_id: int + user_id: int solution_path: str | None = None status: Literal["Testing", "OK"] upload_time: datetime.datetime diff --git a/src/db/types/user.py b/src/db/types/user.py index 1cb48a1..0f0abe5 100644 --- a/src/db/types/user.py +++ b/src/db/types/user.py @@ -1,20 +1,20 @@ from pydantic import Field from utils.schemas import BaseModel -from .common import IntegerId, DomainName, Email, StringId +from .common import Email class User(BaseModel): """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-295""" - id: IntegerId = Field(alias='_id') - domain: DomainName | None = Field(None) + id: int = Field(alias='_id') + domain: str | None = Field(None) first_name: str | None = Field(None) last_name: str | None = Field(None) mid_name: str | None = Field(None) - groups: list[IntegerId] = [] - roles: list[StringId] = [] + groups: list[int] = [] + roles: list[str] = [] hashed_password: str - email: Email + email: str class UserSignup(BaseModel): From 1268a476fd92c127cb010b867ba1cf9ac5e230d1 Mon Sep 17 00:00:00 2001 From: spotika4 Date: Thu, 8 Aug 2024 23:29:25 +0300 Subject: [PATCH 68/94] chore: improve pylint config --- tests/package-lock.json | 9425 +++++++++++++++++++-------------------- tests/src/auth.test.ts | 1 - 2 files changed, 4709 insertions(+), 4717 deletions(-) diff --git a/tests/package-lock.json b/tests/package-lock.json index 17172df..cbf1f56 100644 --- a/tests/package-lock.json +++ b/tests/package-lock.json @@ -1,4720 +1,4713 @@ { - "name": "integration_tests", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "integration_tests", - "version": "1.0.0", - "dependencies": { - "extended-eventsource": "^1.4.9", - "pactum": "^3.6.9" - }, - "devDependencies": { - "@shelf/jest-mongodb": "^4.3.2", - "jest": "^29.7.0", - "ts-jest": "^29.1.3", - "typescript": "^5.4.5" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@arr/every": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@arr/every/-/every-1.0.1.tgz", - "integrity": "sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", - "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", - "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-module-transforms": "^7.25.2", - "@babel/helpers": "^7.25.0", - "@babel/parser": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.2", - "@babel/types": "^7.25.2", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", - "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", - "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.25.2", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", - "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", - "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/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/@babel/highlight/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/@babel/parser": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", - "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.2" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", - "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", - "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", - "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.2", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", - "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@exodus/schemasafe": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", - "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==", - "license": "MIT" - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@mongodb-js/saslprep": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", - "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "sparse-bitfield": "^3.0.3" - } - }, - "node_modules/@polka/url": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz", - "integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==", - "license": "MIT" - }, - "node_modules/@shelf/jest-mongodb": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@shelf/jest-mongodb/-/jest-mongodb-4.3.2.tgz", - "integrity": "sha512-LL7NBaT04sJspoOZXqw3HGLw0+XnZNlIV72x2ymzyuloqIKXwgUl8eL1XKDUh4Ud8dUBRMrOngCQBcHKjWnrHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4.3.4", - "mongodb-memory-server": "9.2.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "jest-environment-node": "28.x || 29.x", - "mongodb": "3.x.x || 4.x || 5.x || 6.x" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/node": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", - "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.13.0" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/webidl-conversions": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/whatwg-url": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", - "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/webidl-conversions": "*" - } - }, - "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true, - "license": "MIT" - }, - "node_modules/async-mutex": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.4.1.tgz", - "integrity": "sha512-WfoBo4E/TbCX1G95XTjbWTE3X2XLG0m1Xbv2cwOtuPdyH9CZvnaA5nCt1ucjaKEgW2A5IF71hxrRhr83Je5xjA==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/b4a": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", - "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/bare-events": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", - "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", - "dev": true, - "license": "Apache-2.0", - "optional": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.23.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", - "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001646", - "electron-to-chromium": "^1.5.4", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/bson": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", - "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=16.20.1" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001647", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001647.tgz", - "integrity": "sha512-n83xdNiyeNcHpzWY+1aFbqCK7LuLfBricc4+alSQL2Xb6OR3XpnQAmlDG+pQcdTfiHRuLcQ96VOfrPSGiNJYSg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/centra": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", - "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", - "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dedent": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/deep-override": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/deep-override/-/deep-override-1.0.2.tgz", - "integrity": "sha512-+bAuLuYqaVVUWPaq8rmU8NLTX85p4I5k5/cVdhBioEfH7k+5NlGdv4NoJVQcJRByqzzTWWzTpih+pU1wBTmMow==", - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", - "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==", - "dev": true, - "license": "ISC" - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/extended-eventsource": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/extended-eventsource/-/extended-eventsource-1.4.9.tgz", - "integrity": "sha512-x0SMAw57jEaiBKLQWTatVBZkT/PRuL5hdiEP6s8GKqeQOapBRwnohI6e8zGM0XStolQrQe+L6Wvin8G0UthRbw==", - "license": "MIT" - }, - "node_modules/fast-fifo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "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/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "license": "MIT", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-cache-dir/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data-lite": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/form-data-lite/-/form-data-lite-1.0.3.tgz", - "integrity": "sha512-P7xPqAiOPKzC9Q9aywAZJCQq4QOE5WokPb3HrcWRh7C57RKytueJzoORZAVgHBNvK/lL7E+FxjQjd4X/zbecEQ==", - "license": "ISC", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-lite": "^1.0.3" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "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==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-core-module": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", - "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-query": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/json-query/-/json-query-2.2.2.tgz", - "integrity": "sha512-y+IcVZSdqNmS4fO8t1uZF6RMMs0xh3SrTjJr9bp1X3+v0Q13+7Cyv12dSmKwDswp/H427BVtpkLWhGxYu3ZWRA==", - "engines": { - "node": "*" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/lightcookie": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/lightcookie/-/lightcookie-1.0.25.tgz", - "integrity": "sha512-SrY/+eBPaKAMnsn7mCsoOMZzoQyCyHHHZlFCu2fjo28XxSyCLjlooKiTxyrXTg8NPaHp1YzWi0lcGG1gDi6KHw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "license": "SEE LICENSE IN LICENSE.md" - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/matchit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/matchit/-/matchit-1.1.0.tgz", - "integrity": "sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==", - "license": "MIT", - "dependencies": { - "@arr/every": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-lite": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mime-lite/-/mime-lite-1.0.3.tgz", - "integrity": "sha512-V85l97zJSTG8FEvmdTlmNYb0UMrVBwvRjw7bWTf/aT6KjFwtz3iTz8D2tuFIp7lwiaO2C5ecnrEmSkkMRCrqVw==", - "license": "MIT" - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mongodb": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz", - "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@mongodb-js/saslprep": "^1.1.5", - "bson": "^6.7.0", - "mongodb-connection-string-url": "^3.0.0" - }, - "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.2.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/mongodb-connection-string-url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", - "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@types/whatwg-url": "^11.0.2", - "whatwg-url": "^13.0.0" - } - }, - "node_modules/mongodb-memory-server": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-9.2.0.tgz", - "integrity": "sha512-w/usKdYtby5EALERxmA0+et+D0brP0InH3a26shNDgGefXA61hgl6U0P3IfwqZlEGRZdkbZig3n57AHZgDiwvg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "mongodb-memory-server-core": "9.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.20.1" - } - }, - "node_modules/mongodb-memory-server-core": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-9.2.0.tgz", - "integrity": "sha512-9SWZEy+dGj5Fvm5RY/mtqHZKS64o4heDwReD4SsfR7+uNgtYo+JN41kPCcJeIH3aJf04j25i5Dia2s52KmsMPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "async-mutex": "^0.4.0", - "camelcase": "^6.3.0", - "debug": "^4.3.4", - "find-cache-dir": "^3.3.2", - "follow-redirects": "^1.15.6", - "https-proxy-agent": "^7.0.4", - "mongodb": "^5.9.1", - "new-find-package-json": "^2.0.0", - "semver": "^7.6.0", - "tar-stream": "^3.1.7", - "tslib": "^2.6.2", - "yauzl": "^3.1.3" - }, - "engines": { - "node": ">=14.20.1" - } - }, - "node_modules/mongodb-memory-server-core/node_modules/@types/whatwg-url": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", - "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/webidl-conversions": "*" - } - }, - "node_modules/mongodb-memory-server-core/node_modules/bson": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", - "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14.20.1" - } - }, - "node_modules/mongodb-memory-server-core/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mongodb-memory-server-core/node_modules/mongodb": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz", - "integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bson": "^5.5.0", - "mongodb-connection-string-url": "^2.6.0", - "socks": "^2.7.1" - }, - "engines": { - "node": ">=14.20.1" - }, - "optionalDependencies": { - "@mongodb-js/saslprep": "^1.1.0" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.0.0", - "kerberos": "^1.0.0 || ^2.0.0", - "mongodb-client-encryption": ">=2.3.0 <3", - "snappy": "^7.2.2" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - } - } - }, - "node_modules/mongodb-memory-server-core/node_modules/mongodb-connection-string-url": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", - "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/whatwg-url": "^8.2.1", - "whatwg-url": "^11.0.0" - } - }, - "node_modules/mongodb-memory-server-core/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mongodb-memory-server-core/node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mongodb-memory-server-core/node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/new-find-package-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/new-find-package-json/-/new-find-package-json-2.0.0.tgz", - "integrity": "sha512-lDcBsjBSMlj3LXH2v/FW3txlh2pYTjmbOXPYJD93HI5EwuLzI11tdHSIpUMmfq/IOsldj4Ps8M8flhm+pCK4Ew==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">=12.22.0" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true, - "license": "MIT" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/openapi-fuzzer-core": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/openapi-fuzzer-core/-/openapi-fuzzer-core-1.0.6.tgz", - "integrity": "sha512-FJNJIfgUFuv4NmVGq9MYdoKra2GrkDy2uhIjE2YGlw30UA1glf4SXLMhI4UwdcJ8jisKdIxi7lXrfej8GvNW5w==", - "license": "ISC", - "dependencies": { - "klona": "^2.0.4" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pactum": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/pactum/-/pactum-3.7.1.tgz", - "integrity": "sha512-r+R1dMy2MfRCQpAHohMyICusiMz14t0E+bhnLDScl2x4lXJKQAvQUGV/WWKUUxN2DS0Jdm0PUj6KjblfcSk1GA==", - "license": "MIT", - "dependencies": { - "@exodus/schemasafe": "^1.3.0", - "deep-override": "^1.0.2", - "form-data-lite": "^1.0.3", - "json-query": "^2.2.2", - "klona": "^2.0.6", - "lightcookie": "^1.0.25", - "openapi-fuzzer-core": "^1.0.6", - "pactum-matchers": "^1.1.7", - "parse-graphql": "^1.0.0", - "phin": "^3.7.0", - "polka": "^0.5.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pactum-matchers": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/pactum-matchers/-/pactum-matchers-1.1.7.tgz", - "integrity": "sha512-RqwewcUje6vhcYQGbPfdSXkcp/Vtwn4WmmTWLSmqp0CGxBroCEqRg3JMIjkjQTZCd2VmG+tTcQw+n4P/iuqv3Q==", - "license": "MIT" - }, - "node_modules/parse-graphql": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-graphql/-/parse-graphql-1.0.0.tgz", - "integrity": "sha512-NjvQHHaiPCxPZrhm/kKnorxOv7r/eA+tE0VW5E8iJMH9wTqFA1V0YK/7nbpxVu3JdXUxyWTKMez9lsHUtAwa0w==", - "license": "MIT" - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, - "license": "MIT" - }, - "node_modules/phin": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", - "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", - "license": "MIT", - "dependencies": { - "centra": "^2.7.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/polka": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/polka/-/polka-0.5.2.tgz", - "integrity": "sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==", - "license": "MIT", - "dependencies": { - "@polka/url": "^0.5.0", - "trouter": "^2.0.1" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", - "dev": true, - "license": "MIT" - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ip-address": "^9.0.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "memory-pager": "^1.0.2" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/streamx": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", - "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-fifo": "^1.3.2", - "queue-tick": "^1.0.1", - "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", - "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "punycode": "^2.3.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/trouter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/trouter/-/trouter-2.0.1.tgz", - "integrity": "sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==", - "license": "MIT", - "dependencies": { - "matchit": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/ts-jest": { - "version": "29.2.4", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.4.tgz", - "integrity": "sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "0.x", - "ejs": "^3.1.10", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "^7.5.3", - "yargs-parser": "^21.0.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true, - "license": "0BSD" - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", - "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==", - "dev": true, - "license": "MIT" - }, - "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", - "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yauzl": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.1.3.tgz", - "integrity": "sha512-JCCdmlJJWv7L0q/KylOekyRaUrdEoUxWkWVcgorosTROCFWiS9p2NNPE9Yb91ak7b1N5SxAZEliWpspbZccivw==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "pend": "~1.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "name": "tests", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tests", + "version": "1.0.0", + "dependencies": { + "pactum": "^3.6.9" + }, + "devDependencies": { + "@shelf/jest-mongodb": "^4.3.2", + "jest": "^29.7.0", + "ts-jest": "^29.1.3", + "typescript": "^5.4.5" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@arr/every": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@arr/every/-/every-1.0.1.tgz", + "integrity": "sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/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/@babel/highlight/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/@babel/parser": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.2" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", + "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", + "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==", + "license": "MIT" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", + "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@polka/url": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz", + "integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==", + "license": "MIT" + }, + "node_modules/@shelf/jest-mongodb": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@shelf/jest-mongodb/-/jest-mongodb-4.3.2.tgz", + "integrity": "sha512-LL7NBaT04sJspoOZXqw3HGLw0+XnZNlIV72x2ymzyuloqIKXwgUl8eL1XKDUh4Ud8dUBRMrOngCQBcHKjWnrHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4.3.4", + "mongodb-memory-server": "9.2.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "jest-environment-node": "28.x || 29.x", + "mongodb": "3.x.x || 4.x || 5.x || 6.x" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", + "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.13.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-mutex": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.4.1.tgz", + "integrity": "sha512-WfoBo4E/TbCX1G95XTjbWTE3X2XLG0m1Xbv2cwOtuPdyH9CZvnaA5nCt1ucjaKEgW2A5IF71hxrRhr83Je5xjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", + "dev": true, + "license": "Apache-2.0", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/bson": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", + "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001647", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001647.tgz", + "integrity": "sha512-n83xdNiyeNcHpzWY+1aFbqCK7LuLfBricc4+alSQL2Xb6OR3XpnQAmlDG+pQcdTfiHRuLcQ96VOfrPSGiNJYSg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/centra": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", + "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-override": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/deep-override/-/deep-override-1.0.2.tgz", + "integrity": "sha512-+bAuLuYqaVVUWPaq8rmU8NLTX85p4I5k5/cVdhBioEfH7k+5NlGdv4NoJVQcJRByqzzTWWzTpih+pU1wBTmMow==", + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", + "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "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/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-cache-dir/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data-lite": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/form-data-lite/-/form-data-lite-1.0.3.tgz", + "integrity": "sha512-P7xPqAiOPKzC9Q9aywAZJCQq4QOE5WokPb3HrcWRh7C57RKytueJzoORZAVgHBNvK/lL7E+FxjQjd4X/zbecEQ==", + "license": "ISC", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-lite": "^1.0.3" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "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==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-query": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json-query/-/json-query-2.2.2.tgz", + "integrity": "sha512-y+IcVZSdqNmS4fO8t1uZF6RMMs0xh3SrTjJr9bp1X3+v0Q13+7Cyv12dSmKwDswp/H427BVtpkLWhGxYu3ZWRA==", + "engines": { + "node": "*" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lightcookie": { + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/lightcookie/-/lightcookie-1.0.25.tgz", + "integrity": "sha512-SrY/+eBPaKAMnsn7mCsoOMZzoQyCyHHHZlFCu2fjo28XxSyCLjlooKiTxyrXTg8NPaHp1YzWi0lcGG1gDi6KHw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "SEE LICENSE IN LICENSE.md" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/matchit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/matchit/-/matchit-1.1.0.tgz", + "integrity": "sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==", + "license": "MIT", + "dependencies": { + "@arr/every": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-lite": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mime-lite/-/mime-lite-1.0.3.tgz", + "integrity": "sha512-V85l97zJSTG8FEvmdTlmNYb0UMrVBwvRjw7bWTf/aT6KjFwtz3iTz8D2tuFIp7lwiaO2C5ecnrEmSkkMRCrqVw==", + "license": "MIT" + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mongodb": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz", + "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, + "node_modules/mongodb-memory-server": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-9.2.0.tgz", + "integrity": "sha512-w/usKdYtby5EALERxmA0+et+D0brP0InH3a26shNDgGefXA61hgl6U0P3IfwqZlEGRZdkbZig3n57AHZgDiwvg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "mongodb-memory-server-core": "9.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.20.1" + } + }, + "node_modules/mongodb-memory-server-core": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-9.2.0.tgz", + "integrity": "sha512-9SWZEy+dGj5Fvm5RY/mtqHZKS64o4heDwReD4SsfR7+uNgtYo+JN41kPCcJeIH3aJf04j25i5Dia2s52KmsMPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-mutex": "^0.4.0", + "camelcase": "^6.3.0", + "debug": "^4.3.4", + "find-cache-dir": "^3.3.2", + "follow-redirects": "^1.15.6", + "https-proxy-agent": "^7.0.4", + "mongodb": "^5.9.1", + "new-find-package-json": "^2.0.0", + "semver": "^7.6.0", + "tar-stream": "^3.1.7", + "tslib": "^2.6.2", + "yauzl": "^3.1.3" + }, + "engines": { + "node": ">=14.20.1" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/bson": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", + "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14.20.1" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/mongodb": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz", + "integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bson": "^5.5.0", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=14.20.1" + }, + "optionalDependencies": { + "@mongodb-js/saslprep": "^1.1.0" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.0.0", + "kerberos": "^1.0.0 || ^2.0.0", + "mongodb-client-encryption": ">=2.3.0 <3", + "snappy": "^7.2.2" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + } + } + }, + "node_modules/mongodb-memory-server-core/node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-memory-server-core/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/new-find-package-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/new-find-package-json/-/new-find-package-json-2.0.0.tgz", + "integrity": "sha512-lDcBsjBSMlj3LXH2v/FW3txlh2pYTjmbOXPYJD93HI5EwuLzI11tdHSIpUMmfq/IOsldj4Ps8M8flhm+pCK4Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openapi-fuzzer-core": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/openapi-fuzzer-core/-/openapi-fuzzer-core-1.0.6.tgz", + "integrity": "sha512-FJNJIfgUFuv4NmVGq9MYdoKra2GrkDy2uhIjE2YGlw30UA1glf4SXLMhI4UwdcJ8jisKdIxi7lXrfej8GvNW5w==", + "license": "ISC", + "dependencies": { + "klona": "^2.0.4" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pactum": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/pactum/-/pactum-3.7.1.tgz", + "integrity": "sha512-r+R1dMy2MfRCQpAHohMyICusiMz14t0E+bhnLDScl2x4lXJKQAvQUGV/WWKUUxN2DS0Jdm0PUj6KjblfcSk1GA==", + "license": "MIT", + "dependencies": { + "@exodus/schemasafe": "^1.3.0", + "deep-override": "^1.0.2", + "form-data-lite": "^1.0.3", + "json-query": "^2.2.2", + "klona": "^2.0.6", + "lightcookie": "^1.0.25", + "openapi-fuzzer-core": "^1.0.6", + "pactum-matchers": "^1.1.7", + "parse-graphql": "^1.0.0", + "phin": "^3.7.0", + "polka": "^0.5.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pactum-matchers": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/pactum-matchers/-/pactum-matchers-1.1.7.tgz", + "integrity": "sha512-RqwewcUje6vhcYQGbPfdSXkcp/Vtwn4WmmTWLSmqp0CGxBroCEqRg3JMIjkjQTZCd2VmG+tTcQw+n4P/iuqv3Q==", + "license": "MIT" + }, + "node_modules/parse-graphql": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-graphql/-/parse-graphql-1.0.0.tgz", + "integrity": "sha512-NjvQHHaiPCxPZrhm/kKnorxOv7r/eA+tE0VW5E8iJMH9wTqFA1V0YK/7nbpxVu3JdXUxyWTKMez9lsHUtAwa0w==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/phin": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", + "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", + "license": "MIT", + "dependencies": { + "centra": "^2.7.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/polka": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/polka/-/polka-0.5.2.tgz", + "integrity": "sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==", + "license": "MIT", + "dependencies": { + "@polka/url": "^0.5.0", + "trouter": "^2.0.1" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/streamx": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", + "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", + "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/trouter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/trouter/-/trouter-2.0.1.tgz", + "integrity": "sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==", + "license": "MIT", + "dependencies": { + "matchit": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ts-jest": { + "version": "29.2.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.4.tgz", + "integrity": "sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "0.x", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.1.3.tgz", + "integrity": "sha512-JCCdmlJJWv7L0q/KylOekyRaUrdEoUxWkWVcgorosTROCFWiS9p2NNPE9Yb91ak7b1N5SxAZEliWpspbZccivw==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } + } } diff --git a/tests/src/auth.test.ts b/tests/src/auth.test.ts index e7e4f1d..54c2a5e 100644 --- a/tests/src/auth.test.ts +++ b/tests/src/auth.test.ts @@ -9,7 +9,6 @@ pactum.request.setBaseUrl("http://api_test:4242"); describe("Basic auth", () => { const first_email = GlobalCounter.getNextEmail(); const second_email = GlobalCounter.getNextEmail(); - const third_domain = GlobalCounter.getNextString(); const third_email = GlobalCounter.getNextEmail(); test("Registration", async () => { await pactum.spec() From fb962963bb29ebc50186a3281dcf2c3bc9fec0c8 Mon Sep 17 00:00:00 2001 From: spotika4 Date: Thu, 8 Aug 2024 23:30:02 +0300 Subject: [PATCH 69/94] ci: remove uneccessary build flag --- .github/workflows/test.yaml | 2 +- docker-compose.yml | 4 +++- pyproject.toml | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e0dc852..bc15e52 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -19,7 +19,7 @@ jobs: - name: Build and run Docker Compose run: | - sudo docker compose up --build -d test + sudo docker compose up -d test sudo docker compose logs -f test > test_logs.txt continue-on-error: true diff --git a/docker-compose.yml b/docker-compose.yml index 835b8ec..a9b3dae 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,8 @@ services: environment: - MONGO_INITDB_ROOT_USERNAME=admin - MONGO_INITDB_ROOT_PASSWORD=admin + ports: + - "27017:27017" api: build: context: ./ @@ -23,7 +25,7 @@ services: - MONGO_INITDB_ROOT_USERNAME=admin - MONGO_INITDB_ROOT_PASSWORD=admin ports: - - "27017:27017" + - "42042:42042" api_test: build: context: ./ diff --git a/pyproject.toml b/pyproject.toml index 34850ba..9c87f88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ build-backend = "poetry.core.masonry.api" [tool.pylint."MASTER"] jobs=4 +persistent="no" [tool.pylint."MESSAGES CONTROL"] disable="fixme,no-self-argument,missing-class-docstring,import-error,no-name-in-module,too-few-public-methods,missing-function-docstring,missing-module-docstring" From 0e8e2b0a199aa5f335fd1c5d580739b7085910b3 Mon Sep 17 00:00:00 2001 From: spotika4 Date: Fri, 9 Aug 2024 14:14:51 +0300 Subject: [PATCH 70/94] chore: refactor according the last meeting --- src/db/__init__.py | 1 + src/db/methods/__init__.py | 1 + src/db/methods/collections/__init__.py | 2 -- src/db/methods/collections/collections.py | 5 +--- src/db/methods/roles.py | 12 ++++----- src/db/methods/users.py | 18 +++++-------- src/db/types/__init__.py | 13 +++++++--- src/db/types/auth.py | 21 ++------------- src/db/types/common.py | 31 +---------------------- src/db/types/contest.py | 21 --------------- src/db/types/contest_member.py | 10 -------- src/db/types/domain.py | 2 -- src/db/types/group.py | 15 ----------- src/db/types/group_member.py | 12 --------- src/db/types/group_role.py | 13 ---------- src/db/types/problem.py | 10 -------- src/db/types/requests.py | 25 ++++++++++++++++++ src/db/types/responses.py | 10 ++++++++ src/db/types/role.py | 5 ++-- src/db/types/submission.py | 16 ------------ src/db/types/user.py | 20 +++++++-------- src/main.py | 9 ++----- src/routers/__init__.py | 16 ++---------- src/routers/auth.py | 20 +++++++++------ src/routers/contests.py | 4 --- src/routers/groups.py | 4 --- src/routers/problems.py | 4 --- src/routers/roles.py | 4 --- src/routers/service.py | 6 +++-- src/routers/submissions.py | 4 --- src/routers/users.py | 4 --- src/utils/auth/__init__.py | 1 + src/utils/auth/auth.py | 15 +++++------ tests/src/auth.test.ts | 21 ++++++++++----- 34 files changed, 116 insertions(+), 259 deletions(-) delete mode 100644 src/db/types/contest.py delete mode 100644 src/db/types/contest_member.py delete mode 100644 src/db/types/group.py delete mode 100644 src/db/types/group_member.py delete mode 100644 src/db/types/group_role.py delete mode 100644 src/db/types/problem.py create mode 100644 src/db/types/requests.py create mode 100644 src/db/types/responses.py delete mode 100644 src/db/types/submission.py delete mode 100644 src/routers/contests.py delete mode 100644 src/routers/groups.py delete mode 100644 src/routers/problems.py delete mode 100644 src/routers/roles.py delete mode 100644 src/routers/submissions.py delete mode 100644 src/routers/users.py diff --git a/src/db/__init__.py b/src/db/__init__.py index be86f3d..45dcb57 100644 --- a/src/db/__init__.py +++ b/src/db/__init__.py @@ -2,6 +2,7 @@ from .client import client, close_connection + __all__ = [ "types", "methods", diff --git a/src/db/methods/__init__.py b/src/db/methods/__init__.py index 2b79c62..e26ae62 100644 --- a/src/db/methods/__init__.py +++ b/src/db/methods/__init__.py @@ -4,6 +4,7 @@ domains ) + __all__ = [ "users", "roles", diff --git a/src/db/methods/collections/__init__.py b/src/db/methods/collections/__init__.py index 1adddd5..623a633 100644 --- a/src/db/methods/collections/__init__.py +++ b/src/db/methods/collections/__init__.py @@ -1,5 +1,3 @@ -"""This module for working with collections""" - from .collections import ( users, roles, diff --git a/src/db/methods/collections/collections.py b/src/db/methods/collections/collections.py index 0502c4c..b204ca3 100644 --- a/src/db/methods/collections/collections.py +++ b/src/db/methods/collections/collections.py @@ -1,7 +1,4 @@ -""" -The module that receives all collections by the configured name and exports them -Moreover this module create indexes -""" +"""Here collection and indexes are defined""" from db.client import db from config import config diff --git a/src/db/methods/roles.py b/src/db/methods/roles.py index 5fe81db..8adc806 100644 --- a/src/db/methods/roles.py +++ b/src/db/methods/roles.py @@ -1,15 +1,15 @@ from pymongo.errors import DuplicateKeyError -from db.types.role import Role + +from db import types from .collections import roles -def get(role_name: str) -> Role | None: - role = roles.find_one({"_id": role_name}) - if role is None: +def get(role_id: str) -> types.role.Role | None: + if (role := roles.find_one({"_id": role_id})) is None: return None - return Role(**role) + return types.role.Role(**role) -def insert(role: Role) -> bool: +def insert(role: types.role.Role) -> bool: try: roles.insert_one(role.model_dump()) except DuplicateKeyError: diff --git a/src/db/methods/users.py b/src/db/methods/users.py index d8c0382..3035ddb 100644 --- a/src/db/methods/users.py +++ b/src/db/methods/users.py @@ -1,24 +1,22 @@ from pymongo.errors import DuplicateKeyError -from db.types.user import User +from db import types from .collections import users from .helpers import insert_with_auto_increment_id -def get(user_id: int) -> User | None: +def get(user_id: int) -> types.user.User | None: if (user := users.find_one({"_id": user_id})) is None: return None - return User(**user) + return types.user.User(**user) def get_by_email(email: str): if (user := users.find_one({"email": email})) is None: return None - return User(**user) + return types.user.User(**user) def insert_user_with_id( - email: str, - hashed_password: str, - roles: list[str] | None = None + user: types.user.UserWithoutID ) -> int | None: """ Returns: @@ -27,11 +25,7 @@ def insert_user_with_id( try: return insert_with_auto_increment_id( users, - { - "email": email, - "hashed_password": hashed_password, - "roles": roles or [] - } + user.model_dump() ) except DuplicateKeyError: return None diff --git a/src/db/types/__init__.py b/src/db/types/__init__.py index 14f0087..321fc66 100644 --- a/src/db/types/__init__.py +++ b/src/db/types/__init__.py @@ -1,15 +1,20 @@ from . import ( auth, - user, common, + user, domain, - role + role, + requests, + responses ) + __all__ = [ "auth", "user", - "common", "domain", - "role" + "role", + "common", + "requests", + "responses" ] diff --git a/src/db/types/auth.py b/src/db/types/auth.py index 8d112af..13bf3fe 100644 --- a/src/db/types/auth.py +++ b/src/db/types/auth.py @@ -1,23 +1,6 @@ -from pydantic import model_validator - from utils.schemas import BaseModel -from db.types.common import IntegerId, DomainName, Email class JWTPair(BaseModel): - access: str - refresh: str - -class SignInInput(BaseModel): - id: IntegerId | None = None - domain: DomainName | None = None - email: Email | None = None - password: str - - @model_validator(mode="after") - def check_only_one_field(self): - error_message = "You must provide exactly one of the fields: email, domain, user_id" - assert sum(x is not None for x in ( - self.id, self.domain, self.email - )) == 1, error_message - return self + access_token: str + refresh_token: str diff --git a/src/db/types/common.py b/src/db/types/common.py index 9990902..b5074ef 100644 --- a/src/db/types/common.py +++ b/src/db/types/common.py @@ -1,5 +1,4 @@ import re -from typing import Annotated from pydantic import AfterValidator @@ -7,32 +6,4 @@ def _is_email(email: str) -> str: pattern = r"^[a-zA-Z0-9_\.]+@[a-zA-Z0-9_\.]+\.[a-z]{2,5}" assert re.fullmatch(pattern, email) is not None, f"String {email} is not a valid email" return email -Email = Annotated[str, AfterValidator(_is_email)] - -def _is_positive_number(number: int) -> int: - assert number > 0, f"Number {number} must be a positive number" - return number -IntegerId = Annotated[int, AfterValidator(_is_positive_number)] - -def _is_domain_name(domain: str) -> str: - return domain # TODO: define behaviour -DomainName = Annotated[str, AfterValidator(_is_domain_name)] - -def _is_object_name(name: str) -> str: - return name # TODO: define behaviour -ObjectName = Annotated[str, AfterValidator(_is_object_name)] - -def _is_object_description(description: str) -> str: - return description # TODO: define behaviour -ObjectDescription = Annotated[str, AfterValidator(_is_object_description)] - -def _is_role_code(number: int) -> int: - assert number >= 0, "Role code can not be negative" - return number -RoleCode = Annotated[int, AfterValidator(_is_role_code)] - -def _string_id(string: str) -> str: - pattern = r"[a-z]+(?:_[a-z]+)*" - assert re.fullmatch(pattern, string) is not None, "String id is not valid" - return string -StringId = Annotated[str, AfterValidator(_string_id)] +is_email = AfterValidator(_is_email) diff --git a/src/db/types/contest.py b/src/db/types/contest.py deleted file mode 100644 index 336566b..0000000 --- a/src/db/types/contest.py +++ /dev/null @@ -1,21 +0,0 @@ -import datetime -from pydantic import Field - -from utils.schemas import BaseModel - - -class Contest(BaseModel): - """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-375""" - - id: int = Field(alias='_id') - name: str - domain: str | None = None - local_domain: str | None = None - description: str = "" - submissions: list[int] - members: list[int] - creators: list[int] - begin_time: datetime.datetime - duration: datetime.datetime - after_work: bool - group_id: int diff --git a/src/db/types/contest_member.py b/src/db/types/contest_member.py deleted file mode 100644 index 1172b9c..0000000 --- a/src/db/types/contest_member.py +++ /dev/null @@ -1,10 +0,0 @@ -from pydantic import Field - -from utils.schemas import BaseModel - - -class ContestMember(BaseModel): - """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-435""" - - id: int = Field(alias="_id") - contest_id: int diff --git a/src/db/types/domain.py b/src/db/types/domain.py index c2751dd..0b8f518 100644 --- a/src/db/types/domain.py +++ b/src/db/types/domain.py @@ -7,8 +7,6 @@ TargetType = Literal["user", "group", "contest"] class Entity(BaseModel): - """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-395""" - id: str = Field(alias='_id') target_type: TargetType target_id: int diff --git a/src/db/types/group.py b/src/db/types/group.py deleted file mode 100644 index 437812e..0000000 --- a/src/db/types/group.py +++ /dev/null @@ -1,15 +0,0 @@ -from pydantic import Field - -from utils.schemas import BaseModel - - -class Group(BaseModel): - """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-335""" - - id: int = Field(alias='_id') - name: str - domain: str | None = None - description: str - members: list[int] = [] - owner_id: int - roles: list[str] = [] diff --git a/src/db/types/group_member.py b/src/db/types/group_member.py deleted file mode 100644 index bc0ae44..0000000 --- a/src/db/types/group_member.py +++ /dev/null @@ -1,12 +0,0 @@ -from pydantic import Field - -from utils.schemas import BaseModel - - -class GroupMember(BaseModel): - """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-415""" - - id: int = Field(alias="_id") - group_id: int - custom_role_code: int - roles: list[int] diff --git a/src/db/types/group_role.py b/src/db/types/group_role.py deleted file mode 100644 index f358a75..0000000 --- a/src/db/types/group_role.py +++ /dev/null @@ -1,13 +0,0 @@ -from pydantic import Field - -from utils.schemas import BaseModel - - -class GroupRole(BaseModel): - """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-495""" - - id: str = Field(alias='_id') - name: str - description: str - group_id: int - role_code: int diff --git a/src/db/types/problem.py b/src/db/types/problem.py deleted file mode 100644 index 2e9e6d4..0000000 --- a/src/db/types/problem.py +++ /dev/null @@ -1,10 +0,0 @@ -from pydantic import Field - -from utils.schemas import BaseModel - - -class Problem(BaseModel): - """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-455""" - - id: int = Field(alias='_id') - name: str diff --git a/src/db/types/requests.py b/src/db/types/requests.py new file mode 100644 index 0000000..8729e5a --- /dev/null +++ b/src/db/types/requests.py @@ -0,0 +1,25 @@ +from typing import Annotated +from pydantic import model_validator +from utils.schemas import BaseModel + +from .common import is_email + + +class AuthSignin(BaseModel): + id: int | None = None + domain: str | None = None + email: str | None = None + password: str + + @model_validator(mode="after") + def check_only_one_field(self): + error_message = "You must provide exactly one of the fields: email, domain, user_id" + assert sum(x is not None for x in ( + self.id, self.domain, self.email + )) == 1, error_message + return self + +class AuthSignup(BaseModel): + first_name: str # TODO: set validation here + email: Annotated[str, is_email] + password: str diff --git a/src/db/types/responses.py b/src/db/types/responses.py new file mode 100644 index 0000000..7324324 --- /dev/null +++ b/src/db/types/responses.py @@ -0,0 +1,10 @@ +from utils.schemas import BaseModel + + +class AuthSignin(BaseModel): + access_token: str + refresh_token: str + +class AuthSignup(BaseModel): + access_token: str + refresh_token: str diff --git a/src/db/types/role.py b/src/db/types/role.py index 4f48d7c..99c86b8 100644 --- a/src/db/types/role.py +++ b/src/db/types/role.py @@ -2,10 +2,9 @@ from utils.schemas import BaseModel -class Role(BaseModel): - """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-315""" +class Role(BaseModel): id: str = Field(alias='_id') name: str - description: str = "" + description: str | None = None code: int diff --git a/src/db/types/submission.py b/src/db/types/submission.py deleted file mode 100644 index ad55ea7..0000000 --- a/src/db/types/submission.py +++ /dev/null @@ -1,16 +0,0 @@ -import datetime -from typing import Literal -from pydantic import Field - -from utils.schemas import BaseModel - -class Submission(BaseModel): - """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-475""" - - id: int = Field(alias="_id") - problem_id: int - contest_id: int - user_id: int - solution_path: str | None = None - status: Literal["Testing", "OK"] - upload_time: datetime.datetime diff --git a/src/db/types/user.py b/src/db/types/user.py index 0f0abe5..3165f00 100644 --- a/src/db/types/user.py +++ b/src/db/types/user.py @@ -1,22 +1,20 @@ from pydantic import Field from utils.schemas import BaseModel -from .common import Email -class User(BaseModel): - """https://app.clickup.com/9015604104/v/dc/8cnycw8-115/8cnycw8-295""" - id: int = Field(alias='_id') - domain: str | None = Field(None) - first_name: str | None = Field(None) - last_name: str | None = Field(None) - mid_name: str | None = Field(None) +class _UserBase(BaseModel): + domain: str | None = None + first_name: str + last_name: str | None = None + mid_name: str | None = None groups: list[int] = [] roles: list[str] = [] hashed_password: str email: str +class UserWithoutID(_UserBase): + ... -class UserSignup(BaseModel): - email: Email - password: str +class User(_UserBase): + id: int = Field(alias='_id') diff --git a/src/main.py b/src/main.py index a10bf08..d471787 100644 --- a/src/main.py +++ b/src/main.py @@ -2,9 +2,10 @@ from loguru import logger from fastapi import FastAPI from fastapi.exceptions import RequestValidationError -from starlette.middleware.cors import CORSMiddleware +from fastapi.middleware.cors import CORSMiddleware import db +import routers.service import utils.handlers import utils.response import utils.auth @@ -23,13 +24,7 @@ async def lifespan(_app: FastAPI): app = FastAPI(debug=config.debug, lifespan=lifespan) -app.include_router(routers.users.router, prefix="/api/users") app.include_router(routers.auth.router, prefix="/api/auth") -app.include_router(routers.roles.router, prefix="/api/roles") -app.include_router(routers.groups.router, prefix="/api/groups") -app.include_router(routers.contests.router, prefix="/api/contests") -app.include_router(routers.problems.router, prefix="/api/problems") -app.include_router(routers.submissions.router, prefix="/api/submissions") app.include_router(routers.service.router, prefix="/api/service") diff --git a/src/routers/__init__.py b/src/routers/__init__.py index 58f6441..f8a0fbf 100644 --- a/src/routers/__init__.py +++ b/src/routers/__init__.py @@ -1,22 +1,10 @@ from . import ( auth, - users, - roles, - groups, - service, - problems, - contests, - submissions + service ) __all__ = [ "auth", - "users", - "roles", - "groups", - "service", - "problems", - "contests", - "submissions" + "service" ] diff --git a/src/routers/auth.py b/src/routers/auth.py index 0f128f6..872bede 100644 --- a/src/routers/auth.py +++ b/src/routers/auth.py @@ -1,24 +1,28 @@ from fastapi import APIRouter -from starlette import status as http_status +from fastapi import status as http_status import utils.auth from utils.response import SuccessfulResponse, ErrorCodes, ErrorResponse from db import methods from db import types +from db.types import requests as RQ, responses as RS router = APIRouter() -@router.post("/signup", response_model=SuccessfulResponse[types.auth.JWTPair]) +@router.post("/signup", response_model=SuccessfulResponse[RS.AuthSignup]) async def signup( - user_signup: types.user.UserSignup + request: RQ.AuthSignup ): - hashed_password = utils.auth.hash_password(user_signup.password) + hashed_password = utils.auth.hash_password(request.password) inserted_user_id = methods.users.insert_user_with_id( - user_signup.email, - hashed_password + types.user.UserWithoutID( + email=request.email, + hashed_password=hashed_password, + first_name=request.first_name + ) ) if inserted_user_id is None: @@ -29,9 +33,9 @@ async def signup( return utils.auth.create_jwt_pair_by_user_id(inserted_user_id) -@router.post("/signin", response_model=SuccessfulResponse[types.auth.JWTPair]) +@router.post("/signin", response_model=SuccessfulResponse[RS.AuthSignin]) async def signin( - siginin_input: types.auth.SignInInput + siginin_input: RQ.AuthSignin ): user: types.user.User | None = None if siginin_input.id: diff --git a/src/routers/contests.py b/src/routers/contests.py deleted file mode 100644 index e6f2f82..0000000 --- a/src/routers/contests.py +++ /dev/null @@ -1,4 +0,0 @@ -from fastapi import APIRouter - - -router = APIRouter() diff --git a/src/routers/groups.py b/src/routers/groups.py deleted file mode 100644 index 01800de..0000000 --- a/src/routers/groups.py +++ /dev/null @@ -1,4 +0,0 @@ -from fastapi import APIRouter - - -router = APIRouter() diff --git a/src/routers/problems.py b/src/routers/problems.py deleted file mode 100644 index e6f2f82..0000000 --- a/src/routers/problems.py +++ /dev/null @@ -1,4 +0,0 @@ -from fastapi import APIRouter - - -router = APIRouter() diff --git a/src/routers/roles.py b/src/routers/roles.py deleted file mode 100644 index 01800de..0000000 --- a/src/routers/roles.py +++ /dev/null @@ -1,4 +0,0 @@ -from fastapi import APIRouter - - -router = APIRouter() diff --git a/src/routers/service.py b/src/routers/service.py index dfe638a..af0fc5b 100644 --- a/src/routers/service.py +++ b/src/routers/service.py @@ -1,9 +1,11 @@ from fastapi import APIRouter +from utils.response import SuccessfulResponse + router = APIRouter() -@router.get("/ping") +@router.get("/ping", response_model=SuccessfulResponse[None]) async def ping(): - return "pong" + return diff --git a/src/routers/submissions.py b/src/routers/submissions.py deleted file mode 100644 index e6f2f82..0000000 --- a/src/routers/submissions.py +++ /dev/null @@ -1,4 +0,0 @@ -from fastapi import APIRouter - - -router = APIRouter() diff --git a/src/routers/users.py b/src/routers/users.py deleted file mode 100644 index 01800de..0000000 --- a/src/routers/users.py +++ /dev/null @@ -1,4 +0,0 @@ -from fastapi import APIRouter - - -router = APIRouter() diff --git a/src/utils/auth/__init__.py b/src/utils/auth/__init__.py index 18a9696..d8a0751 100644 --- a/src/utils/auth/__init__.py +++ b/src/utils/auth/__init__.py @@ -7,6 +7,7 @@ ) from . import permissions + __all__ = [ "auth_user", "create_jwt", diff --git a/src/utils/auth/auth.py b/src/utils/auth/auth.py index 2cb4a51..68674eb 100644 --- a/src/utils/auth/auth.py +++ b/src/utils/auth/auth.py @@ -3,11 +3,10 @@ import jose.jwt from passlib.context import CryptContext from fastapi import Header -from starlette import status as http_status +from fastapi import status as http_status +from db import types from db import methods -from db.types.auth import JWTPair -from db.types.user import User from utils import response from config import config from .permissions import Permissions @@ -119,14 +118,14 @@ def decode_jwt( http_status_code=http_status.HTTP_401_UNAUTHORIZED, ) from exc -def create_jwt_pair_by_user_id(user_id: int) -> JWTPair: - return JWTPair( - access=create_jwt( +def create_jwt_pair_by_user_id(user_id: int) ->types.auth.JWTPair: + return types.auth.JWTPair( + access_token=create_jwt( str(user_id), expiration_time_minutes=config.auth.access_token_expire_minutes, secret_key=config.auth.jwt_access_secret_key.get_secret_value() ), - refresh=create_jwt( + refresh_token=create_jwt( str(user_id), expiration_time_minutes=config.auth.refresh_token_expire_minutes, secret_key=config.auth.jwt_refresh_secret_key.get_secret_value() @@ -146,7 +145,7 @@ def auth_user(*permissions: Permissions): Function that auth user by given permissions and auth header """ - def wrapper(authorization: str = Header()) -> User: + def wrapper(authorization: str = Header()) -> types.user.User: token = get_auth_header_credentials(authorization, "Bearer") subject = decode_jwt(token, config.auth.jwt_access_secret_key.get_secret_value())["subject"] diff --git a/tests/src/auth.test.ts b/tests/src/auth.test.ts index 54c2a5e..c6dc673 100644 --- a/tests/src/auth.test.ts +++ b/tests/src/auth.test.ts @@ -14,6 +14,7 @@ describe("Basic auth", () => { await pactum.spec() .post("/api/auth/signup") .withBody({ + first_name: "Test", email: first_email, password: "1234" }) @@ -21,6 +22,7 @@ describe("Basic auth", () => { await pactum.spec() .post("/api/auth/signup") .withBody({ + first_name: "Test", email: second_email, password: "1234" }) @@ -29,6 +31,7 @@ describe("Basic auth", () => { await pactum.spec() .post("/api/auth/signup") .withBody({ + first_name: "Test", email: second_email, password: "1234" }) @@ -42,6 +45,7 @@ describe("Basic auth", () => { await pactum.spec() .post("/api/auth/signup") .withBody({ + first_name: "Test", email: third_email, password: "1234" }) @@ -57,17 +61,22 @@ describe("Basic auth", () => { }) .expectJsonLike({ok: true}); + await pactum.spec() + .post("/api/auth/signin") + .withBody({ + email: first_email, + domain: "test", + password: "1234" + }) + .expectJsonLike({ok: false, error: {code: ErrorCodes.UNPROCESSABLE_ENTITY}}); + + await pactum.spec() .post("/api/auth/signin") .withBody({ email: first_email, password: "incorrect_password" }) - .expectJsonLike({ - ok: false, - error: { - code: ErrorCodes.ACCESS_DENIED - } - }); + .expectJsonLike({ok: false, error: {code: ErrorCodes.ACCESS_DENIED}}); }); }); From e95a9d7c5314c2d05159367a0a4ff684fb396d19 Mon Sep 17 00:00:00 2001 From: spotika4 Date: Fri, 9 Aug 2024 14:18:38 +0300 Subject: [PATCH 71/94] style: fix pylint --- src/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.py b/src/main.py index d471787..835e05a 100644 --- a/src/main.py +++ b/src/main.py @@ -5,12 +5,12 @@ from fastapi.middleware.cors import CORSMiddleware import db +import routers import routers.service import utils.handlers import utils.response import utils.auth from config import config -import routers @asynccontextmanager From 93605b46bd636e60e9cce89ffccd868e687e9ecc Mon Sep 17 00:00:00 2001 From: spotika4 Date: Fri, 9 Aug 2024 14:23:17 +0300 Subject: [PATCH 72/94] chore: change allowed methods --- src/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.py b/src/main.py index 835e05a..98d60fe 100644 --- a/src/main.py +++ b/src/main.py @@ -32,7 +32,7 @@ async def lifespan(_app: FastAPI): CORSMiddleware, allow_origins=config.allow_origins, allow_credentials=config.debug, - allow_methods=["*"], + allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], allow_headers=["*"], ) From a8b0a0f9bc052cb13f8d30a13debc1971fc84be0 Mon Sep 17 00:00:00 2001 From: spotika4 Date: Fri, 9 Aug 2024 14:31:18 +0300 Subject: [PATCH 73/94] style --- src/db/methods/domains.py | 4 +--- src/db/methods/users.py | 7 ++----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/db/methods/domains.py b/src/db/methods/domains.py index 6de8841..9802582 100644 --- a/src/db/methods/domains.py +++ b/src/db/methods/domains.py @@ -16,9 +16,7 @@ def attach_to_entity( upsert=True ) -def resolve_entity( - domain: str -) -> types.domain.Entity | None: +def resolve_entity(domain: str) -> types.domain.Entity | None: if (entity := domains.find_one({"_id": domain})) is None: return None return types.domain.Entity(**entity) diff --git a/src/db/methods/users.py b/src/db/methods/users.py index 3035ddb..f50220b 100644 --- a/src/db/methods/users.py +++ b/src/db/methods/users.py @@ -15,17 +15,14 @@ def get_by_email(email: str): return None return types.user.User(**user) -def insert_user_with_id( - user: types.user.UserWithoutID -) -> int | None: +def insert_user_with_id(user: types.user.UserWithoutID) -> int | None: """ Returns: Inserted user id or None, if error occurred """ try: return insert_with_auto_increment_id( - users, - user.model_dump() + users, user.model_dump() ) except DuplicateKeyError: return None From ae440418301d89246288457a86b7ef18d9be04e0 Mon Sep 17 00:00:00 2001 From: spotika4 Date: Thu, 22 Aug 2024 00:09:28 +0300 Subject: [PATCH 74/94] feat: mongodb entrypoint --- .gitignore | 1 + configs/test.json | 2 +- docker-compose.yml | 15 ++++++++------- mongo_entrypoint/init.js | 6 ++++++ src/db/types/domain.py | 24 ++++++++++++------------ 5 files changed, 28 insertions(+), 20 deletions(-) create mode 100644 mongo_entrypoint/init.js diff --git a/.gitignore b/.gitignore index 92b4428..dc0ab78 100644 --- a/.gitignore +++ b/.gitignore @@ -162,4 +162,5 @@ cython_debug/ .vscode configs/main.json +mongo_entrypoint/.env tests/node_modules/ diff --git a/configs/test.json b/configs/test.json index c3ed931..1eb437f 100644 --- a/configs/test.json +++ b/configs/test.json @@ -1,6 +1,6 @@ { "database": { - "connect_url": "mongodb://admin:admin@db_test", + "connect_url": "mongodb://test:test@db_test/ELANDB", "name": "ELANDB" }, "auth": { diff --git a/docker-compose.yml b/docker-compose.yml index a9b3dae..de32c3e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,13 +1,12 @@ services: db: image: mongo - volumes: - - /var/lib/elan/mongodb_data:/data/db - environment: - - MONGO_INITDB_ROOT_USERNAME=admin - - MONGO_INITDB_ROOT_PASSWORD=admin ports: - "27017:27017" + env_file: "mongo_entrypoint/.env" + volumes: + - ./mongo_entrypoint:/docker-entrypoint-initdb.d + - /var/lib/elan/mongodb_data:/data/db api: build: context: ./ @@ -22,10 +21,12 @@ services: db_test: image: mongo environment: - - MONGO_INITDB_ROOT_USERNAME=admin - - MONGO_INITDB_ROOT_PASSWORD=admin + - MONGO_ELANDB_USERNAME=test + - MONGO_ELANDB_PASSWORD=test ports: - "42042:42042" + volumes: + - ./mongo_entrypoint:/docker-entrypoint-initdb.d api_test: build: context: ./ diff --git a/mongo_entrypoint/init.js b/mongo_entrypoint/init.js new file mode 100644 index 0000000..db57a95 --- /dev/null +++ b/mongo_entrypoint/init.js @@ -0,0 +1,6 @@ +db = db.getSiblingDB("ELANDB"); +db.createUser({ + user: process.env.MONGO_ELANDB_USERNAME, + pwd: process.env.MONGO_ELANDB_PASSWORD, + roles: [{ role: "readWrite", db: "ELANDB" }] +}); diff --git a/src/db/types/domain.py b/src/db/types/domain.py index 0b8f518..33a74a7 100644 --- a/src/db/types/domain.py +++ b/src/db/types/domain.py @@ -1,12 +1,12 @@ -from typing import Literal -from pydantic import Field - -from utils.schemas import BaseModel - - -TargetType = Literal["user", "group", "contest"] - -class Entity(BaseModel): - id: str = Field(alias='_id') - target_type: TargetType - target_id: int +from typing import Literal +from pydantic import Field + +from utils.schemas import BaseModel + + +TargetType = Literal["user", "group", "contest"] + +class Entity(BaseModel): + id: str = Field(alias='_id') + target_type: TargetType + target_id: int From 54b7a01c358e2b6c80f2ba51facd974b4c8da02e Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 11:13:10 +0300 Subject: [PATCH 75/94] chore: moved .env password conf to compose --- .gitignore | 1 - docker-compose.yml | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index dc0ab78..92b4428 100644 --- a/.gitignore +++ b/.gitignore @@ -162,5 +162,4 @@ cython_debug/ .vscode configs/main.json -mongo_entrypoint/.env tests/node_modules/ diff --git a/docker-compose.yml b/docker-compose.yml index de32c3e..d171dc0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,9 @@ services: image: mongo ports: - "27017:27017" - env_file: "mongo_entrypoint/.env" + environment: + - MONGO_ELANDB_USERNAME= + - MONGO_ELANDB_PASSWORD= volumes: - ./mongo_entrypoint:/docker-entrypoint-initdb.d - /var/lib/elan/mongodb_data:/data/db From 10c69d306bfab81ba709d6a5897f659a6160ba3b Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 11:21:06 +0300 Subject: [PATCH 76/94] ci: improve configs --- .github/workflows/lint.yaml | 3 +++ .github/workflows/test.yaml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 423424a..ad68092 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -7,11 +7,13 @@ on: pull_request: branches: - "*" + workflow_dispatch: jobs: pylint: name: Pylint runs-on: ubuntu-latest + timeout-minutes: 15 steps: - name: Checkout code @@ -40,6 +42,7 @@ jobs: pyright: name: Pyright runs-on: ubuntu-latest + timeout-minutes: 15 steps: - name: Check out code diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index bc15e52..19c23f0 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -7,11 +7,13 @@ on: pull_request: branches: - "*" + workflow_dispatch: jobs: test: name: Run tests runs-on: ubuntu-latest + timeout-minutes: 15 steps: - name: Checkout code From 8ecdbde963f321368d398d94c05b1c031e37fadc Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 13:00:36 +0300 Subject: [PATCH 77/94] ci: selfhosted runner test --- .github/workflows/lint.yaml | 4 ++-- .github/workflows/test.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index ad68092..7a78921 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -12,7 +12,7 @@ on: jobs: pylint: name: Pylint - runs-on: ubuntu-latest + runs-on: self-hosted timeout-minutes: 15 steps: @@ -41,7 +41,7 @@ jobs: fi pyright: name: Pyright - runs-on: ubuntu-latest + runs-on: self-hosted timeout-minutes: 15 steps: diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 19c23f0..183b97f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -12,7 +12,7 @@ on: jobs: test: name: Run tests - runs-on: ubuntu-latest + runs-on: self-hosted timeout-minutes: 15 steps: From 21dae08ba9f3dfd322af85108a48f31a7dfc9080 Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 13:30:37 +0300 Subject: [PATCH 78/94] ci: remove sudo in commands --- .github/workflows/test.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 183b97f..41c1dc8 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -21,8 +21,8 @@ jobs: - name: Build and run Docker Compose run: | - sudo docker compose up -d test - sudo docker compose logs -f test > test_logs.txt + docker compose up -d test + docker compose logs -f test > test_logs.txt continue-on-error: true - name: Check test results From 5f43aaa8bee510249548b920584426f746c7c5ec Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 14:51:09 +0300 Subject: [PATCH 79/94] ci: cleanup after docker use --- .github/workflows/test.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 41c1dc8..4e2513a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -23,6 +23,7 @@ jobs: run: | docker compose up -d test docker compose logs -f test > test_logs.txt + docker compose down -v continue-on-error: true - name: Check test results From 04adf1f1b01231a1569c7f96582d7597559412bc Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 14:54:59 +0300 Subject: [PATCH 80/94] ci: fix test logs on error --- .github/workflows/test.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4e2513a..a3e5f21 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -34,6 +34,7 @@ jobs: else echo "Tests passed" fi + continue-on-error: true - name: Show test logs run: docker compose logs --no-log-prefix test From 2fa45f24056822f163cb26a6f91c6e2df73070aa Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 14:57:32 +0300 Subject: [PATCH 81/94] ci: add docker cleanup --- .github/workflows/test.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index a3e5f21..705e42a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -23,7 +23,6 @@ jobs: run: | docker compose up -d test docker compose logs -f test > test_logs.txt - docker compose down -v continue-on-error: true - name: Check test results @@ -38,3 +37,6 @@ jobs: - name: Show test logs run: docker compose logs --no-log-prefix test + + - name: Cleanup + run: docker compose down -v From 0fd9bd07c08bfb9e62ba6fc081124fe9ee1658b0 Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 15:33:22 +0300 Subject: [PATCH 82/94] style --- src/config/__init__.py | 1 + src/db/client.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/config/__init__.py b/src/config/__init__.py index 85c2e2a..437d86a 100644 --- a/src/config/__init__.py +++ b/src/config/__init__.py @@ -1,5 +1,6 @@ from .config_model import Config + config = Config.load() __all__ = [ diff --git a/src/db/client.py b/src/db/client.py index ff54460..9b1af00 100644 --- a/src/db/client.py +++ b/src/db/client.py @@ -5,6 +5,7 @@ from config import config + logger.info("Connecting to database") client: MongoClient = MongoClient(config.database.connect_url.get_secret_value()) From 22ec6c9a3f62df2294f6f114071cbac4b74e273d Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 15:34:42 +0300 Subject: [PATCH 83/94] refactor: remove unnecessary user info --- src/db/types/user.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/db/types/user.py b/src/db/types/user.py index 3165f00..8605ca0 100644 --- a/src/db/types/user.py +++ b/src/db/types/user.py @@ -6,8 +6,6 @@ class _UserBase(BaseModel): domain: str | None = None first_name: str - last_name: str | None = None - mid_name: str | None = None groups: list[int] = [] roles: list[str] = [] hashed_password: str From 74a68a02547bb3cac4a5eb46d7330a2375c969b2 Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 15:36:54 +0300 Subject: [PATCH 84/94] refactor: remove unnecessary import --- src/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.py b/src/main.py index 98d60fe..3ea6430 100644 --- a/src/main.py +++ b/src/main.py @@ -6,7 +6,6 @@ import db import routers -import routers.service import utils.handlers import utils.response import utils.auth From 1a8e4fb6f0a43ef2c6c26cd241947db6aef603bd Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 15:40:54 +0300 Subject: [PATCH 85/94] refactor(tests): remove superuser --- tests/src/auth.test.ts | 2 +- tests/src/helpers/constants.ts | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/src/auth.test.ts b/tests/src/auth.test.ts index c6dc673..57bab56 100644 --- a/tests/src/auth.test.ts +++ b/tests/src/auth.test.ts @@ -1,7 +1,7 @@ import pactum from "pactum"; import {describe, test, expect} from "@jest/globals"; import { GlobalCounter } from "./helpers/scripts"; -import {ErrorCodes, SuperUser as SuperUserCredentials} from "./helpers/constants"; +import {ErrorCodes} from "./helpers/constants"; pactum.request.setBaseUrl("http://api_test:4242"); diff --git a/tests/src/helpers/constants.ts b/tests/src/helpers/constants.ts index c235b7a..07eea7e 100644 --- a/tests/src/helpers/constants.ts +++ b/tests/src/helpers/constants.ts @@ -9,9 +9,4 @@ const ErrorCodes = { NAME_ALREADY_TAKEN: 8 } -const SuperUser = { - email: "root@gmail.com", - password: "root" -} - -export {SuperUser, ErrorCodes}; +export {ErrorCodes}; From 655d4ffaf4b2a6e0c202299d8cc80c5b6930778b Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 15:43:35 +0300 Subject: [PATCH 86/94] refactor: resolve TODO --- src/db/types/requests.py | 6 +++--- src/utils/response.py | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/db/types/requests.py b/src/db/types/requests.py index 8729e5a..14e9c43 100644 --- a/src/db/types/requests.py +++ b/src/db/types/requests.py @@ -1,7 +1,7 @@ from typing import Annotated -from pydantic import model_validator -from utils.schemas import BaseModel +from pydantic import model_validator, Field +from utils.schemas import BaseModel from .common import is_email @@ -20,6 +20,6 @@ def check_only_one_field(self): return self class AuthSignup(BaseModel): - first_name: str # TODO: set validation here + first_name: str = Field(..., max_length=30) email: Annotated[str, is_email] password: str diff --git a/src/utils/response.py b/src/utils/response.py index efde699..af01383 100644 --- a/src/utils/response.py +++ b/src/utils/response.py @@ -8,7 +8,6 @@ class ErrorCodes(Enum): """ Enum of response error codes. For description see documentation - TODO: set documentation url """ INTERNAL_SERVER_ERROR = 1 UNPROCESSABLE_ENTITY = 2 From ddf6f4b9b6c5cb86ffcf714370df09155bbce6a0 Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 15:50:35 +0300 Subject: [PATCH 87/94] refactor --- src/db/methods/helpers.py | 1 + src/utils/handlers.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/db/methods/helpers.py b/src/db/methods/helpers.py index 6149002..18b89a1 100644 --- a/src/db/methods/helpers.py +++ b/src/db/methods/helpers.py @@ -1,6 +1,7 @@ from typing import Any from pymongo.collection import Collection from pymongo.errors import DuplicateKeyError + from .collections import internal_counters diff --git a/src/utils/handlers.py b/src/utils/handlers.py index 7596549..5cbdc56 100644 --- a/src/utils/handlers.py +++ b/src/utils/handlers.py @@ -4,6 +4,7 @@ from fastapi.responses import JSONResponse from fastapi.exceptions import RequestValidationError from loguru import logger + from . import response From d9998fd03039b0f6732cdc79800d551def28b239 Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 16:12:45 +0300 Subject: [PATCH 88/94] chore: fix mongodb credentials --- docker-compose.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index d171dc0..1bf21b6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,8 @@ services: environment: - MONGO_ELANDB_USERNAME= - MONGO_ELANDB_PASSWORD= + - MONGO_INITDB_ROOT_USERNAME= + - MONGO_INITDB_ROOT_PASSWORD= volumes: - ./mongo_entrypoint:/docker-entrypoint-initdb.d - /var/lib/elan/mongodb_data:/data/db @@ -25,6 +27,8 @@ services: environment: - MONGO_ELANDB_USERNAME=test - MONGO_ELANDB_PASSWORD=test + - MONGO_INITDB_ROOT_USERNAME=admin + - MONGO_INITDB_ROOT_PASSWORD=admin ports: - "42042:42042" volumes: From 4116be52aebf091ee61656bab2554023bfb77687 Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 16:23:16 +0300 Subject: [PATCH 89/94] fix: fix test mongodb ports --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1bf21b6..a53bf37 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,7 +30,7 @@ services: - MONGO_INITDB_ROOT_USERNAME=admin - MONGO_INITDB_ROOT_PASSWORD=admin ports: - - "42042:42042" + - "42042:27017" volumes: - ./mongo_entrypoint:/docker-entrypoint-initdb.d api_test: From ee81a6e584255ed9abbb3e8f0d7cede0218595bb Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 16:57:59 +0300 Subject: [PATCH 90/94] refactor --- src/db/types/user.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/db/types/user.py b/src/db/types/user.py index 8605ca0..fb5eadf 100644 --- a/src/db/types/user.py +++ b/src/db/types/user.py @@ -6,6 +6,7 @@ class _UserBase(BaseModel): domain: str | None = None first_name: str + last_name: str | None = None groups: list[int] = [] roles: list[str] = [] hashed_password: str From 5b1464b244cb0066835963e6c92c3801a7122a2b Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 22:13:43 +0300 Subject: [PATCH 91/94] refactor --- src/db/methods/collections/collections.py | 2 +- src/routers/auth.py | 8 ++------ src/utils/auth/auth.py | 8 ++++---- src/utils/response.py | 4 +--- tests/src/helpers/constants.ts | 20 +++++++++----------- 5 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/db/methods/collections/collections.py b/src/db/methods/collections/collections.py index b204ca3..709e541 100644 --- a/src/db/methods/collections/collections.py +++ b/src/db/methods/collections/collections.py @@ -15,4 +15,4 @@ users.create_index([("email", 1)], unique=True, name="email") -domains.create_index([("target_id", 1)], unique=True, name="target_id") +# domains.create_index([("target_id", 1)], unique=True, name="target_id") diff --git a/src/routers/auth.py b/src/routers/auth.py index 872bede..9d8183f 100644 --- a/src/routers/auth.py +++ b/src/routers/auth.py @@ -12,9 +12,7 @@ @router.post("/signup", response_model=SuccessfulResponse[RS.AuthSignup]) -async def signup( - request: RQ.AuthSignup -): +async def signup(request: RQ.AuthSignup): hashed_password = utils.auth.hash_password(request.password) inserted_user_id = methods.users.insert_user_with_id( @@ -34,9 +32,7 @@ async def signup( return utils.auth.create_jwt_pair_by_user_id(inserted_user_id) @router.post("/signin", response_model=SuccessfulResponse[RS.AuthSignin]) -async def signin( - siginin_input: RQ.AuthSignin -): +async def signin(siginin_input: RQ.AuthSignin): user: types.user.User | None = None if siginin_input.id: user = methods.users.get(siginin_input.id) diff --git a/src/utils/auth/auth.py b/src/utils/auth/auth.py index 68674eb..5cc0090 100644 --- a/src/utils/auth/auth.py +++ b/src/utils/auth/auth.py @@ -25,8 +25,8 @@ def get_auth_header_credentials( if len(credentials) != 2: raise response.ErrorResponse( - code=response.ErrorCodes.INCORRECT_AUTH_HEADER_FOMAT, - http_status_code=http_status.HTTP_422_UNPROCESSABLE_ENTITY, + code=response.ErrorCodes.TOKEN_VALIDATION_FAILED, + http_status_code=http_status.HTTP_401_UNAUTHORIZED, message=error_message ) @@ -34,8 +34,8 @@ def get_auth_header_credentials( if current_prefix != prefix: raise response.ErrorResponse( - code=response.ErrorCodes.INCORRECT_AUTH_HEADER_FOMAT, - http_status_code=http_status.HTTP_422_UNPROCESSABLE_ENTITY, + code=response.ErrorCodes.TOKEN_VALIDATION_FAILED, + http_status_code=http_status.HTTP_401_UNAUTHORIZED, message=error_message ) diff --git a/src/utils/response.py b/src/utils/response.py index af01383..b4c3aaf 100644 --- a/src/utils/response.py +++ b/src/utils/response.py @@ -40,9 +40,7 @@ def __init__( self.auto_message = auto_message -T = TypeVar("T", bound=BaseModel | None) - -class SuccessfulResponse(BaseModel, Generic[T]): +class SuccessfulResponse[T: BaseModel | None](BaseModel): @model_validator(mode="before") @classmethod def before_validation(cls, data) -> dict[str, Any]: diff --git a/tests/src/helpers/constants.ts b/tests/src/helpers/constants.ts index 07eea7e..d003ac6 100644 --- a/tests/src/helpers/constants.ts +++ b/tests/src/helpers/constants.ts @@ -1,12 +1,10 @@ -const ErrorCodes = { - INTERNAL_SERVER_ERROR: 1, - UNPROCESSABLE_ENTITY: 2, - TOKEN_EXPIRED: 3, - TOKEN_VALIDATION_FAILED: 4, - ENTITY_NOT_FOUND: 5, - INCORRECT_AUTH_HEADER_FOMAT: 6, - ACCESS_DENIED: 7, - NAME_ALREADY_TAKEN: 8 +export enum ErrorCodes { + INTERNAL_SERVER_ERROR = 1, + UNPROCESSABLE_ENTITY, + TOKEN_EXPIRED, + TOKEN_VALIDATION_FAILED, + ENTITY_NOT_FOUND, + INCORRECT_AUTH_HEADER_FOMAT, + ACCESS_DENIED, + NAME_ALREADY_TAKEN } - -export {ErrorCodes}; From c2e38abcf4265e6854d20fdc5f8c9f204aee679a Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 22:20:48 +0300 Subject: [PATCH 92/94] style --- src/utils/response.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/response.py b/src/utils/response.py index b4c3aaf..6b65ff3 100644 --- a/src/utils/response.py +++ b/src/utils/response.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import Any, Generic, Literal, TypeVar +from typing import Any, Literal from pydantic import BaseModel, model_validator, model_serializer From f1cb1a2a5cde6b4e4cb76c62c50a6b1e667e31aa Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 22:42:36 +0300 Subject: [PATCH 93/94] refactor: change BaseModel source --- src/utils/response.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/response.py b/src/utils/response.py index 6b65ff3..8bc0fef 100644 --- a/src/utils/response.py +++ b/src/utils/response.py @@ -1,8 +1,8 @@ from enum import Enum from typing import Any, Literal +from pydantic import model_validator, model_serializer -from pydantic import BaseModel, model_validator, model_serializer - +from utils.schemas import BaseModel class ErrorCodes(Enum): """ From c3267a3779c43c3f40ee2d20b1540435a465e481 Mon Sep 17 00:00:00 2001 From: Spotika Date: Thu, 22 Aug 2024 22:44:30 +0300 Subject: [PATCH 94/94] style: replace by response --- src/routers/auth.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/routers/auth.py b/src/routers/auth.py index 9d8183f..2b251b3 100644 --- a/src/routers/auth.py +++ b/src/routers/auth.py @@ -32,16 +32,16 @@ async def signup(request: RQ.AuthSignup): return utils.auth.create_jwt_pair_by_user_id(inserted_user_id) @router.post("/signin", response_model=SuccessfulResponse[RS.AuthSignin]) -async def signin(siginin_input: RQ.AuthSignin): +async def signin(request: RQ.AuthSignin): user: types.user.User | None = None - if siginin_input.id: - user = methods.users.get(siginin_input.id) - elif siginin_input.domain: - entity = methods.domains.resolve_entity(siginin_input.domain) + if request.id: + user = methods.users.get(request.id) + elif request.domain: + entity = methods.domains.resolve_entity(request.domain) if entity and entity.target_type == "user": user = methods.users.get(entity.target_id) - elif siginin_input.email: - user = methods.users.get_by_email(siginin_input.email) + elif request.email: + user = methods.users.get_by_email(request.email) if user is None: raise ErrorResponse( @@ -50,7 +50,7 @@ async def signin(siginin_input: RQ.AuthSignin): message="User not found" ) - if not utils.auth.verify_password(siginin_input.password, user.hashed_password): + if not utils.auth.verify_password(request.password, user.hashed_password): raise ErrorResponse( code=ErrorCodes.ACCESS_DENIED, http_status_code=http_status.HTTP_403_FORBIDDEN,