├── .gitignore ├── backend ├── .env.example ├── Dockerfile ├── app │ ├── __init__.py │ ├── api │ │ ├── __init__.py │ │ ├── api.py │ │ ├── deps │ │ │ ├── auth.py │ │ │ └── db.py │ │ └── endpoints │ │ │ ├── __init__.py │ │ │ ├── demo.py │ │ │ └── user.py │ ├── core │ │ ├── __init__.py │ │ ├── config.py │ │ ├── extras │ │ │ ├── __init__.py │ │ │ └── typehints.py │ │ ├── security.py │ │ └── utils.py │ ├── crud │ │ ├── __init__.py │ │ └── crud_user.py │ ├── db │ │ ├── __init__.py │ │ ├── mongodb.py │ │ └── mongodb_utils.py │ ├── main.py │ ├── models │ │ ├── __init__.py │ │ ├── core.py │ │ ├── jwt.py │ │ └── user.py │ └── services │ │ ├── __init__.py │ │ ├── authentication.py │ │ └── registration.py ├── requirements.txt └── tests │ ├── __init__.py │ ├── conftest.py │ └── test_users.py ├── docker-compose.yaml ├── frontend ├── .eslintignore ├── .eslintrc.cjs ├── .npmrc ├── .prettierignore ├── .prettierrc ├── Dockerfile ├── package-lock.json ├── package.json ├── postcss.config.cjs ├── src │ ├── app.css │ ├── app.html │ ├── lib │ │ ├── components │ │ │ └── Nav.svelte │ │ ├── config.js │ │ └── stores.js │ └── routes │ │ ├── +layout.svelte │ │ ├── +page.svelte │ │ ├── articles │ │ └── +page.svelte │ │ ├── contact │ │ └── +page.svelte │ │ └── tutorials │ │ └── +page.svelte ├── static │ └── favicon.png ├── svelte.config.js ├── tailwind.config.cjs └── vite.config.js └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | frontend/.svelte-kit 2 | frontend/node_modules -------------------------------------------------------------------------------- /backend/.env.example: -------------------------------------------------------------------------------- 1 | SECRET_KEY=EXMAPLESECRETKEY 2 | 3 | MONGODB_HOST=mongodb 4 | MONGODB_PORT=27017 5 | MONGODB_USER=mongouser 6 | MONGODB_PASSWORD=mongopassword 7 | MONGODB_DB=app 8 | -------------------------------------------------------------------------------- /backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10.8 2 | 3 | WORKDIR /usr/src/app 4 | 5 | ENV PYTHONDONTWRITEBYTECODE 1 6 | ENV PYTHONBUFFERED 1 7 | 8 | RUN pip install --upgrade pip 9 | COPY ./requirements.txt ./requirements.txt 10 | RUN pip install -r requirements.txt 11 | 12 | COPY . . -------------------------------------------------------------------------------- /backend/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartgoo/sveltekit-fastapi-mongodb/1e7be3a207bec3012237f574158b6e1e51371211/backend/app/__init__.py -------------------------------------------------------------------------------- /backend/app/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartgoo/sveltekit-fastapi-mongodb/1e7be3a207bec3012237f574158b6e1e51371211/backend/app/api/__init__.py -------------------------------------------------------------------------------- /backend/app/api/api.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | from app.api.endpoints import demo 4 | from app.api.endpoints import user 5 | 6 | api_router = APIRouter() 7 | 8 | api_router.include_router(demo.router, prefix="/demo", tags=["demo"]) 9 | api_router.include_router(user.router, prefix="/users", tags=["user"]) -------------------------------------------------------------------------------- /backend/app/api/deps/auth.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from motor.motor_asyncio import AsyncIOMotorClient 4 | 5 | from fastapi import Depends, HTTPException, status 6 | from fastapi.security import OAuth2PasswordBearer 7 | 8 | from app.core.config import settings 9 | from app.db.mongodb import db 10 | from app import services, models, crud 11 | from .db import get_database 12 | 13 | 14 | oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{settings.API_V1_STR}/users/login/token/") 15 | 16 | 17 | async def get_user_from_token( 18 | token: str = Depends(oauth2_scheme), 19 | db: AsyncIOMotorClient = Depends(get_database), 20 | ) -> Optional[models.UserInDB]: 21 | try: 22 | email = services.authentication.get_email_from_token(token=token, secret_key=str(settings.SECRET_KEY)) 23 | user = await crud.user.get_by_email(db=db, email=email) 24 | except Exception as e: 25 | raise e 26 | return user 27 | 28 | 29 | def get_current_active_user(current_user: models.UserInDB = Depends(get_user_from_token)) -> Optional[models.UserInDB]: 30 | if not current_user: 31 | raise HTTPException( 32 | status_code=status.HTTP_401_UNAUTHORIZED, 33 | detail="No authenticated user.", 34 | headers={"WWW-Authenticate": "Bearer"}, 35 | ) 36 | if not current_user.is_active: 37 | raise HTTPException( 38 | status_code=status.HTTP_401_UNAUTHORIZED, 39 | detail="Not an active user.", 40 | headers={"WWW-Authenticate": "Bearer"}, 41 | ) 42 | return current_user 43 | -------------------------------------------------------------------------------- /backend/app/api/deps/db.py: -------------------------------------------------------------------------------- 1 | from motor.motor_asyncio import AsyncIOMotorClient 2 | 3 | from app.db.mongodb import db 4 | from app.core.config import settings 5 | 6 | async def get_database() -> AsyncIOMotorClient: 7 | return db.client[settings.MONGODB_DB] -------------------------------------------------------------------------------- /backend/app/api/endpoints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartgoo/sveltekit-fastapi-mongodb/1e7be3a207bec3012237f574158b6e1e51371211/backend/app/api/endpoints/__init__.py -------------------------------------------------------------------------------- /backend/app/api/endpoints/demo.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router = APIRouter() 4 | 5 | @router.get("/posts") 6 | def get_blog_posts(): 7 | return [{ 8 | 'title': 'Hello World', 9 | 'date': '1/1/2021', 10 | 'text': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.' 11 | 12 | }] -------------------------------------------------------------------------------- /backend/app/api/endpoints/user.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter, Depends, HTTPException 2 | from fastapi.security import OAuth2PasswordRequestForm 3 | from fastapi import status 4 | 5 | from app import crud, models, services 6 | from app.db.mongodb import AsyncIOMotorClient 7 | from app.api.deps.db import get_database 8 | from app.api.deps.auth import get_current_active_user 9 | 10 | 11 | router = APIRouter() 12 | 13 | 14 | @router.post('/', name="user:create", response_model=models.UserPublic, status_code=status.HTTP_201_CREATED) 15 | async def create_user( 16 | obj_in: models.UserCreate, 17 | db: AsyncIOMotorClient = Depends(get_database), 18 | ): 19 | """ 20 | Create new user 21 | """ 22 | obj_in = models.UserCreate(**obj_in.dict()) 23 | user = await services.registration.register_new_user(db, obj_in) 24 | access_token = models.AccessToken( 25 | access_token = services.authentication.create_access_token_for_user(user=user), token_type="bearer" 26 | ) 27 | return models.UserPublic(**user.dict(), access_token=access_token) 28 | 29 | 30 | @router.post('/login/token', name="user:login", response_model=models.AccessToken) 31 | async def login_user( 32 | form_data: OAuth2PasswordRequestForm = Depends(OAuth2PasswordRequestForm), 33 | db: AsyncIOMotorClient = Depends(get_database), 34 | ) -> models.AccessToken: 35 | """ 36 | Authentication endpoint 37 | """ 38 | token = await services.authentication.authenticate_user(db=db, email=form_data.username, password=form_data.password) 39 | return token 40 | 41 | 42 | @router.get("/me/", response_model=models.UserPublic, name="user:me") 43 | async def get_currently_authenticated_user(current_user: models.UserInDB = Depends(get_current_active_user)) -> models.UserPublic: 44 | """ 45 | Get current user 46 | """ 47 | return current_user -------------------------------------------------------------------------------- /backend/app/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartgoo/sveltekit-fastapi-mongodb/1e7be3a207bec3012237f574158b6e1e51371211/backend/app/core/__init__.py -------------------------------------------------------------------------------- /backend/app/core/config.py: -------------------------------------------------------------------------------- 1 | import secrets 2 | import os 3 | from typing import Any, Dict, List, Optional, Union 4 | 5 | from pydantic import AnyHttpUrl, BaseSettings, EmailStr, HttpUrl 6 | from databases import DatabaseURL 7 | 8 | 9 | class Settings(BaseSettings): 10 | API_V1_STR: str = "/api/v1" 11 | 12 | # JWT Token Config 13 | SECRET_KEY: str = os.environ.get('SECRET_KEY') 14 | ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7 #7 days 15 | JWT_ALGORITHM: str = "HS256" 16 | JWT_AUDIENCE: str = "smartgoo:auth" 17 | JWT_TOKEN_PREFIX = "Bearer" 18 | 19 | SERVER_NAME: str = '' 20 | SERVER_HOST: str = '' 21 | 22 | BACKEND_CORS_ORIGINS: List[AnyHttpUrl] = ["http://localhost:5173"] 23 | 24 | PROJECT_NAME: str = 'SvelteKit-FastAPI-MongoDB Starter Template' 25 | SENTRY_DSN: Optional[HttpUrl] = None 26 | 27 | # MongoDB config 28 | MONGODB_MAX_CONNECTIONS_COUNT: int = 10 29 | MONGODB_MIN_CONNECTIONS_COUNT: int = 10 30 | MONGODB_HOST: str = os.environ.get('MONGODB_HOST') 31 | MONGODB_PORT: int = os.environ.get('MONGODB_PORT') 32 | MONGODB_USER: str = os.environ.get('MONGODB_USER') 33 | MONGODB_PASSWORD: str = os.environ.get('MONGODB_PASSWORD') 34 | MONGODB_DB: str = os.environ.get('MONGODB_DB') 35 | MONGODB_CONN_STRING = DatabaseURL( 36 | f"mongodb://{MONGODB_USER}:{MONGODB_PASSWORD}@{MONGODB_HOST}:{MONGODB_PORT}" 37 | ) 38 | 39 | # SMTP config for sending emails 40 | SMTP_TLS: bool = True 41 | SMTP_PORT: Optional[int] = None 42 | SMTP_HOST: Optional[str] = None 43 | SMTP_USER: Optional[str] = None 44 | SMTP_PASSWORD: Optional[str] = None 45 | EMAILS_FROM_EMAIL: Optional[EmailStr] = None 46 | EMAILS_FROM_NAME: Optional[str] = None 47 | 48 | EMAIL_RESET_TOKEN_EXPIRE_HOURS: int = 48 49 | EMAIL_TEMPLATES_DIR: str = "/app/app/email-templates/build" 50 | EMAILS_ENABLED: bool = False 51 | 52 | EMAIL_TEST_USER: EmailStr = "test@example.com" 53 | FIRST_SUPERUSER: EmailStr = 'test@example.com' 54 | FIRST_SUPERUSER_PASSWORD: str = '' 55 | USERS_OPEN_REGISTRATION: bool = False 56 | 57 | # MongodDB Collections 58 | USERS_COLLECTION = 'users' 59 | 60 | 61 | class Config: 62 | case_sensitive = True 63 | 64 | 65 | settings = Settings() -------------------------------------------------------------------------------- /backend/app/core/extras/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartgoo/sveltekit-fastapi-mongodb/1e7be3a207bec3012237f574158b6e1e51371211/backend/app/core/extras/__init__.py -------------------------------------------------------------------------------- /backend/app/core/extras/typehints.py: -------------------------------------------------------------------------------- 1 | from bson.objectid import ObjectId 2 | 3 | class MongoIDType(ObjectId): 4 | """ 5 | A custom type for MongoDB. Refer to this repo: 6 | https://github.com/mongodb-developer/mongodb-with-fastapi 7 | https://developer.mongodb.com/quickstart/python-quickstart-fastapi/ 8 | """ 9 | @classmethod 10 | def __get_validators__(cls): 11 | yield cls.validate 12 | 13 | @classmethod 14 | def validate(cls, v): 15 | if not ObjectId.is_valid(v): 16 | raise ValueError("Invalid objectid") 17 | return ObjectId(v) 18 | 19 | @classmethod 20 | def __modify_schema__(cls, field_schema): 21 | field_schema.update(type="string") -------------------------------------------------------------------------------- /backend/app/core/security.py: -------------------------------------------------------------------------------- 1 | from passlib.context import CryptContext 2 | 3 | pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") 4 | 5 | def get_password_hash(password: str) -> str: 6 | return pwd_context.hash(password) -------------------------------------------------------------------------------- /backend/app/core/utils.py: -------------------------------------------------------------------------------- 1 | from typing import Callable, Collection 2 | from fastapi import FastAPI 3 | 4 | from app.db.mongodb_utils import connect_to_mongo, close_mongo_connection 5 | 6 | 7 | def create_start_app_handler(app: FastAPI) -> Callable: 8 | def start_app() -> None: 9 | connect_to_mongo(app) 10 | 11 | return start_app 12 | 13 | 14 | def create_stop_app_handler(app: FastAPI) -> Callable: 15 | def stop_app() -> None: 16 | close_mongo_connection(app) 17 | 18 | return stop_app -------------------------------------------------------------------------------- /backend/app/crud/__init__.py: -------------------------------------------------------------------------------- 1 | from app.crud.crud_user import user -------------------------------------------------------------------------------- /backend/app/crud/crud_user.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic import EmailStr 4 | 5 | from app.core.config import settings 6 | from app.db.mongodb import AsyncIOMotorClient 7 | from app import models 8 | 9 | 10 | class CRUDUser(): 11 | collection: str = settings.USERS_COLLECTION 12 | 13 | async def get_by_email(self, db: AsyncIOMotorClient, email: EmailStr) -> Optional[models.UserInDB]: 14 | user = await db[self.collection].find_one({"email": email}) 15 | if not user: 16 | return None 17 | 18 | return models.UserInDB(**user) 19 | 20 | async def create(self, db: AsyncIOMotorClient, user_in: models.UserCreate) -> models.UserInDB: 21 | doc = await db[self.collection].insert_one(user_in.dict()) 22 | user_out = await db[self.collection].find_one({"_id": doc.inserted_id}) 23 | return models.UserInDB(**user_out) 24 | 25 | async def update(self, db: AsyncIOMotorClient, user_in: models.UserUpdate) -> models.UserInDB: 26 | # TODO 27 | pass 28 | 29 | async def delete(self, db: AsyncIOMotorClient): 30 | # TODO 31 | pass 32 | 33 | 34 | user = CRUDUser() -------------------------------------------------------------------------------- /backend/app/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartgoo/sveltekit-fastapi-mongodb/1e7be3a207bec3012237f574158b6e1e51371211/backend/app/db/__init__.py -------------------------------------------------------------------------------- /backend/app/db/mongodb.py: -------------------------------------------------------------------------------- 1 | from motor.motor_asyncio import AsyncIOMotorClient 2 | 3 | from app.core.config import settings 4 | 5 | class DataBase: 6 | client: AsyncIOMotorClient = None 7 | 8 | 9 | db = DataBase() 10 | 11 | 12 | async def get_database() -> AsyncIOMotorClient: 13 | return db.client[settings.MONGODB_DB] -------------------------------------------------------------------------------- /backend/app/db/mongodb_utils.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from motor.motor_asyncio import AsyncIOMotorClient 4 | 5 | from app.core.config import settings 6 | from app.db.mongodb import db 7 | 8 | 9 | def connect_to_mongo(app: FastAPI): 10 | print('connecting to database') 11 | db.client = AsyncIOMotorClient(str(settings.MONGODB_CONN_STRING), 12 | maxPoolSize=settings.MONGODB_MAX_CONNECTIONS_COUNT, 13 | minPoolSize=settings.MONGODB_MIN_CONNECTIONS_COUNT) 14 | app.state._db_client = db.client 15 | print('connected') 16 | 17 | 18 | def close_mongo_connection(app: FastAPI): 19 | print('closing database connection') 20 | db.client.close() 21 | print('closed') 22 | -------------------------------------------------------------------------------- /backend/app/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.middleware.cors import CORSMiddleware 3 | 4 | 5 | from app.core import utils 6 | from app.api.api import api_router 7 | from app.core.config import settings 8 | from app.db.mongodb_utils import close_mongo_connection, connect_to_mongo 9 | 10 | 11 | app = FastAPI( 12 | title=settings.PROJECT_NAME, 13 | ) 14 | 15 | # Set all CORS enabled origins 16 | if settings.BACKEND_CORS_ORIGINS: 17 | app.add_middleware( 18 | CORSMiddleware, 19 | allow_origins=settings.BACKEND_CORS_ORIGINS, 20 | allow_credentials=True, 21 | allow_methods=["*"], 22 | allow_headers=["*"], 23 | ) 24 | 25 | app.add_event_handler("startup", utils.create_start_app_handler(app)) 26 | app.add_event_handler("shutdown", utils.create_stop_app_handler(app)) 27 | 28 | app.include_router(api_router, prefix=settings.API_V1_STR) -------------------------------------------------------------------------------- /backend/app/models/__init__.py: -------------------------------------------------------------------------------- 1 | from .user import UserBase, UserCreate, UserUpdate, UserPasswordUpdate, UserInDB, UserPublic 2 | from .jwt import JWTMeta, JWTCreds, JWTPayload, AccessToken -------------------------------------------------------------------------------- /backend/app/models/core.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from datetime import datetime 3 | 4 | from bson.objectid import ObjectId 5 | from pydantic import BaseModel, Field, validator 6 | 7 | from app.core.extras.typehints import MongoIDType 8 | 9 | 10 | class CoreModel(BaseModel): 11 | """ 12 | Any common logic to be shared by all models goes here 13 | """ 14 | pass 15 | 16 | 17 | class DateTimeModelMixin(BaseModel): 18 | created_at: Optional[datetime] 19 | updated_at: Optional[datetime] 20 | 21 | @validator("created_at", "updated_at", pre=True) 22 | def default_datetime(cls, value: datetime) -> datetime: 23 | return value or datetime.now() 24 | 25 | 26 | class IDModelMixin(BaseModel): 27 | """ 28 | Allows a model to read the MongoDB _id in 29 | TODO figure out better way to handle this 30 | """ 31 | id: MongoIDType = Field(alias='_id') 32 | 33 | class Config: 34 | # Allows `id` or `_id` input to popluate the field `id` 35 | allow_population_by_field_name = True 36 | 37 | # Allows use of our custom type `MongoIDType` 38 | arbitrary_types_allowed = True 39 | 40 | # Since MongoDB ObjectIDs are BSON, this allows encoding to JSON 41 | json_encoders = {ObjectId: str} -------------------------------------------------------------------------------- /backend/app/models/jwt.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta 2 | from pydantic import EmailStr 3 | 4 | from app.core.config import settings 5 | from app.models.core import CoreModel 6 | 7 | 8 | class JWTMeta(CoreModel): 9 | iss: str = "smartgoo.io" 10 | aud: str = settings.JWT_AUDIENCE 11 | iat: float = datetime.timestamp(datetime.utcnow()) 12 | exp: float = datetime.timestamp(datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)) 13 | 14 | 15 | class JWTCreds(CoreModel): 16 | """How we'll identify users""" 17 | sub: EmailStr 18 | # email: EmailStr 19 | 20 | 21 | class JWTPayload(JWTMeta, JWTCreds): 22 | """ 23 | JWT Payload right before it's encoded - combine meta and username 24 | """ 25 | pass 26 | 27 | 28 | class AccessToken(CoreModel): 29 | access_token: str 30 | token_type: str 31 | -------------------------------------------------------------------------------- /backend/app/models/user.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic import EmailStr, constr 5 | 6 | from .jwt import AccessToken 7 | from app.models.core import CoreModel, DateTimeModelMixin, IDModelMixin 8 | 9 | 10 | class UserBase(CoreModel): 11 | """ 12 | Leaving off password and salt from base model 13 | """ 14 | email: EmailStr 15 | first_name: str 16 | last_name: str 17 | email_verified: bool = False 18 | is_active: bool = True 19 | is_superuser: bool = False 20 | 21 | 22 | class UserCreate(UserBase, DateTimeModelMixin): 23 | """ 24 | Email, password, first, last names are required for registering a new user 25 | """ 26 | email: EmailStr 27 | password: constr(min_length=8, max_length=100) 28 | first_name: str 29 | last_name: str 30 | 31 | 32 | class UserUpdate(UserBase): 33 | """ 34 | Users are allowed to update their name and activation status 35 | """ 36 | # TODO: allow user to change email address 37 | first_name: Optional[str] 38 | last_name: Optional[str] 39 | 40 | 41 | class UserPasswordUpdate(CoreModel): 42 | """ 43 | Users can change their password 44 | """ 45 | password: constr(min_length=8, max_length=100) 46 | salt: str 47 | 48 | 49 | class UserInDB(IDModelMixin, DateTimeModelMixin, UserBase): 50 | """ 51 | Add in id, created_at, updated_at, and user's password and salt 52 | """ 53 | password: constr(min_length=7, max_length=100) 54 | salt: str 55 | 56 | 57 | class UserPublic(IDModelMixin, DateTimeModelMixin, UserBase): 58 | access_token: Optional[AccessToken] 59 | 60 | -------------------------------------------------------------------------------- /backend/app/services/__init__.py: -------------------------------------------------------------------------------- 1 | from app.services.registration import registration 2 | from app.services.authentication import authentication -------------------------------------------------------------------------------- /backend/app/services/authentication.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta 2 | from typing import Optional 3 | 4 | from fastapi import HTTPException, status 5 | import jwt 6 | import bcrypt 7 | from passlib.context import CryptContext 8 | from pydantic import EmailStr, ValidationError 9 | 10 | from app.core.config import settings 11 | from app import models, crud 12 | from app.db.mongodb import AsyncIOMotorClient 13 | 14 | 15 | pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") 16 | 17 | class AuthenticationService(): 18 | """ 19 | An API to handle user authentication. 20 | Abstracts out the lower level operations in the authentication flow. 21 | Handles... # TODO - see registration.py 22 | """ 23 | def create_salt_and_hashed_password(self, plaintext_password: str) -> models.UserPasswordUpdate: 24 | salt = self.generate_salt() 25 | hashed_password = self.hash_password(password=plaintext_password, salt=salt) 26 | 27 | return models.UserPasswordUpdate(salt=salt, password=hashed_password) 28 | 29 | def generate_salt(self) -> str: 30 | """ 31 | Generate a random salt to be used when hashing the password 32 | """ 33 | return bcrypt.gensalt().decode() 34 | 35 | def hash_password(self, password: str, salt: str) -> str: 36 | """ 37 | Hash given password with salt 38 | """ 39 | return pwd_context.hash(password + salt) 40 | 41 | def verify_password(self, password: str, salt: str, hashed_password: str) -> bool: 42 | """ 43 | Verify the saved password hash against the given password and salt 44 | """ 45 | return pwd_context.verify(password + salt, hashed_password) 46 | 47 | def create_access_token_for_user( 48 | self, 49 | *, 50 | user: models.UserInDB, 51 | secret_key: str = settings.SECRET_KEY, 52 | audience: str = settings.JWT_AUDIENCE, 53 | expires_in: int = settings.ACCESS_TOKEN_EXPIRE_MINUTES 54 | ) -> str: 55 | """ 56 | Creates JWT for a user 57 | """ 58 | if not user or not isinstance(user, models.UserInDB): 59 | return None 60 | 61 | jwt_meta = models.JWTMeta( 62 | aud=audience, 63 | iat=datetime.timestamp(datetime.utcnow()), 64 | exp=datetime.timestamp(datetime.utcnow() + timedelta(minutes=expires_in)), 65 | ) 66 | 67 | jwt_creds = models.JWTCreds(sub=user.email) 68 | 69 | token_payload = models.JWTPayload( 70 | **jwt_meta.dict(), 71 | **jwt_creds.dict(), 72 | ) 73 | return jwt.encode(token_payload.dict(), secret_key, algorithm=settings.JWT_ALGORITHM) 74 | 75 | async def authenticate_user(self, db: AsyncIOMotorClient, email: EmailStr, password: str) -> models.AccessToken: 76 | """ 77 | Authentication method to auth user and return a JWT token 78 | """ 79 | # Try to get user from database 80 | user = await crud.user.get_by_email(db=db, email=email) 81 | 82 | # if no user exists with that email, or password is invalid... raise error 83 | if not user or not self.verify_password(password=password, salt=user.salt, hashed_password=user.password): 84 | raise HTTPException( 85 | status_code=status.HTTP_401_UNAUTHORIZED, 86 | detail="Authentication was unsuccessful.", 87 | headers={"WWW-Authenticate": "Bearer"}, 88 | ) 89 | 90 | # create jwt 91 | return models.AccessToken(access_token=self.create_access_token_for_user(user=user), token_type="bearer") 92 | 93 | def get_email_from_token(self, *, token: str, secret_key: str) -> Optional[str]: 94 | """ 95 | Decode a provided JWT token and get the email address 96 | """ 97 | try: 98 | decoded_token = jwt.decode(token, str(settings.SECRET_KEY), audience=settings.JWT_AUDIENCE, algorithms=[settings.JWT_ALGORITHM]) 99 | payload = models.JWTPayload(**decoded_token) 100 | except (jwt.PyJWTError, ValidationError): 101 | raise HTTPException( 102 | status_code=status.HTTP_401_UNAUTHORIZED, 103 | detail="Could not validate token credentials.", 104 | headers={"WWW-Authenticate": "Bearer"}, 105 | ) 106 | return payload.sub 107 | 108 | 109 | authentication = AuthenticationService() -------------------------------------------------------------------------------- /backend/app/services/registration.py: -------------------------------------------------------------------------------- 1 | from fastapi import HTTPException 2 | 3 | from app import crud, models, services 4 | from app.db.mongodb import AsyncIOMotorClient 5 | 6 | 7 | class RegistrationService(): 8 | """ 9 | An API to handle user registration. 10 | Abstracts out the lower level operations in the registration flow. 11 | Handles crud operations, celery worker delegation, emails, etc. 12 | """ 13 | # TODO - verify email before allowing login 14 | 15 | async def register_new_user(self, db: AsyncIOMotorClient, user_in: models.UserCreate) -> models.UserInDB: 16 | """ 17 | Register a new user account and hash password with salt 18 | """ 19 | # make sure email isn't already taken, raise exception if it is 20 | user = await crud.user.get_by_email(db, email=user_in.email) 21 | if user: 22 | raise HTTPException(status_code=422, detail="Email address already in use") 23 | 24 | user_password_update = services.authentication.create_salt_and_hashed_password(plaintext_password=user_in.password) 25 | new_user_params = user_in.copy(update=user_password_update.dict()) 26 | user = await crud.user.create(db, user_in=new_user_params) 27 | return user 28 | 29 | 30 | registration = RegistrationService() -------------------------------------------------------------------------------- /backend/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.2 2 | bcrypt==4.0.1 3 | cffi==1.15.1 4 | click==8.1.3 5 | cryptography==38.0.1 6 | databases==0.6.1 7 | dnspython==2.2.1 8 | email-validator==1.3.0 9 | fastapi==0.85.1 10 | greenlet==1.1.3.post0 11 | h11==0.14.0 12 | idna==3.4 13 | jwt==1.3.1 14 | motor==3.0.0 15 | passlib==1.7.4 16 | pycparser==2.21 17 | pydantic==1.10.2 18 | pymongo==4.3.2 19 | python-multipart==0.0.5 20 | six==1.16.0 21 | sniffio==1.3.0 22 | SQLAlchemy==1.4.42 23 | starlette==0.20.4 24 | typing_extensions==4.4.0 25 | uvicorn==0.19.0 26 | -------------------------------------------------------------------------------- /backend/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartgoo/sveltekit-fastapi-mongodb/1e7be3a207bec3012237f574158b6e1e51371211/backend/tests/__init__.py -------------------------------------------------------------------------------- /backend/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from fastapi import FastAPI, Depends 4 | 5 | import pytest 6 | from asgi_lifespan import LifespanManager 7 | 8 | from fastapi import FastAPI 9 | from httpx import AsyncClient 10 | from databases import Database 11 | 12 | from app.db.mongodb import db 13 | from app.api.deps.db import get_database 14 | from app import models, services, crud 15 | from app.core.config import settings 16 | 17 | 18 | # Setup pytest-asyncio functions to help with closing the event loop properly. 19 | @pytest.fixture 20 | def event_loop(): 21 | yield asyncio.get_event_loop() 22 | 23 | def pytest_sessionfinish(session, exitstatus): 24 | asyncio.get_event_loop().close() 25 | 26 | 27 | # Create a new application for testing 28 | @pytest.fixture 29 | def app() -> FastAPI: 30 | def get_test_db(): 31 | """ 32 | Connect to a different DB just for testing 33 | """ 34 | return db.client['pytest'] 35 | 36 | from app.main import app 37 | app.dependency_overrides[get_database] = get_test_db 38 | yield app 39 | 40 | # Delete pytest database after tests run 41 | db.client.drop_database('pytest') 42 | 43 | 44 | # Grab a reference to our database when needed 45 | @pytest.fixture 46 | def database(app: FastAPI) -> Database: 47 | return app.state._db_client['pytest'] 48 | 49 | 50 | # Make requests in our tests 51 | @pytest.fixture 52 | async def client(app: FastAPI) -> AsyncClient: 53 | async with LifespanManager(app): 54 | async with AsyncClient( 55 | app=app, 56 | base_url="http://backend", 57 | headers={"Content-Type": "application/json"} 58 | ) as client: 59 | yield client 60 | 61 | 62 | @pytest.fixture 63 | async def test_user(database: Database) -> models.UserInDB: 64 | new_user = models.UserCreate( 65 | email="tester2@gmail.com", 66 | password="testtest", 67 | first_name="Chuck", 68 | last_name="Vallone" 69 | ) 70 | user = await crud.user.get_by_email(db=database, email=new_user.email) 71 | if user: 72 | return user 73 | user = await services.registration.register_new_user(db=database, user_in=new_user) 74 | return user 75 | 76 | 77 | @pytest.fixture 78 | def authorized_client(client: AsyncClient, test_user: models.UserInDB) -> AsyncClient: 79 | access_token = services.authentication.create_access_token_for_user(user=test_user, secret_key=str(settings.SECRET_KEY)) 80 | client.headers = { 81 | **client.headers, 82 | "Authorization": f"{settings.JWT_TOKEN_PREFIX} {access_token}", 83 | } 84 | return client -------------------------------------------------------------------------------- /backend/tests/test_users.py: -------------------------------------------------------------------------------- 1 | from typing import List, Union, Type, Optional 2 | 3 | import pytest 4 | import jwt 5 | from httpx import AsyncClient 6 | from fastapi import FastAPI, HTTPException 7 | from databases import Database 8 | from pydantic import ValidationError 9 | from starlette.datastructures import Secret 10 | from starlette.status import ( 11 | HTTP_200_OK, 12 | HTTP_201_CREATED, 13 | HTTP_400_BAD_REQUEST, 14 | HTTP_401_UNAUTHORIZED, 15 | HTTP_404_NOT_FOUND, 16 | HTTP_422_UNPROCESSABLE_ENTITY, 17 | ) 18 | 19 | from app import models, services, crud 20 | from app.core.config import settings 21 | 22 | 23 | 24 | class TestUserRoutes: 25 | @pytest.mark.asyncio 26 | async def test_routes_exist(self, app: FastAPI, client: AsyncClient) -> None: 27 | res = await client.post(app.url_path_for("user:create"), json={}) 28 | assert res.status_code != HTTP_404_NOT_FOUND 29 | 30 | 31 | class TestUserRegistration: 32 | @pytest.mark.asyncio 33 | async def test_successful_user_create(self, app: FastAPI, client: AsyncClient) -> None: 34 | body = { 35 | "email": "test@gmail.com", 36 | "password": "testtest", 37 | "first_name": "Charles", 38 | "last_name": "Vallone" 39 | } 40 | res = await client.post(app.url_path_for("user:create"), json=body) 41 | assert res.status_code == HTTP_201_CREATED 42 | data = res.json() 43 | assert type(models.UserPublic(**data)) is models.UserPublic 44 | 45 | 46 | @pytest.mark.asyncio 47 | async def test_invalid_create_input_raises_error(self, app: FastAPI, client: AsyncClient) -> None: 48 | body_no_password = { 49 | "email": "test@gmail.com", 50 | "first_name": "Charles", 51 | "last_name": "Vallone" 52 | } 53 | res = await client.post(app.url_path_for("user:create"), json=body_no_password) 54 | assert res.status_code == HTTP_422_UNPROCESSABLE_ENTITY 55 | 56 | body_no_email = { 57 | "password": "testtest", 58 | "first_name": "Charles", 59 | "last_name": "Vallone" 60 | } 61 | res = await client.post(app.url_path_for("user:create"), json=body_no_email) 62 | assert res.status_code == HTTP_422_UNPROCESSABLE_ENTITY 63 | 64 | body_no_first = { 65 | "email": "test@gmail.com", 66 | "password": "testtest", 67 | "last_name": "Vallone" 68 | } 69 | res = await client.post(app.url_path_for("user:create"), json=body_no_first) 70 | assert res.status_code == HTTP_422_UNPROCESSABLE_ENTITY 71 | 72 | 73 | body_no_last = { 74 | "email": "test@gmail.com", 75 | "password": "testtest", 76 | "first_name": "Charles" 77 | } 78 | res = await client.post(app.url_path_for("user:create"), json=body_no_last) 79 | assert res.status_code == HTTP_422_UNPROCESSABLE_ENTITY 80 | 81 | 82 | @pytest.mark.asyncio 83 | async def test_email_already_in_use(self, app: FastAPI, client: AsyncClient) -> None: 84 | body = { 85 | "email": "test-duplicate@gmail.com", 86 | "password": "testtest", 87 | "first_name": "Charles", 88 | "last_name": "Vallone" 89 | } 90 | 91 | # Create it the first time 92 | res = await client.post(app.url_path_for("user:create"), json=body) 93 | assert res.status_code == HTTP_201_CREATED 94 | 95 | # Try to create it again 96 | res = await client.post(app.url_path_for("user:create"), json=body) 97 | assert res.status_code == HTTP_422_UNPROCESSABLE_ENTITY 98 | assert res.json()['detail'] == "Email address already in use" 99 | 100 | @pytest.mark.asyncio 101 | async def test_users_saved_password_is_hashed_and_has_salt( 102 | self, 103 | app: FastAPI, 104 | client: AsyncClient, 105 | database: Database 106 | ) -> None: 107 | 108 | body = { 109 | "email": "test@gmail.com", 110 | "password": "testtest", 111 | "first_name": "Charles", 112 | "last_name": "Vallone" 113 | } 114 | 115 | # send post request to create user and ensure it is successful 116 | res = await client.post(app.url_path_for("user:create"), json=body) 117 | assert res.status_code == HTTP_201_CREATED 118 | 119 | # ensure that the users password is hashed in the db 120 | # and that we can verify it using our auth service 121 | user_in_db = await crud.user.get_by_email(db=database, email=body["email"]) 122 | print(type(user_in_db)) 123 | print(user_in_db.salt) 124 | assert user_in_db is not None 125 | assert user_in_db.salt is not None and user_in_db.salt != "123" 126 | assert user_in_db.password != body["password"] 127 | assert services.authentication.verify_password( 128 | password=body["password"], 129 | salt=user_in_db.salt, 130 | hashed_password=user_in_db.password, 131 | ) 132 | 133 | 134 | class TestAuthTokens: 135 | @pytest.mark.asyncio 136 | async def test_can_successfully_create_access_token( 137 | self, app: FastAPI, client: AsyncClient, test_user: models.UserInDB 138 | ) -> None: 139 | access_token = services.authentication.create_access_token_for_user( 140 | user=test_user, 141 | secret_key=str(settings.SECRET_KEY), 142 | audience=settings.JWT_AUDIENCE, 143 | expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES, 144 | ) 145 | 146 | creds = jwt.decode(access_token, str(settings.SECRET_KEY), audience=settings.JWT_AUDIENCE, algorithms=[settings.JWT_ALGORITHM]) 147 | print(creds) 148 | assert creds.get("sub") is not None 149 | assert creds["sub"] == test_user.email 150 | assert creds["aud"] == settings.JWT_AUDIENCE 151 | 152 | 153 | @pytest.mark.asyncio 154 | async def test_token_missing_user_is_invalid(self, app: FastAPI, client: AsyncClient) -> None: 155 | access_token = services.authentication.create_access_token_for_user( 156 | user=None, 157 | secret_key=str(settings.SECRET_KEY), 158 | audience=settings.JWT_AUDIENCE, 159 | expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES, 160 | ) 161 | 162 | with pytest.raises(jwt.PyJWTError): 163 | jwt.decode(access_token, str(settings.SECRET_KEY), audience=settings.JWT_AUDIENCE, algorithms=[settings.JWT_ALGORITHM]) 164 | 165 | 166 | @pytest.mark.asyncio 167 | @pytest.mark.parametrize( 168 | "secret_key, jwt_audience, exception", 169 | ( 170 | ("wrong-secret", settings.JWT_AUDIENCE, jwt.InvalidSignatureError), 171 | (None, settings.JWT_AUDIENCE, jwt.InvalidSignatureError), 172 | (settings.SECRET_KEY, "othersite:auth", jwt.InvalidAudienceError), 173 | (settings.SECRET_KEY, None, ValidationError), 174 | ) 175 | ) 176 | async def test_invalid_token_content_raises_error( 177 | self, 178 | app: FastAPI, 179 | client: AsyncClient, 180 | database: Database, 181 | secret_key: Union[str, Secret], 182 | jwt_audience: str, 183 | exception: Type[BaseException], 184 | test_user: models.UserInDB 185 | ) -> None: 186 | 187 | with pytest.raises(exception): 188 | access_token = services.authentication.create_access_token_for_user( 189 | user=test_user, 190 | secret_key=str(secret_key), 191 | audience=jwt_audience, 192 | expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES, 193 | ) 194 | print(access_token) 195 | 196 | jwt.decode(access_token, str(settings.SECRET_KEY), audience=settings.JWT_AUDIENCE, algorithms=[settings.JWT_ALGORITHM]) 197 | 198 | 199 | class TestUserLogin: 200 | @pytest.mark.asyncio 201 | async def test_user_can_login_successfully_and_receives_valid_token( 202 | self, app: FastAPI, client: AsyncClient, test_user: models.UserInDB, 203 | ) -> None: 204 | client.headers["content-type"] = "application/x-www-form-urlencoded" 205 | login_data = { 206 | "username": test_user.email, 207 | "password": "testtest", # insert user's plaintext password 208 | } 209 | res = await client.post(app.url_path_for("user:login"), data=login_data) 210 | assert res.status_code == HTTP_200_OK 211 | 212 | # check that token exists in response and has user encoded within it 213 | token = res.json().get("access_token") 214 | creds = jwt.decode(token, str(settings.SECRET_KEY), audience=settings.JWT_AUDIENCE, algorithms=[settings.JWT_ALGORITHM]) 215 | print(creds) 216 | # assert "email" in creds # TODO - this is failing. why don't I have email address in here? Had to chagne this in another test to `sub` to get that to work. Is it an issue if email is not in here 217 | # assert creds["email"] == test_user.username 218 | assert "sub" in creds 219 | assert creds["sub"] == test_user.email 220 | 221 | # check that token is proper type 222 | assert "token_type" in res.json() 223 | assert res.json().get("token_type") == "bearer" 224 | 225 | 226 | @pytest.mark.asyncio 227 | @pytest.mark.parametrize( 228 | "credential, wrong_value, status_code", 229 | ( 230 | ("email", "wrong@email.com", 401), 231 | ("email", None, 401), 232 | ("email", "notemail", 401), 233 | ("password", "wrongpassword", 401), 234 | ("password", None, 401), 235 | ), 236 | ) 237 | async def test_user_with_wrong_creds_doesnt_receive_token( 238 | self, 239 | app: FastAPI, 240 | client: AsyncClient, 241 | test_user: models.UserInDB, 242 | credential: str, 243 | wrong_value: str, 244 | status_code: int, 245 | ) -> None: 246 | client.headers["content-type"] = "application/x-www-form-urlencoded" 247 | user_data = test_user.dict() 248 | user_data["password"] = "testtest" # insert user's plaintext password 249 | user_data[credential] = wrong_value 250 | login_data = { 251 | "username": user_data["email"], 252 | "password": user_data["password"], 253 | } 254 | res = await client.post(app.url_path_for("user:login"), data=login_data) 255 | assert res.status_code == status_code 256 | assert "access_token" not in res.json() 257 | 258 | 259 | @pytest.mark.asyncio 260 | async def test_can_retrieve_email_from_token( 261 | self, app: FastAPI, client: AsyncClient, test_user: models.UserInDB 262 | ) -> None: 263 | token = services.authentication.create_access_token_for_user(user=test_user, secret_key=str(settings.SECRET_KEY)) 264 | email = services.authentication.get_email_from_token(token=token, secret_key=str(settings.SECRET_KEY)) 265 | assert email == test_user.email 266 | 267 | @pytest.mark.asyncio 268 | @pytest.mark.parametrize( 269 | "secret, wrong_token", 270 | ( 271 | (settings.SECRET_KEY, "asdf"), # use wrong token 272 | (settings.SECRET_KEY, ""), # use wrong token 273 | (settings.SECRET_KEY, None), # use wrong token 274 | ("ABC123", "use correct token"), # use wrong secret 275 | ), 276 | ) 277 | async def test_error_when_token_or_secret_is_wrong( 278 | self, 279 | app: FastAPI, 280 | client: AsyncClient, 281 | test_user: models.UserInDB, 282 | secret: Union[Secret, str], 283 | wrong_token: Optional[str], 284 | ) -> None: 285 | token = services.authentication.create_access_token_for_user(user=test_user, secret_key=str(settings.SECRET_KEY)) 286 | if wrong_token == "use correct token": 287 | wrong_token = settings.JWT_TOKEN_PREFIX 288 | with pytest.raises(HTTPException): 289 | print(secret) 290 | print(wrong_token) 291 | email = services.authentication.get_email_from_token(token=wrong_token, secret_key=str(secret)) 292 | print(email) 293 | 294 | 295 | class TestUserMe: 296 | @pytest.mark.asyncio 297 | async def test_authenticated_user_can_retrieve_own_data( 298 | self, app: FastAPI, authorized_client: AsyncClient, test_user: models.UserInDB, 299 | ) -> None: 300 | res = await authorized_client.get(app.url_path_for("user:me")) 301 | assert res.status_code == HTTP_200_OK 302 | user = models.UserPublic(**res.json()) 303 | assert user.email == test_user.email 304 | assert user.id == test_user.id 305 | 306 | 307 | @pytest.mark.asyncio 308 | async def test_user_cannot_access_own_data_if_not_authenticated( 309 | self, app: FastAPI, client: AsyncClient, test_user: models.UserInDB, 310 | ) -> None: 311 | res = await client.get(app.url_path_for("user:me")) 312 | assert res.status_code == HTTP_401_UNAUTHORIZED 313 | 314 | 315 | @pytest.mark.asyncio 316 | @pytest.mark.parametrize("jwt_prefix", (("",), ("value",), ("Token",), ("JWT",), ("Swearer",),)) 317 | async def test_user_cannot_access_own_data_with_incorrect_jwt_prefix( 318 | self, app: FastAPI, client: AsyncClient, test_user: models.UserInDB, jwt_prefix: str, 319 | ) -> None: 320 | token = services.authentication.create_access_token_for_user(user=test_user, secret_key=str(settings.SECRET_KEY)) 321 | res = await client.get( 322 | app.url_path_for("user:me"), headers={"Authorization": f"{jwt_prefix} {token}"} 323 | ) 324 | assert res.status_code == HTTP_401_UNAUTHORIZED 325 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | mongodb: 5 | image: mongo:latest 6 | environment: 7 | MONGO_DB: app 8 | MONGO_INITDB_ROOT_USERNAME: mongouser 9 | MONGO_INITDB_ROOT_PASSWORD: mongopassword 10 | ports: 11 | - 27017:27017 12 | volumes: 13 | - mongodb:/data/db 14 | 15 | backend: 16 | build: 17 | context: ./backend 18 | env_file: 19 | - ./backend/.env.example 20 | volumes: 21 | - ./backend:/usr/src/app 22 | command: uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 23 | ports: 24 | - 8000:8000 25 | depends_on: 26 | - mongodb 27 | 28 | frontend: 29 | build: 30 | context: ./frontend 31 | volumes: 32 | - ./frontend:/usr/src/app 33 | # command: npm run dev -- --host 0.0.0.0 34 | ports: 35 | - 5173:5173 36 | depends_on: 37 | - backend 38 | 39 | volumes: 40 | mongodb: -------------------------------------------------------------------------------- /frontend/.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /frontend/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['eslint:recommended', 'prettier'], 4 | plugins: ['svelte3'], 5 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 6 | parserOptions: { 7 | sourceType: 'module', 8 | ecmaVersion: 2020 9 | }, 10 | env: { 11 | browser: true, 12 | es2017: true, 13 | node: true 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /frontend/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /frontend/.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /frontend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "pluginSearchDirs": ["."], 8 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 9 | } 10 | -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | 3 | WORKDIR /usr/src/app 4 | 5 | COPY package.json package-lock.json ./ 6 | 7 | RUN npm ci 8 | COPY . . 9 | RUN npm run build 10 | 11 | CMD npm rebuild esbuild && npm run dev -- --host -------------------------------------------------------------------------------- /frontend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend2", 3 | "version": "0.0.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "frontend2", 9 | "version": "0.0.1", 10 | "devDependencies": { 11 | "@sveltejs/adapter-auto": "next", 12 | "@sveltejs/kit": "next", 13 | "autoprefixer": "^10.4.12", 14 | "eslint": "^8.16.0", 15 | "eslint-config-prettier": "^8.3.0", 16 | "eslint-plugin-svelte3": "^4.0.0", 17 | "postcss": "^8.4.18", 18 | "prettier": "^2.6.2", 19 | "prettier-plugin-svelte": "^2.7.0", 20 | "svelte": "^3.44.0", 21 | "svelte-preprocess": "^4.10.7", 22 | "tailwindcss": "^3.2.1", 23 | "vite": "^3.1.0" 24 | } 25 | }, 26 | "node_modules/@cloudflare/workers-types": { 27 | "version": "3.18.0", 28 | "dev": true, 29 | "license": "BSD-3-Clause" 30 | }, 31 | "node_modules/@eslint/eslintrc": { 32 | "version": "1.3.3", 33 | "dev": true, 34 | "license": "MIT", 35 | "dependencies": { 36 | "ajv": "^6.12.4", 37 | "debug": "^4.3.2", 38 | "espree": "^9.4.0", 39 | "globals": "^13.15.0", 40 | "ignore": "^5.2.0", 41 | "import-fresh": "^3.2.1", 42 | "js-yaml": "^4.1.0", 43 | "minimatch": "^3.1.2", 44 | "strip-json-comments": "^3.1.1" 45 | }, 46 | "engines": { 47 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 48 | }, 49 | "funding": { 50 | "url": "https://opencollective.com/eslint" 51 | } 52 | }, 53 | "node_modules/@humanwhocodes/config-array": { 54 | "version": "0.11.6", 55 | "dev": true, 56 | "license": "Apache-2.0", 57 | "dependencies": { 58 | "@humanwhocodes/object-schema": "^1.2.1", 59 | "debug": "^4.1.1", 60 | "minimatch": "^3.0.4" 61 | }, 62 | "engines": { 63 | "node": ">=10.10.0" 64 | } 65 | }, 66 | "node_modules/@humanwhocodes/module-importer": { 67 | "version": "1.0.1", 68 | "dev": true, 69 | "license": "Apache-2.0", 70 | "engines": { 71 | "node": ">=12.22" 72 | }, 73 | "funding": { 74 | "type": "github", 75 | "url": "https://github.com/sponsors/nzakas" 76 | } 77 | }, 78 | "node_modules/@humanwhocodes/object-schema": { 79 | "version": "1.2.1", 80 | "dev": true, 81 | "license": "BSD-3-Clause" 82 | }, 83 | "node_modules/@iarna/toml": { 84 | "version": "2.2.5", 85 | "dev": true, 86 | "license": "ISC" 87 | }, 88 | "node_modules/@mapbox/node-pre-gyp": { 89 | "version": "1.0.10", 90 | "dev": true, 91 | "license": "BSD-3-Clause", 92 | "dependencies": { 93 | "detect-libc": "^2.0.0", 94 | "https-proxy-agent": "^5.0.0", 95 | "make-dir": "^3.1.0", 96 | "node-fetch": "^2.6.7", 97 | "nopt": "^5.0.0", 98 | "npmlog": "^5.0.1", 99 | "rimraf": "^3.0.2", 100 | "semver": "^7.3.5", 101 | "tar": "^6.1.11" 102 | }, 103 | "bin": { 104 | "node-pre-gyp": "bin/node-pre-gyp" 105 | } 106 | }, 107 | "node_modules/@nodelib/fs.scandir": { 108 | "version": "2.1.5", 109 | "dev": true, 110 | "license": "MIT", 111 | "dependencies": { 112 | "@nodelib/fs.stat": "2.0.5", 113 | "run-parallel": "^1.1.9" 114 | }, 115 | "engines": { 116 | "node": ">= 8" 117 | } 118 | }, 119 | "node_modules/@nodelib/fs.stat": { 120 | "version": "2.0.5", 121 | "dev": true, 122 | "license": "MIT", 123 | "engines": { 124 | "node": ">= 8" 125 | } 126 | }, 127 | "node_modules/@nodelib/fs.walk": { 128 | "version": "1.2.8", 129 | "dev": true, 130 | "license": "MIT", 131 | "dependencies": { 132 | "@nodelib/fs.scandir": "2.1.5", 133 | "fastq": "^1.6.0" 134 | }, 135 | "engines": { 136 | "node": ">= 8" 137 | } 138 | }, 139 | "node_modules/@polka/url": { 140 | "version": "1.0.0-next.21", 141 | "dev": true, 142 | "license": "MIT" 143 | }, 144 | "node_modules/@rollup/pluginutils": { 145 | "version": "4.2.1", 146 | "dev": true, 147 | "license": "MIT", 148 | "dependencies": { 149 | "estree-walker": "^2.0.1", 150 | "picomatch": "^2.2.2" 151 | }, 152 | "engines": { 153 | "node": ">= 8.0.0" 154 | } 155 | }, 156 | "node_modules/@sveltejs/adapter-auto": { 157 | "version": "1.0.0-next.84", 158 | "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-1.0.0-next.84.tgz", 159 | "integrity": "sha512-95NI5dZ3ZNd4vs1/N5knTcArBlWL9pBw2IANCBAcGzwVMoGPjKyyMKZt1gEX74LVwCN6RSRPZ36+6Z6HEb/ojQ==", 160 | "dev": true, 161 | "dependencies": { 162 | "@sveltejs/adapter-cloudflare": "1.0.0-next.39", 163 | "@sveltejs/adapter-netlify": "1.0.0-next.81", 164 | "@sveltejs/adapter-vercel": "1.0.0-next.80" 165 | } 166 | }, 167 | "node_modules/@sveltejs/adapter-cloudflare": { 168 | "version": "1.0.0-next.39", 169 | "dev": true, 170 | "license": "MIT", 171 | "dependencies": { 172 | "@cloudflare/workers-types": "^3.14.0", 173 | "esbuild": "^0.15.7", 174 | "worktop": "0.8.0-next.14" 175 | } 176 | }, 177 | "node_modules/@sveltejs/adapter-netlify": { 178 | "version": "1.0.0-next.81", 179 | "dev": true, 180 | "license": "MIT", 181 | "dependencies": { 182 | "@iarna/toml": "^2.2.5", 183 | "esbuild": "^0.15.7", 184 | "set-cookie-parser": "^2.4.8" 185 | } 186 | }, 187 | "node_modules/@sveltejs/adapter-vercel": { 188 | "version": "1.0.0-next.80", 189 | "dev": true, 190 | "license": "MIT", 191 | "dependencies": { 192 | "@vercel/nft": "^0.22.0", 193 | "esbuild": "^0.15.7" 194 | } 195 | }, 196 | "node_modules/@sveltejs/kit": { 197 | "version": "1.0.0-next.522", 198 | "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.522.tgz", 199 | "integrity": "sha512-dVVrRPbXlAut4vg8kbCeZOjUZnYB7ZvDKp/yAx8InpDF0P1bvUDlc++DXFeMBdXX8bakTA3NGonWnDjqslCsZw==", 200 | "dev": true, 201 | "hasInstallScript": true, 202 | "dependencies": { 203 | "@sveltejs/vite-plugin-svelte": "^1.0.5", 204 | "@types/cookie": "^0.5.1", 205 | "cookie": "^0.5.0", 206 | "devalue": "^4.0.0", 207 | "kleur": "^4.1.4", 208 | "magic-string": "^0.26.2", 209 | "mime": "^3.0.0", 210 | "sade": "^1.8.1", 211 | "set-cookie-parser": "^2.4.8", 212 | "sirv": "^2.0.2", 213 | "tiny-glob": "^0.2.9", 214 | "undici": "^5.11.0" 215 | }, 216 | "bin": { 217 | "svelte-kit": "svelte-kit.js" 218 | }, 219 | "engines": { 220 | "node": ">=16.14" 221 | }, 222 | "peerDependencies": { 223 | "svelte": "^3.44.0", 224 | "vite": "^3.1.0" 225 | } 226 | }, 227 | "node_modules/@sveltejs/vite-plugin-svelte": { 228 | "version": "1.0.9", 229 | "dev": true, 230 | "license": "MIT", 231 | "dependencies": { 232 | "@rollup/pluginutils": "^4.2.1", 233 | "debug": "^4.3.4", 234 | "deepmerge": "^4.2.2", 235 | "kleur": "^4.1.5", 236 | "magic-string": "^0.26.5", 237 | "svelte-hmr": "^0.15.0" 238 | }, 239 | "engines": { 240 | "node": "^14.18.0 || >= 16" 241 | }, 242 | "peerDependencies": { 243 | "diff-match-patch": "^1.0.5", 244 | "svelte": "^3.44.0", 245 | "vite": "^3.0.0" 246 | }, 247 | "peerDependenciesMeta": { 248 | "diff-match-patch": { 249 | "optional": true 250 | } 251 | } 252 | }, 253 | "node_modules/@types/cookie": { 254 | "version": "0.5.1", 255 | "dev": true, 256 | "license": "MIT" 257 | }, 258 | "node_modules/@types/node": { 259 | "version": "18.11.5", 260 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.5.tgz", 261 | "integrity": "sha512-3JRwhbjI+cHLAkUorhf8RnqUbFXajvzX4q6fMn5JwkgtuwfYtRQYI3u4V92vI6NJuTsbBQWWh3RZjFsuevyMGQ==", 262 | "dev": true 263 | }, 264 | "node_modules/@types/pug": { 265 | "version": "2.0.6", 266 | "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz", 267 | "integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==", 268 | "dev": true 269 | }, 270 | "node_modules/@types/sass": { 271 | "version": "1.43.1", 272 | "resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.43.1.tgz", 273 | "integrity": "sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==", 274 | "dev": true, 275 | "dependencies": { 276 | "@types/node": "*" 277 | } 278 | }, 279 | "node_modules/@vercel/nft": { 280 | "version": "0.22.1", 281 | "dev": true, 282 | "license": "MIT", 283 | "dependencies": { 284 | "@mapbox/node-pre-gyp": "^1.0.5", 285 | "acorn": "^8.6.0", 286 | "async-sema": "^3.1.1", 287 | "bindings": "^1.4.0", 288 | "estree-walker": "2.0.2", 289 | "glob": "^7.1.3", 290 | "graceful-fs": "^4.2.9", 291 | "micromatch": "^4.0.2", 292 | "node-gyp-build": "^4.2.2", 293 | "resolve-from": "^5.0.0", 294 | "rollup-pluginutils": "^2.8.2" 295 | }, 296 | "bin": { 297 | "nft": "out/cli.js" 298 | } 299 | }, 300 | "node_modules/abbrev": { 301 | "version": "1.1.1", 302 | "dev": true, 303 | "license": "ISC" 304 | }, 305 | "node_modules/acorn": { 306 | "version": "8.8.0", 307 | "dev": true, 308 | "license": "MIT", 309 | "bin": { 310 | "acorn": "bin/acorn" 311 | }, 312 | "engines": { 313 | "node": ">=0.4.0" 314 | } 315 | }, 316 | "node_modules/acorn-jsx": { 317 | "version": "5.3.2", 318 | "dev": true, 319 | "license": "MIT", 320 | "peerDependencies": { 321 | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 322 | } 323 | }, 324 | "node_modules/acorn-node": { 325 | "version": "1.8.2", 326 | "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", 327 | "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", 328 | "dev": true, 329 | "dependencies": { 330 | "acorn": "^7.0.0", 331 | "acorn-walk": "^7.0.0", 332 | "xtend": "^4.0.2" 333 | } 334 | }, 335 | "node_modules/acorn-node/node_modules/acorn": { 336 | "version": "7.4.1", 337 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", 338 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", 339 | "dev": true, 340 | "bin": { 341 | "acorn": "bin/acorn" 342 | }, 343 | "engines": { 344 | "node": ">=0.4.0" 345 | } 346 | }, 347 | "node_modules/acorn-walk": { 348 | "version": "7.2.0", 349 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", 350 | "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", 351 | "dev": true, 352 | "engines": { 353 | "node": ">=0.4.0" 354 | } 355 | }, 356 | "node_modules/agent-base": { 357 | "version": "6.0.2", 358 | "dev": true, 359 | "license": "MIT", 360 | "dependencies": { 361 | "debug": "4" 362 | }, 363 | "engines": { 364 | "node": ">= 6.0.0" 365 | } 366 | }, 367 | "node_modules/ajv": { 368 | "version": "6.12.6", 369 | "dev": true, 370 | "license": "MIT", 371 | "dependencies": { 372 | "fast-deep-equal": "^3.1.1", 373 | "fast-json-stable-stringify": "^2.0.0", 374 | "json-schema-traverse": "^0.4.1", 375 | "uri-js": "^4.2.2" 376 | }, 377 | "funding": { 378 | "type": "github", 379 | "url": "https://github.com/sponsors/epoberezkin" 380 | } 381 | }, 382 | "node_modules/ansi-regex": { 383 | "version": "5.0.1", 384 | "dev": true, 385 | "license": "MIT", 386 | "engines": { 387 | "node": ">=8" 388 | } 389 | }, 390 | "node_modules/ansi-styles": { 391 | "version": "4.3.0", 392 | "dev": true, 393 | "license": "MIT", 394 | "dependencies": { 395 | "color-convert": "^2.0.1" 396 | }, 397 | "engines": { 398 | "node": ">=8" 399 | }, 400 | "funding": { 401 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 402 | } 403 | }, 404 | "node_modules/anymatch": { 405 | "version": "3.1.2", 406 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 407 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 408 | "dev": true, 409 | "dependencies": { 410 | "normalize-path": "^3.0.0", 411 | "picomatch": "^2.0.4" 412 | }, 413 | "engines": { 414 | "node": ">= 8" 415 | } 416 | }, 417 | "node_modules/aproba": { 418 | "version": "2.0.0", 419 | "dev": true, 420 | "license": "ISC" 421 | }, 422 | "node_modules/are-we-there-yet": { 423 | "version": "2.0.0", 424 | "dev": true, 425 | "license": "ISC", 426 | "dependencies": { 427 | "delegates": "^1.0.0", 428 | "readable-stream": "^3.6.0" 429 | }, 430 | "engines": { 431 | "node": ">=10" 432 | } 433 | }, 434 | "node_modules/arg": { 435 | "version": "5.0.2", 436 | "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", 437 | "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", 438 | "dev": true 439 | }, 440 | "node_modules/argparse": { 441 | "version": "2.0.1", 442 | "dev": true, 443 | "license": "Python-2.0" 444 | }, 445 | "node_modules/async-sema": { 446 | "version": "3.1.1", 447 | "dev": true, 448 | "license": "MIT" 449 | }, 450 | "node_modules/autoprefixer": { 451 | "version": "10.4.12", 452 | "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.12.tgz", 453 | "integrity": "sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==", 454 | "dev": true, 455 | "funding": [ 456 | { 457 | "type": "opencollective", 458 | "url": "https://opencollective.com/postcss/" 459 | }, 460 | { 461 | "type": "tidelift", 462 | "url": "https://tidelift.com/funding/github/npm/autoprefixer" 463 | } 464 | ], 465 | "dependencies": { 466 | "browserslist": "^4.21.4", 467 | "caniuse-lite": "^1.0.30001407", 468 | "fraction.js": "^4.2.0", 469 | "normalize-range": "^0.1.2", 470 | "picocolors": "^1.0.0", 471 | "postcss-value-parser": "^4.2.0" 472 | }, 473 | "bin": { 474 | "autoprefixer": "bin/autoprefixer" 475 | }, 476 | "engines": { 477 | "node": "^10 || ^12 || >=14" 478 | }, 479 | "peerDependencies": { 480 | "postcss": "^8.1.0" 481 | } 482 | }, 483 | "node_modules/balanced-match": { 484 | "version": "1.0.2", 485 | "dev": true, 486 | "license": "MIT" 487 | }, 488 | "node_modules/binary-extensions": { 489 | "version": "2.2.0", 490 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 491 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 492 | "dev": true, 493 | "engines": { 494 | "node": ">=8" 495 | } 496 | }, 497 | "node_modules/bindings": { 498 | "version": "1.5.0", 499 | "dev": true, 500 | "license": "MIT", 501 | "dependencies": { 502 | "file-uri-to-path": "1.0.0" 503 | } 504 | }, 505 | "node_modules/brace-expansion": { 506 | "version": "1.1.11", 507 | "dev": true, 508 | "license": "MIT", 509 | "dependencies": { 510 | "balanced-match": "^1.0.0", 511 | "concat-map": "0.0.1" 512 | } 513 | }, 514 | "node_modules/braces": { 515 | "version": "3.0.2", 516 | "dev": true, 517 | "license": "MIT", 518 | "dependencies": { 519 | "fill-range": "^7.0.1" 520 | }, 521 | "engines": { 522 | "node": ">=8" 523 | } 524 | }, 525 | "node_modules/browserslist": { 526 | "version": "4.21.4", 527 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", 528 | "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", 529 | "dev": true, 530 | "funding": [ 531 | { 532 | "type": "opencollective", 533 | "url": "https://opencollective.com/browserslist" 534 | }, 535 | { 536 | "type": "tidelift", 537 | "url": "https://tidelift.com/funding/github/npm/browserslist" 538 | } 539 | ], 540 | "dependencies": { 541 | "caniuse-lite": "^1.0.30001400", 542 | "electron-to-chromium": "^1.4.251", 543 | "node-releases": "^2.0.6", 544 | "update-browserslist-db": "^1.0.9" 545 | }, 546 | "bin": { 547 | "browserslist": "cli.js" 548 | }, 549 | "engines": { 550 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 551 | } 552 | }, 553 | "node_modules/buffer-crc32": { 554 | "version": "0.2.13", 555 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 556 | "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", 557 | "dev": true, 558 | "engines": { 559 | "node": "*" 560 | } 561 | }, 562 | "node_modules/busboy": { 563 | "version": "1.6.0", 564 | "dev": true, 565 | "dependencies": { 566 | "streamsearch": "^1.1.0" 567 | }, 568 | "engines": { 569 | "node": ">=10.16.0" 570 | } 571 | }, 572 | "node_modules/callsites": { 573 | "version": "3.1.0", 574 | "dev": true, 575 | "license": "MIT", 576 | "engines": { 577 | "node": ">=6" 578 | } 579 | }, 580 | "node_modules/camelcase-css": { 581 | "version": "2.0.1", 582 | "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", 583 | "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", 584 | "dev": true, 585 | "engines": { 586 | "node": ">= 6" 587 | } 588 | }, 589 | "node_modules/caniuse-lite": { 590 | "version": "1.0.30001425", 591 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001425.tgz", 592 | "integrity": "sha512-/pzFv0OmNG6W0ym80P3NtapU0QEiDS3VuYAZMGoLLqiC7f6FJFe1MjpQDREGApeenD9wloeytmVDj+JLXPC6qw==", 593 | "dev": true, 594 | "funding": [ 595 | { 596 | "type": "opencollective", 597 | "url": "https://opencollective.com/browserslist" 598 | }, 599 | { 600 | "type": "tidelift", 601 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 602 | } 603 | ] 604 | }, 605 | "node_modules/chalk": { 606 | "version": "4.1.2", 607 | "dev": true, 608 | "license": "MIT", 609 | "dependencies": { 610 | "ansi-styles": "^4.1.0", 611 | "supports-color": "^7.1.0" 612 | }, 613 | "engines": { 614 | "node": ">=10" 615 | }, 616 | "funding": { 617 | "url": "https://github.com/chalk/chalk?sponsor=1" 618 | } 619 | }, 620 | "node_modules/chokidar": { 621 | "version": "3.5.3", 622 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 623 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 624 | "dev": true, 625 | "funding": [ 626 | { 627 | "type": "individual", 628 | "url": "https://paulmillr.com/funding/" 629 | } 630 | ], 631 | "dependencies": { 632 | "anymatch": "~3.1.2", 633 | "braces": "~3.0.2", 634 | "glob-parent": "~5.1.2", 635 | "is-binary-path": "~2.1.0", 636 | "is-glob": "~4.0.1", 637 | "normalize-path": "~3.0.0", 638 | "readdirp": "~3.6.0" 639 | }, 640 | "engines": { 641 | "node": ">= 8.10.0" 642 | }, 643 | "optionalDependencies": { 644 | "fsevents": "~2.3.2" 645 | } 646 | }, 647 | "node_modules/chokidar/node_modules/glob-parent": { 648 | "version": "5.1.2", 649 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 650 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 651 | "dev": true, 652 | "dependencies": { 653 | "is-glob": "^4.0.1" 654 | }, 655 | "engines": { 656 | "node": ">= 6" 657 | } 658 | }, 659 | "node_modules/chownr": { 660 | "version": "2.0.0", 661 | "dev": true, 662 | "license": "ISC", 663 | "engines": { 664 | "node": ">=10" 665 | } 666 | }, 667 | "node_modules/color-convert": { 668 | "version": "2.0.1", 669 | "dev": true, 670 | "license": "MIT", 671 | "dependencies": { 672 | "color-name": "~1.1.4" 673 | }, 674 | "engines": { 675 | "node": ">=7.0.0" 676 | } 677 | }, 678 | "node_modules/color-name": { 679 | "version": "1.1.4", 680 | "dev": true, 681 | "license": "MIT" 682 | }, 683 | "node_modules/color-support": { 684 | "version": "1.1.3", 685 | "dev": true, 686 | "license": "ISC", 687 | "bin": { 688 | "color-support": "bin.js" 689 | } 690 | }, 691 | "node_modules/concat-map": { 692 | "version": "0.0.1", 693 | "dev": true, 694 | "license": "MIT" 695 | }, 696 | "node_modules/console-control-strings": { 697 | "version": "1.1.0", 698 | "dev": true, 699 | "license": "ISC" 700 | }, 701 | "node_modules/cookie": { 702 | "version": "0.5.0", 703 | "dev": true, 704 | "license": "MIT", 705 | "engines": { 706 | "node": ">= 0.6" 707 | } 708 | }, 709 | "node_modules/cross-spawn": { 710 | "version": "7.0.3", 711 | "dev": true, 712 | "license": "MIT", 713 | "dependencies": { 714 | "path-key": "^3.1.0", 715 | "shebang-command": "^2.0.0", 716 | "which": "^2.0.1" 717 | }, 718 | "engines": { 719 | "node": ">= 8" 720 | } 721 | }, 722 | "node_modules/cssesc": { 723 | "version": "3.0.0", 724 | "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", 725 | "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", 726 | "dev": true, 727 | "bin": { 728 | "cssesc": "bin/cssesc" 729 | }, 730 | "engines": { 731 | "node": ">=4" 732 | } 733 | }, 734 | "node_modules/debug": { 735 | "version": "4.3.4", 736 | "dev": true, 737 | "license": "MIT", 738 | "dependencies": { 739 | "ms": "2.1.2" 740 | }, 741 | "engines": { 742 | "node": ">=6.0" 743 | }, 744 | "peerDependenciesMeta": { 745 | "supports-color": { 746 | "optional": true 747 | } 748 | } 749 | }, 750 | "node_modules/deep-is": { 751 | "version": "0.1.4", 752 | "dev": true, 753 | "license": "MIT" 754 | }, 755 | "node_modules/deepmerge": { 756 | "version": "4.2.2", 757 | "dev": true, 758 | "license": "MIT", 759 | "engines": { 760 | "node": ">=0.10.0" 761 | } 762 | }, 763 | "node_modules/defined": { 764 | "version": "1.0.1", 765 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", 766 | "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", 767 | "dev": true, 768 | "funding": { 769 | "url": "https://github.com/sponsors/ljharb" 770 | } 771 | }, 772 | "node_modules/delegates": { 773 | "version": "1.0.0", 774 | "dev": true, 775 | "license": "MIT" 776 | }, 777 | "node_modules/detect-indent": { 778 | "version": "6.1.0", 779 | "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", 780 | "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", 781 | "dev": true, 782 | "engines": { 783 | "node": ">=8" 784 | } 785 | }, 786 | "node_modules/detect-libc": { 787 | "version": "2.0.1", 788 | "dev": true, 789 | "license": "Apache-2.0", 790 | "engines": { 791 | "node": ">=8" 792 | } 793 | }, 794 | "node_modules/detective": { 795 | "version": "5.2.1", 796 | "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", 797 | "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", 798 | "dev": true, 799 | "dependencies": { 800 | "acorn-node": "^1.8.2", 801 | "defined": "^1.0.0", 802 | "minimist": "^1.2.6" 803 | }, 804 | "bin": { 805 | "detective": "bin/detective.js" 806 | }, 807 | "engines": { 808 | "node": ">=0.8.0" 809 | } 810 | }, 811 | "node_modules/devalue": { 812 | "version": "4.0.1", 813 | "dev": true, 814 | "license": "MIT" 815 | }, 816 | "node_modules/didyoumean": { 817 | "version": "1.2.2", 818 | "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", 819 | "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", 820 | "dev": true 821 | }, 822 | "node_modules/dlv": { 823 | "version": "1.1.3", 824 | "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", 825 | "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", 826 | "dev": true 827 | }, 828 | "node_modules/doctrine": { 829 | "version": "3.0.0", 830 | "dev": true, 831 | "license": "Apache-2.0", 832 | "dependencies": { 833 | "esutils": "^2.0.2" 834 | }, 835 | "engines": { 836 | "node": ">=6.0.0" 837 | } 838 | }, 839 | "node_modules/electron-to-chromium": { 840 | "version": "1.4.284", 841 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", 842 | "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", 843 | "dev": true 844 | }, 845 | "node_modules/emoji-regex": { 846 | "version": "8.0.0", 847 | "dev": true, 848 | "license": "MIT" 849 | }, 850 | "node_modules/es6-promise": { 851 | "version": "3.3.1", 852 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", 853 | "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", 854 | "dev": true 855 | }, 856 | "node_modules/esbuild": { 857 | "version": "0.15.12", 858 | "dev": true, 859 | "hasInstallScript": true, 860 | "license": "MIT", 861 | "bin": { 862 | "esbuild": "bin/esbuild" 863 | }, 864 | "engines": { 865 | "node": ">=12" 866 | }, 867 | "optionalDependencies": { 868 | "@esbuild/android-arm": "0.15.12", 869 | "@esbuild/linux-loong64": "0.15.12", 870 | "esbuild-android-64": "0.15.12", 871 | "esbuild-android-arm64": "0.15.12", 872 | "esbuild-darwin-64": "0.15.12", 873 | "esbuild-darwin-arm64": "0.15.12", 874 | "esbuild-freebsd-64": "0.15.12", 875 | "esbuild-freebsd-arm64": "0.15.12", 876 | "esbuild-linux-32": "0.15.12", 877 | "esbuild-linux-64": "0.15.12", 878 | "esbuild-linux-arm": "0.15.12", 879 | "esbuild-linux-arm64": "0.15.12", 880 | "esbuild-linux-mips64le": "0.15.12", 881 | "esbuild-linux-ppc64le": "0.15.12", 882 | "esbuild-linux-riscv64": "0.15.12", 883 | "esbuild-linux-s390x": "0.15.12", 884 | "esbuild-netbsd-64": "0.15.12", 885 | "esbuild-openbsd-64": "0.15.12", 886 | "esbuild-sunos-64": "0.15.12", 887 | "esbuild-windows-32": "0.15.12", 888 | "esbuild-windows-64": "0.15.12", 889 | "esbuild-windows-arm64": "0.15.12" 890 | } 891 | }, 892 | "node_modules/esbuild-darwin-arm64": { 893 | "version": "0.15.12", 894 | "cpu": [ 895 | "arm64" 896 | ], 897 | "dev": true, 898 | "license": "MIT", 899 | "optional": true, 900 | "os": [ 901 | "darwin" 902 | ], 903 | "engines": { 904 | "node": ">=12" 905 | } 906 | }, 907 | "node_modules/escalade": { 908 | "version": "3.1.1", 909 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 910 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 911 | "dev": true, 912 | "engines": { 913 | "node": ">=6" 914 | } 915 | }, 916 | "node_modules/escape-string-regexp": { 917 | "version": "4.0.0", 918 | "dev": true, 919 | "license": "MIT", 920 | "engines": { 921 | "node": ">=10" 922 | }, 923 | "funding": { 924 | "url": "https://github.com/sponsors/sindresorhus" 925 | } 926 | }, 927 | "node_modules/eslint": { 928 | "version": "8.26.0", 929 | "dev": true, 930 | "license": "MIT", 931 | "dependencies": { 932 | "@eslint/eslintrc": "^1.3.3", 933 | "@humanwhocodes/config-array": "^0.11.6", 934 | "@humanwhocodes/module-importer": "^1.0.1", 935 | "@nodelib/fs.walk": "^1.2.8", 936 | "ajv": "^6.10.0", 937 | "chalk": "^4.0.0", 938 | "cross-spawn": "^7.0.2", 939 | "debug": "^4.3.2", 940 | "doctrine": "^3.0.0", 941 | "escape-string-regexp": "^4.0.0", 942 | "eslint-scope": "^7.1.1", 943 | "eslint-utils": "^3.0.0", 944 | "eslint-visitor-keys": "^3.3.0", 945 | "espree": "^9.4.0", 946 | "esquery": "^1.4.0", 947 | "esutils": "^2.0.2", 948 | "fast-deep-equal": "^3.1.3", 949 | "file-entry-cache": "^6.0.1", 950 | "find-up": "^5.0.0", 951 | "glob-parent": "^6.0.2", 952 | "globals": "^13.15.0", 953 | "grapheme-splitter": "^1.0.4", 954 | "ignore": "^5.2.0", 955 | "import-fresh": "^3.0.0", 956 | "imurmurhash": "^0.1.4", 957 | "is-glob": "^4.0.0", 958 | "is-path-inside": "^3.0.3", 959 | "js-sdsl": "^4.1.4", 960 | "js-yaml": "^4.1.0", 961 | "json-stable-stringify-without-jsonify": "^1.0.1", 962 | "levn": "^0.4.1", 963 | "lodash.merge": "^4.6.2", 964 | "minimatch": "^3.1.2", 965 | "natural-compare": "^1.4.0", 966 | "optionator": "^0.9.1", 967 | "regexpp": "^3.2.0", 968 | "strip-ansi": "^6.0.1", 969 | "strip-json-comments": "^3.1.0", 970 | "text-table": "^0.2.0" 971 | }, 972 | "bin": { 973 | "eslint": "bin/eslint.js" 974 | }, 975 | "engines": { 976 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 977 | }, 978 | "funding": { 979 | "url": "https://opencollective.com/eslint" 980 | } 981 | }, 982 | "node_modules/eslint-config-prettier": { 983 | "version": "8.5.0", 984 | "dev": true, 985 | "license": "MIT", 986 | "bin": { 987 | "eslint-config-prettier": "bin/cli.js" 988 | }, 989 | "peerDependencies": { 990 | "eslint": ">=7.0.0" 991 | } 992 | }, 993 | "node_modules/eslint-plugin-svelte3": { 994 | "version": "4.0.0", 995 | "dev": true, 996 | "license": "MIT", 997 | "peerDependencies": { 998 | "eslint": ">=8.0.0", 999 | "svelte": "^3.2.0" 1000 | } 1001 | }, 1002 | "node_modules/eslint-scope": { 1003 | "version": "7.1.1", 1004 | "dev": true, 1005 | "license": "BSD-2-Clause", 1006 | "dependencies": { 1007 | "esrecurse": "^4.3.0", 1008 | "estraverse": "^5.2.0" 1009 | }, 1010 | "engines": { 1011 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 1012 | } 1013 | }, 1014 | "node_modules/eslint-utils": { 1015 | "version": "3.0.0", 1016 | "dev": true, 1017 | "license": "MIT", 1018 | "dependencies": { 1019 | "eslint-visitor-keys": "^2.0.0" 1020 | }, 1021 | "engines": { 1022 | "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" 1023 | }, 1024 | "funding": { 1025 | "url": "https://github.com/sponsors/mysticatea" 1026 | }, 1027 | "peerDependencies": { 1028 | "eslint": ">=5" 1029 | } 1030 | }, 1031 | "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { 1032 | "version": "2.1.0", 1033 | "dev": true, 1034 | "license": "Apache-2.0", 1035 | "engines": { 1036 | "node": ">=10" 1037 | } 1038 | }, 1039 | "node_modules/eslint-visitor-keys": { 1040 | "version": "3.3.0", 1041 | "dev": true, 1042 | "license": "Apache-2.0", 1043 | "engines": { 1044 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 1045 | } 1046 | }, 1047 | "node_modules/espree": { 1048 | "version": "9.4.0", 1049 | "dev": true, 1050 | "license": "BSD-2-Clause", 1051 | "dependencies": { 1052 | "acorn": "^8.8.0", 1053 | "acorn-jsx": "^5.3.2", 1054 | "eslint-visitor-keys": "^3.3.0" 1055 | }, 1056 | "engines": { 1057 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 1058 | }, 1059 | "funding": { 1060 | "url": "https://opencollective.com/eslint" 1061 | } 1062 | }, 1063 | "node_modules/esquery": { 1064 | "version": "1.4.0", 1065 | "dev": true, 1066 | "license": "BSD-3-Clause", 1067 | "dependencies": { 1068 | "estraverse": "^5.1.0" 1069 | }, 1070 | "engines": { 1071 | "node": ">=0.10" 1072 | } 1073 | }, 1074 | "node_modules/esrecurse": { 1075 | "version": "4.3.0", 1076 | "dev": true, 1077 | "license": "BSD-2-Clause", 1078 | "dependencies": { 1079 | "estraverse": "^5.2.0" 1080 | }, 1081 | "engines": { 1082 | "node": ">=4.0" 1083 | } 1084 | }, 1085 | "node_modules/estraverse": { 1086 | "version": "5.3.0", 1087 | "dev": true, 1088 | "license": "BSD-2-Clause", 1089 | "engines": { 1090 | "node": ">=4.0" 1091 | } 1092 | }, 1093 | "node_modules/estree-walker": { 1094 | "version": "2.0.2", 1095 | "dev": true, 1096 | "license": "MIT" 1097 | }, 1098 | "node_modules/esutils": { 1099 | "version": "2.0.3", 1100 | "dev": true, 1101 | "license": "BSD-2-Clause", 1102 | "engines": { 1103 | "node": ">=0.10.0" 1104 | } 1105 | }, 1106 | "node_modules/fast-deep-equal": { 1107 | "version": "3.1.3", 1108 | "dev": true, 1109 | "license": "MIT" 1110 | }, 1111 | "node_modules/fast-glob": { 1112 | "version": "3.2.12", 1113 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", 1114 | "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", 1115 | "dev": true, 1116 | "dependencies": { 1117 | "@nodelib/fs.stat": "^2.0.2", 1118 | "@nodelib/fs.walk": "^1.2.3", 1119 | "glob-parent": "^5.1.2", 1120 | "merge2": "^1.3.0", 1121 | "micromatch": "^4.0.4" 1122 | }, 1123 | "engines": { 1124 | "node": ">=8.6.0" 1125 | } 1126 | }, 1127 | "node_modules/fast-glob/node_modules/glob-parent": { 1128 | "version": "5.1.2", 1129 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1130 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1131 | "dev": true, 1132 | "dependencies": { 1133 | "is-glob": "^4.0.1" 1134 | }, 1135 | "engines": { 1136 | "node": ">= 6" 1137 | } 1138 | }, 1139 | "node_modules/fast-json-stable-stringify": { 1140 | "version": "2.1.0", 1141 | "dev": true, 1142 | "license": "MIT" 1143 | }, 1144 | "node_modules/fast-levenshtein": { 1145 | "version": "2.0.6", 1146 | "dev": true, 1147 | "license": "MIT" 1148 | }, 1149 | "node_modules/fastq": { 1150 | "version": "1.13.0", 1151 | "dev": true, 1152 | "license": "ISC", 1153 | "dependencies": { 1154 | "reusify": "^1.0.4" 1155 | } 1156 | }, 1157 | "node_modules/file-entry-cache": { 1158 | "version": "6.0.1", 1159 | "dev": true, 1160 | "license": "MIT", 1161 | "dependencies": { 1162 | "flat-cache": "^3.0.4" 1163 | }, 1164 | "engines": { 1165 | "node": "^10.12.0 || >=12.0.0" 1166 | } 1167 | }, 1168 | "node_modules/file-uri-to-path": { 1169 | "version": "1.0.0", 1170 | "dev": true, 1171 | "license": "MIT" 1172 | }, 1173 | "node_modules/fill-range": { 1174 | "version": "7.0.1", 1175 | "dev": true, 1176 | "license": "MIT", 1177 | "dependencies": { 1178 | "to-regex-range": "^5.0.1" 1179 | }, 1180 | "engines": { 1181 | "node": ">=8" 1182 | } 1183 | }, 1184 | "node_modules/find-up": { 1185 | "version": "5.0.0", 1186 | "dev": true, 1187 | "license": "MIT", 1188 | "dependencies": { 1189 | "locate-path": "^6.0.0", 1190 | "path-exists": "^4.0.0" 1191 | }, 1192 | "engines": { 1193 | "node": ">=10" 1194 | }, 1195 | "funding": { 1196 | "url": "https://github.com/sponsors/sindresorhus" 1197 | } 1198 | }, 1199 | "node_modules/flat-cache": { 1200 | "version": "3.0.4", 1201 | "dev": true, 1202 | "license": "MIT", 1203 | "dependencies": { 1204 | "flatted": "^3.1.0", 1205 | "rimraf": "^3.0.2" 1206 | }, 1207 | "engines": { 1208 | "node": "^10.12.0 || >=12.0.0" 1209 | } 1210 | }, 1211 | "node_modules/flatted": { 1212 | "version": "3.2.7", 1213 | "dev": true, 1214 | "license": "ISC" 1215 | }, 1216 | "node_modules/fraction.js": { 1217 | "version": "4.2.0", 1218 | "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", 1219 | "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", 1220 | "dev": true, 1221 | "engines": { 1222 | "node": "*" 1223 | }, 1224 | "funding": { 1225 | "type": "patreon", 1226 | "url": "https://www.patreon.com/infusion" 1227 | } 1228 | }, 1229 | "node_modules/fs-minipass": { 1230 | "version": "2.1.0", 1231 | "dev": true, 1232 | "license": "ISC", 1233 | "dependencies": { 1234 | "minipass": "^3.0.0" 1235 | }, 1236 | "engines": { 1237 | "node": ">= 8" 1238 | } 1239 | }, 1240 | "node_modules/fs.realpath": { 1241 | "version": "1.0.0", 1242 | "dev": true, 1243 | "license": "ISC" 1244 | }, 1245 | "node_modules/fsevents": { 1246 | "version": "2.3.2", 1247 | "dev": true, 1248 | "license": "MIT", 1249 | "optional": true, 1250 | "os": [ 1251 | "darwin" 1252 | ], 1253 | "engines": { 1254 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1255 | } 1256 | }, 1257 | "node_modules/function-bind": { 1258 | "version": "1.1.1", 1259 | "dev": true, 1260 | "license": "MIT" 1261 | }, 1262 | "node_modules/gauge": { 1263 | "version": "3.0.2", 1264 | "dev": true, 1265 | "license": "ISC", 1266 | "dependencies": { 1267 | "aproba": "^1.0.3 || ^2.0.0", 1268 | "color-support": "^1.1.2", 1269 | "console-control-strings": "^1.0.0", 1270 | "has-unicode": "^2.0.1", 1271 | "object-assign": "^4.1.1", 1272 | "signal-exit": "^3.0.0", 1273 | "string-width": "^4.2.3", 1274 | "strip-ansi": "^6.0.1", 1275 | "wide-align": "^1.1.2" 1276 | }, 1277 | "engines": { 1278 | "node": ">=10" 1279 | } 1280 | }, 1281 | "node_modules/glob": { 1282 | "version": "7.2.3", 1283 | "dev": true, 1284 | "license": "ISC", 1285 | "dependencies": { 1286 | "fs.realpath": "^1.0.0", 1287 | "inflight": "^1.0.4", 1288 | "inherits": "2", 1289 | "minimatch": "^3.1.1", 1290 | "once": "^1.3.0", 1291 | "path-is-absolute": "^1.0.0" 1292 | }, 1293 | "engines": { 1294 | "node": "*" 1295 | }, 1296 | "funding": { 1297 | "url": "https://github.com/sponsors/isaacs" 1298 | } 1299 | }, 1300 | "node_modules/glob-parent": { 1301 | "version": "6.0.2", 1302 | "dev": true, 1303 | "license": "ISC", 1304 | "dependencies": { 1305 | "is-glob": "^4.0.3" 1306 | }, 1307 | "engines": { 1308 | "node": ">=10.13.0" 1309 | } 1310 | }, 1311 | "node_modules/globals": { 1312 | "version": "13.17.0", 1313 | "dev": true, 1314 | "license": "MIT", 1315 | "dependencies": { 1316 | "type-fest": "^0.20.2" 1317 | }, 1318 | "engines": { 1319 | "node": ">=8" 1320 | }, 1321 | "funding": { 1322 | "url": "https://github.com/sponsors/sindresorhus" 1323 | } 1324 | }, 1325 | "node_modules/globalyzer": { 1326 | "version": "0.1.0", 1327 | "dev": true, 1328 | "license": "MIT" 1329 | }, 1330 | "node_modules/globrex": { 1331 | "version": "0.1.2", 1332 | "dev": true, 1333 | "license": "MIT" 1334 | }, 1335 | "node_modules/graceful-fs": { 1336 | "version": "4.2.10", 1337 | "dev": true, 1338 | "license": "ISC" 1339 | }, 1340 | "node_modules/grapheme-splitter": { 1341 | "version": "1.0.4", 1342 | "dev": true, 1343 | "license": "MIT" 1344 | }, 1345 | "node_modules/has": { 1346 | "version": "1.0.3", 1347 | "dev": true, 1348 | "license": "MIT", 1349 | "dependencies": { 1350 | "function-bind": "^1.1.1" 1351 | }, 1352 | "engines": { 1353 | "node": ">= 0.4.0" 1354 | } 1355 | }, 1356 | "node_modules/has-flag": { 1357 | "version": "4.0.0", 1358 | "dev": true, 1359 | "license": "MIT", 1360 | "engines": { 1361 | "node": ">=8" 1362 | } 1363 | }, 1364 | "node_modules/has-unicode": { 1365 | "version": "2.0.1", 1366 | "dev": true, 1367 | "license": "ISC" 1368 | }, 1369 | "node_modules/https-proxy-agent": { 1370 | "version": "5.0.1", 1371 | "dev": true, 1372 | "license": "MIT", 1373 | "dependencies": { 1374 | "agent-base": "6", 1375 | "debug": "4" 1376 | }, 1377 | "engines": { 1378 | "node": ">= 6" 1379 | } 1380 | }, 1381 | "node_modules/ignore": { 1382 | "version": "5.2.0", 1383 | "dev": true, 1384 | "license": "MIT", 1385 | "engines": { 1386 | "node": ">= 4" 1387 | } 1388 | }, 1389 | "node_modules/import-fresh": { 1390 | "version": "3.3.0", 1391 | "dev": true, 1392 | "license": "MIT", 1393 | "dependencies": { 1394 | "parent-module": "^1.0.0", 1395 | "resolve-from": "^4.0.0" 1396 | }, 1397 | "engines": { 1398 | "node": ">=6" 1399 | }, 1400 | "funding": { 1401 | "url": "https://github.com/sponsors/sindresorhus" 1402 | } 1403 | }, 1404 | "node_modules/import-fresh/node_modules/resolve-from": { 1405 | "version": "4.0.0", 1406 | "dev": true, 1407 | "license": "MIT", 1408 | "engines": { 1409 | "node": ">=4" 1410 | } 1411 | }, 1412 | "node_modules/imurmurhash": { 1413 | "version": "0.1.4", 1414 | "dev": true, 1415 | "license": "MIT", 1416 | "engines": { 1417 | "node": ">=0.8.19" 1418 | } 1419 | }, 1420 | "node_modules/inflight": { 1421 | "version": "1.0.6", 1422 | "dev": true, 1423 | "license": "ISC", 1424 | "dependencies": { 1425 | "once": "^1.3.0", 1426 | "wrappy": "1" 1427 | } 1428 | }, 1429 | "node_modules/inherits": { 1430 | "version": "2.0.4", 1431 | "dev": true, 1432 | "license": "ISC" 1433 | }, 1434 | "node_modules/is-binary-path": { 1435 | "version": "2.1.0", 1436 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1437 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1438 | "dev": true, 1439 | "dependencies": { 1440 | "binary-extensions": "^2.0.0" 1441 | }, 1442 | "engines": { 1443 | "node": ">=8" 1444 | } 1445 | }, 1446 | "node_modules/is-core-module": { 1447 | "version": "2.11.0", 1448 | "dev": true, 1449 | "license": "MIT", 1450 | "dependencies": { 1451 | "has": "^1.0.3" 1452 | }, 1453 | "funding": { 1454 | "url": "https://github.com/sponsors/ljharb" 1455 | } 1456 | }, 1457 | "node_modules/is-extglob": { 1458 | "version": "2.1.1", 1459 | "dev": true, 1460 | "license": "MIT", 1461 | "engines": { 1462 | "node": ">=0.10.0" 1463 | } 1464 | }, 1465 | "node_modules/is-fullwidth-code-point": { 1466 | "version": "3.0.0", 1467 | "dev": true, 1468 | "license": "MIT", 1469 | "engines": { 1470 | "node": ">=8" 1471 | } 1472 | }, 1473 | "node_modules/is-glob": { 1474 | "version": "4.0.3", 1475 | "dev": true, 1476 | "license": "MIT", 1477 | "dependencies": { 1478 | "is-extglob": "^2.1.1" 1479 | }, 1480 | "engines": { 1481 | "node": ">=0.10.0" 1482 | } 1483 | }, 1484 | "node_modules/is-number": { 1485 | "version": "7.0.0", 1486 | "dev": true, 1487 | "license": "MIT", 1488 | "engines": { 1489 | "node": ">=0.12.0" 1490 | } 1491 | }, 1492 | "node_modules/is-path-inside": { 1493 | "version": "3.0.3", 1494 | "dev": true, 1495 | "license": "MIT", 1496 | "engines": { 1497 | "node": ">=8" 1498 | } 1499 | }, 1500 | "node_modules/isexe": { 1501 | "version": "2.0.0", 1502 | "dev": true, 1503 | "license": "ISC" 1504 | }, 1505 | "node_modules/js-sdsl": { 1506 | "version": "4.1.5", 1507 | "dev": true, 1508 | "license": "MIT" 1509 | }, 1510 | "node_modules/js-yaml": { 1511 | "version": "4.1.0", 1512 | "dev": true, 1513 | "license": "MIT", 1514 | "dependencies": { 1515 | "argparse": "^2.0.1" 1516 | }, 1517 | "bin": { 1518 | "js-yaml": "bin/js-yaml.js" 1519 | } 1520 | }, 1521 | "node_modules/json-schema-traverse": { 1522 | "version": "0.4.1", 1523 | "dev": true, 1524 | "license": "MIT" 1525 | }, 1526 | "node_modules/json-stable-stringify-without-jsonify": { 1527 | "version": "1.0.1", 1528 | "dev": true, 1529 | "license": "MIT" 1530 | }, 1531 | "node_modules/kleur": { 1532 | "version": "4.1.5", 1533 | "dev": true, 1534 | "license": "MIT", 1535 | "engines": { 1536 | "node": ">=6" 1537 | } 1538 | }, 1539 | "node_modules/levn": { 1540 | "version": "0.4.1", 1541 | "dev": true, 1542 | "license": "MIT", 1543 | "dependencies": { 1544 | "prelude-ls": "^1.2.1", 1545 | "type-check": "~0.4.0" 1546 | }, 1547 | "engines": { 1548 | "node": ">= 0.8.0" 1549 | } 1550 | }, 1551 | "node_modules/lilconfig": { 1552 | "version": "2.0.6", 1553 | "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", 1554 | "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", 1555 | "dev": true, 1556 | "engines": { 1557 | "node": ">=10" 1558 | } 1559 | }, 1560 | "node_modules/locate-path": { 1561 | "version": "6.0.0", 1562 | "dev": true, 1563 | "license": "MIT", 1564 | "dependencies": { 1565 | "p-locate": "^5.0.0" 1566 | }, 1567 | "engines": { 1568 | "node": ">=10" 1569 | }, 1570 | "funding": { 1571 | "url": "https://github.com/sponsors/sindresorhus" 1572 | } 1573 | }, 1574 | "node_modules/lodash.merge": { 1575 | "version": "4.6.2", 1576 | "dev": true, 1577 | "license": "MIT" 1578 | }, 1579 | "node_modules/lru-cache": { 1580 | "version": "6.0.0", 1581 | "dev": true, 1582 | "license": "ISC", 1583 | "dependencies": { 1584 | "yallist": "^4.0.0" 1585 | }, 1586 | "engines": { 1587 | "node": ">=10" 1588 | } 1589 | }, 1590 | "node_modules/magic-string": { 1591 | "version": "0.26.7", 1592 | "dev": true, 1593 | "license": "MIT", 1594 | "dependencies": { 1595 | "sourcemap-codec": "^1.4.8" 1596 | }, 1597 | "engines": { 1598 | "node": ">=12" 1599 | } 1600 | }, 1601 | "node_modules/make-dir": { 1602 | "version": "3.1.0", 1603 | "dev": true, 1604 | "license": "MIT", 1605 | "dependencies": { 1606 | "semver": "^6.0.0" 1607 | }, 1608 | "engines": { 1609 | "node": ">=8" 1610 | }, 1611 | "funding": { 1612 | "url": "https://github.com/sponsors/sindresorhus" 1613 | } 1614 | }, 1615 | "node_modules/make-dir/node_modules/semver": { 1616 | "version": "6.3.0", 1617 | "dev": true, 1618 | "license": "ISC", 1619 | "bin": { 1620 | "semver": "bin/semver.js" 1621 | } 1622 | }, 1623 | "node_modules/merge2": { 1624 | "version": "1.4.1", 1625 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1626 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1627 | "dev": true, 1628 | "engines": { 1629 | "node": ">= 8" 1630 | } 1631 | }, 1632 | "node_modules/micromatch": { 1633 | "version": "4.0.5", 1634 | "dev": true, 1635 | "license": "MIT", 1636 | "dependencies": { 1637 | "braces": "^3.0.2", 1638 | "picomatch": "^2.3.1" 1639 | }, 1640 | "engines": { 1641 | "node": ">=8.6" 1642 | } 1643 | }, 1644 | "node_modules/mime": { 1645 | "version": "3.0.0", 1646 | "dev": true, 1647 | "license": "MIT", 1648 | "bin": { 1649 | "mime": "cli.js" 1650 | }, 1651 | "engines": { 1652 | "node": ">=10.0.0" 1653 | } 1654 | }, 1655 | "node_modules/min-indent": { 1656 | "version": "1.0.1", 1657 | "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", 1658 | "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", 1659 | "dev": true, 1660 | "engines": { 1661 | "node": ">=4" 1662 | } 1663 | }, 1664 | "node_modules/minimatch": { 1665 | "version": "3.1.2", 1666 | "dev": true, 1667 | "license": "ISC", 1668 | "dependencies": { 1669 | "brace-expansion": "^1.1.7" 1670 | }, 1671 | "engines": { 1672 | "node": "*" 1673 | } 1674 | }, 1675 | "node_modules/minimist": { 1676 | "version": "1.2.7", 1677 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", 1678 | "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", 1679 | "dev": true, 1680 | "funding": { 1681 | "url": "https://github.com/sponsors/ljharb" 1682 | } 1683 | }, 1684 | "node_modules/minipass": { 1685 | "version": "3.3.4", 1686 | "dev": true, 1687 | "license": "ISC", 1688 | "dependencies": { 1689 | "yallist": "^4.0.0" 1690 | }, 1691 | "engines": { 1692 | "node": ">=8" 1693 | } 1694 | }, 1695 | "node_modules/minizlib": { 1696 | "version": "2.1.2", 1697 | "dev": true, 1698 | "license": "MIT", 1699 | "dependencies": { 1700 | "minipass": "^3.0.0", 1701 | "yallist": "^4.0.0" 1702 | }, 1703 | "engines": { 1704 | "node": ">= 8" 1705 | } 1706 | }, 1707 | "node_modules/mkdirp": { 1708 | "version": "1.0.4", 1709 | "dev": true, 1710 | "license": "MIT", 1711 | "bin": { 1712 | "mkdirp": "bin/cmd.js" 1713 | }, 1714 | "engines": { 1715 | "node": ">=10" 1716 | } 1717 | }, 1718 | "node_modules/mri": { 1719 | "version": "1.2.0", 1720 | "dev": true, 1721 | "license": "MIT", 1722 | "engines": { 1723 | "node": ">=4" 1724 | } 1725 | }, 1726 | "node_modules/mrmime": { 1727 | "version": "1.0.1", 1728 | "dev": true, 1729 | "license": "MIT", 1730 | "engines": { 1731 | "node": ">=10" 1732 | } 1733 | }, 1734 | "node_modules/ms": { 1735 | "version": "2.1.2", 1736 | "dev": true, 1737 | "license": "MIT" 1738 | }, 1739 | "node_modules/nanoid": { 1740 | "version": "3.3.4", 1741 | "dev": true, 1742 | "license": "MIT", 1743 | "bin": { 1744 | "nanoid": "bin/nanoid.cjs" 1745 | }, 1746 | "engines": { 1747 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1748 | } 1749 | }, 1750 | "node_modules/natural-compare": { 1751 | "version": "1.4.0", 1752 | "dev": true, 1753 | "license": "MIT" 1754 | }, 1755 | "node_modules/node-fetch": { 1756 | "version": "2.6.7", 1757 | "dev": true, 1758 | "license": "MIT", 1759 | "dependencies": { 1760 | "whatwg-url": "^5.0.0" 1761 | }, 1762 | "engines": { 1763 | "node": "4.x || >=6.0.0" 1764 | }, 1765 | "peerDependencies": { 1766 | "encoding": "^0.1.0" 1767 | }, 1768 | "peerDependenciesMeta": { 1769 | "encoding": { 1770 | "optional": true 1771 | } 1772 | } 1773 | }, 1774 | "node_modules/node-gyp-build": { 1775 | "version": "4.5.0", 1776 | "dev": true, 1777 | "license": "MIT", 1778 | "bin": { 1779 | "node-gyp-build": "bin.js", 1780 | "node-gyp-build-optional": "optional.js", 1781 | "node-gyp-build-test": "build-test.js" 1782 | } 1783 | }, 1784 | "node_modules/node-releases": { 1785 | "version": "2.0.6", 1786 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", 1787 | "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", 1788 | "dev": true 1789 | }, 1790 | "node_modules/nopt": { 1791 | "version": "5.0.0", 1792 | "dev": true, 1793 | "license": "ISC", 1794 | "dependencies": { 1795 | "abbrev": "1" 1796 | }, 1797 | "bin": { 1798 | "nopt": "bin/nopt.js" 1799 | }, 1800 | "engines": { 1801 | "node": ">=6" 1802 | } 1803 | }, 1804 | "node_modules/normalize-path": { 1805 | "version": "3.0.0", 1806 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1807 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1808 | "dev": true, 1809 | "engines": { 1810 | "node": ">=0.10.0" 1811 | } 1812 | }, 1813 | "node_modules/normalize-range": { 1814 | "version": "0.1.2", 1815 | "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", 1816 | "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", 1817 | "dev": true, 1818 | "engines": { 1819 | "node": ">=0.10.0" 1820 | } 1821 | }, 1822 | "node_modules/npmlog": { 1823 | "version": "5.0.1", 1824 | "dev": true, 1825 | "license": "ISC", 1826 | "dependencies": { 1827 | "are-we-there-yet": "^2.0.0", 1828 | "console-control-strings": "^1.1.0", 1829 | "gauge": "^3.0.0", 1830 | "set-blocking": "^2.0.0" 1831 | } 1832 | }, 1833 | "node_modules/object-assign": { 1834 | "version": "4.1.1", 1835 | "dev": true, 1836 | "license": "MIT", 1837 | "engines": { 1838 | "node": ">=0.10.0" 1839 | } 1840 | }, 1841 | "node_modules/object-hash": { 1842 | "version": "3.0.0", 1843 | "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", 1844 | "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", 1845 | "dev": true, 1846 | "engines": { 1847 | "node": ">= 6" 1848 | } 1849 | }, 1850 | "node_modules/once": { 1851 | "version": "1.4.0", 1852 | "dev": true, 1853 | "license": "ISC", 1854 | "dependencies": { 1855 | "wrappy": "1" 1856 | } 1857 | }, 1858 | "node_modules/optionator": { 1859 | "version": "0.9.1", 1860 | "dev": true, 1861 | "license": "MIT", 1862 | "dependencies": { 1863 | "deep-is": "^0.1.3", 1864 | "fast-levenshtein": "^2.0.6", 1865 | "levn": "^0.4.1", 1866 | "prelude-ls": "^1.2.1", 1867 | "type-check": "^0.4.0", 1868 | "word-wrap": "^1.2.3" 1869 | }, 1870 | "engines": { 1871 | "node": ">= 0.8.0" 1872 | } 1873 | }, 1874 | "node_modules/p-limit": { 1875 | "version": "3.1.0", 1876 | "dev": true, 1877 | "license": "MIT", 1878 | "dependencies": { 1879 | "yocto-queue": "^0.1.0" 1880 | }, 1881 | "engines": { 1882 | "node": ">=10" 1883 | }, 1884 | "funding": { 1885 | "url": "https://github.com/sponsors/sindresorhus" 1886 | } 1887 | }, 1888 | "node_modules/p-locate": { 1889 | "version": "5.0.0", 1890 | "dev": true, 1891 | "license": "MIT", 1892 | "dependencies": { 1893 | "p-limit": "^3.0.2" 1894 | }, 1895 | "engines": { 1896 | "node": ">=10" 1897 | }, 1898 | "funding": { 1899 | "url": "https://github.com/sponsors/sindresorhus" 1900 | } 1901 | }, 1902 | "node_modules/parent-module": { 1903 | "version": "1.0.1", 1904 | "dev": true, 1905 | "license": "MIT", 1906 | "dependencies": { 1907 | "callsites": "^3.0.0" 1908 | }, 1909 | "engines": { 1910 | "node": ">=6" 1911 | } 1912 | }, 1913 | "node_modules/path-exists": { 1914 | "version": "4.0.0", 1915 | "dev": true, 1916 | "license": "MIT", 1917 | "engines": { 1918 | "node": ">=8" 1919 | } 1920 | }, 1921 | "node_modules/path-is-absolute": { 1922 | "version": "1.0.1", 1923 | "dev": true, 1924 | "license": "MIT", 1925 | "engines": { 1926 | "node": ">=0.10.0" 1927 | } 1928 | }, 1929 | "node_modules/path-key": { 1930 | "version": "3.1.1", 1931 | "dev": true, 1932 | "license": "MIT", 1933 | "engines": { 1934 | "node": ">=8" 1935 | } 1936 | }, 1937 | "node_modules/path-parse": { 1938 | "version": "1.0.7", 1939 | "dev": true, 1940 | "license": "MIT" 1941 | }, 1942 | "node_modules/picocolors": { 1943 | "version": "1.0.0", 1944 | "dev": true, 1945 | "license": "ISC" 1946 | }, 1947 | "node_modules/picomatch": { 1948 | "version": "2.3.1", 1949 | "dev": true, 1950 | "license": "MIT", 1951 | "engines": { 1952 | "node": ">=8.6" 1953 | }, 1954 | "funding": { 1955 | "url": "https://github.com/sponsors/jonschlinkert" 1956 | } 1957 | }, 1958 | "node_modules/pify": { 1959 | "version": "2.3.0", 1960 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 1961 | "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", 1962 | "dev": true, 1963 | "engines": { 1964 | "node": ">=0.10.0" 1965 | } 1966 | }, 1967 | "node_modules/postcss": { 1968 | "version": "8.4.18", 1969 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", 1970 | "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", 1971 | "dev": true, 1972 | "funding": [ 1973 | { 1974 | "type": "opencollective", 1975 | "url": "https://opencollective.com/postcss/" 1976 | }, 1977 | { 1978 | "type": "tidelift", 1979 | "url": "https://tidelift.com/funding/github/npm/postcss" 1980 | } 1981 | ], 1982 | "dependencies": { 1983 | "nanoid": "^3.3.4", 1984 | "picocolors": "^1.0.0", 1985 | "source-map-js": "^1.0.2" 1986 | }, 1987 | "engines": { 1988 | "node": "^10 || ^12 || >=14" 1989 | } 1990 | }, 1991 | "node_modules/postcss-import": { 1992 | "version": "14.1.0", 1993 | "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", 1994 | "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", 1995 | "dev": true, 1996 | "dependencies": { 1997 | "postcss-value-parser": "^4.0.0", 1998 | "read-cache": "^1.0.0", 1999 | "resolve": "^1.1.7" 2000 | }, 2001 | "engines": { 2002 | "node": ">=10.0.0" 2003 | }, 2004 | "peerDependencies": { 2005 | "postcss": "^8.0.0" 2006 | } 2007 | }, 2008 | "node_modules/postcss-js": { 2009 | "version": "4.0.0", 2010 | "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", 2011 | "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", 2012 | "dev": true, 2013 | "dependencies": { 2014 | "camelcase-css": "^2.0.1" 2015 | }, 2016 | "engines": { 2017 | "node": "^12 || ^14 || >= 16" 2018 | }, 2019 | "funding": { 2020 | "type": "opencollective", 2021 | "url": "https://opencollective.com/postcss/" 2022 | }, 2023 | "peerDependencies": { 2024 | "postcss": "^8.3.3" 2025 | } 2026 | }, 2027 | "node_modules/postcss-load-config": { 2028 | "version": "3.1.4", 2029 | "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", 2030 | "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", 2031 | "dev": true, 2032 | "dependencies": { 2033 | "lilconfig": "^2.0.5", 2034 | "yaml": "^1.10.2" 2035 | }, 2036 | "engines": { 2037 | "node": ">= 10" 2038 | }, 2039 | "funding": { 2040 | "type": "opencollective", 2041 | "url": "https://opencollective.com/postcss/" 2042 | }, 2043 | "peerDependencies": { 2044 | "postcss": ">=8.0.9", 2045 | "ts-node": ">=9.0.0" 2046 | }, 2047 | "peerDependenciesMeta": { 2048 | "postcss": { 2049 | "optional": true 2050 | }, 2051 | "ts-node": { 2052 | "optional": true 2053 | } 2054 | } 2055 | }, 2056 | "node_modules/postcss-nested": { 2057 | "version": "6.0.0", 2058 | "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", 2059 | "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", 2060 | "dev": true, 2061 | "dependencies": { 2062 | "postcss-selector-parser": "^6.0.10" 2063 | }, 2064 | "engines": { 2065 | "node": ">=12.0" 2066 | }, 2067 | "funding": { 2068 | "type": "opencollective", 2069 | "url": "https://opencollective.com/postcss/" 2070 | }, 2071 | "peerDependencies": { 2072 | "postcss": "^8.2.14" 2073 | } 2074 | }, 2075 | "node_modules/postcss-selector-parser": { 2076 | "version": "6.0.10", 2077 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", 2078 | "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", 2079 | "dev": true, 2080 | "dependencies": { 2081 | "cssesc": "^3.0.0", 2082 | "util-deprecate": "^1.0.2" 2083 | }, 2084 | "engines": { 2085 | "node": ">=4" 2086 | } 2087 | }, 2088 | "node_modules/postcss-value-parser": { 2089 | "version": "4.2.0", 2090 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 2091 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 2092 | "dev": true 2093 | }, 2094 | "node_modules/prelude-ls": { 2095 | "version": "1.2.1", 2096 | "dev": true, 2097 | "license": "MIT", 2098 | "engines": { 2099 | "node": ">= 0.8.0" 2100 | } 2101 | }, 2102 | "node_modules/prettier": { 2103 | "version": "2.7.1", 2104 | "dev": true, 2105 | "license": "MIT", 2106 | "bin": { 2107 | "prettier": "bin-prettier.js" 2108 | }, 2109 | "engines": { 2110 | "node": ">=10.13.0" 2111 | }, 2112 | "funding": { 2113 | "url": "https://github.com/prettier/prettier?sponsor=1" 2114 | } 2115 | }, 2116 | "node_modules/prettier-plugin-svelte": { 2117 | "version": "2.8.0", 2118 | "dev": true, 2119 | "license": "MIT", 2120 | "peerDependencies": { 2121 | "prettier": "^1.16.4 || ^2.0.0", 2122 | "svelte": "^3.2.0" 2123 | } 2124 | }, 2125 | "node_modules/punycode": { 2126 | "version": "2.1.1", 2127 | "dev": true, 2128 | "license": "MIT", 2129 | "engines": { 2130 | "node": ">=6" 2131 | } 2132 | }, 2133 | "node_modules/queue-microtask": { 2134 | "version": "1.2.3", 2135 | "dev": true, 2136 | "funding": [ 2137 | { 2138 | "type": "github", 2139 | "url": "https://github.com/sponsors/feross" 2140 | }, 2141 | { 2142 | "type": "patreon", 2143 | "url": "https://www.patreon.com/feross" 2144 | }, 2145 | { 2146 | "type": "consulting", 2147 | "url": "https://feross.org/support" 2148 | } 2149 | ], 2150 | "license": "MIT" 2151 | }, 2152 | "node_modules/quick-lru": { 2153 | "version": "5.1.1", 2154 | "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", 2155 | "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", 2156 | "dev": true, 2157 | "engines": { 2158 | "node": ">=10" 2159 | }, 2160 | "funding": { 2161 | "url": "https://github.com/sponsors/sindresorhus" 2162 | } 2163 | }, 2164 | "node_modules/read-cache": { 2165 | "version": "1.0.0", 2166 | "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", 2167 | "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", 2168 | "dev": true, 2169 | "dependencies": { 2170 | "pify": "^2.3.0" 2171 | } 2172 | }, 2173 | "node_modules/readable-stream": { 2174 | "version": "3.6.0", 2175 | "dev": true, 2176 | "license": "MIT", 2177 | "dependencies": { 2178 | "inherits": "^2.0.3", 2179 | "string_decoder": "^1.1.1", 2180 | "util-deprecate": "^1.0.1" 2181 | }, 2182 | "engines": { 2183 | "node": ">= 6" 2184 | } 2185 | }, 2186 | "node_modules/readdirp": { 2187 | "version": "3.6.0", 2188 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 2189 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 2190 | "dev": true, 2191 | "dependencies": { 2192 | "picomatch": "^2.2.1" 2193 | }, 2194 | "engines": { 2195 | "node": ">=8.10.0" 2196 | } 2197 | }, 2198 | "node_modules/regexparam": { 2199 | "version": "2.0.1", 2200 | "dev": true, 2201 | "license": "MIT", 2202 | "engines": { 2203 | "node": ">=8" 2204 | } 2205 | }, 2206 | "node_modules/regexpp": { 2207 | "version": "3.2.0", 2208 | "dev": true, 2209 | "license": "MIT", 2210 | "engines": { 2211 | "node": ">=8" 2212 | }, 2213 | "funding": { 2214 | "url": "https://github.com/sponsors/mysticatea" 2215 | } 2216 | }, 2217 | "node_modules/resolve": { 2218 | "version": "1.22.1", 2219 | "dev": true, 2220 | "license": "MIT", 2221 | "dependencies": { 2222 | "is-core-module": "^2.9.0", 2223 | "path-parse": "^1.0.7", 2224 | "supports-preserve-symlinks-flag": "^1.0.0" 2225 | }, 2226 | "bin": { 2227 | "resolve": "bin/resolve" 2228 | }, 2229 | "funding": { 2230 | "url": "https://github.com/sponsors/ljharb" 2231 | } 2232 | }, 2233 | "node_modules/resolve-from": { 2234 | "version": "5.0.0", 2235 | "dev": true, 2236 | "license": "MIT", 2237 | "engines": { 2238 | "node": ">=8" 2239 | } 2240 | }, 2241 | "node_modules/reusify": { 2242 | "version": "1.0.4", 2243 | "dev": true, 2244 | "license": "MIT", 2245 | "engines": { 2246 | "iojs": ">=1.0.0", 2247 | "node": ">=0.10.0" 2248 | } 2249 | }, 2250 | "node_modules/rimraf": { 2251 | "version": "3.0.2", 2252 | "dev": true, 2253 | "license": "ISC", 2254 | "dependencies": { 2255 | "glob": "^7.1.3" 2256 | }, 2257 | "bin": { 2258 | "rimraf": "bin.js" 2259 | }, 2260 | "funding": { 2261 | "url": "https://github.com/sponsors/isaacs" 2262 | } 2263 | }, 2264 | "node_modules/rollup": { 2265 | "version": "2.78.1", 2266 | "dev": true, 2267 | "license": "MIT", 2268 | "bin": { 2269 | "rollup": "dist/bin/rollup" 2270 | }, 2271 | "engines": { 2272 | "node": ">=10.0.0" 2273 | }, 2274 | "optionalDependencies": { 2275 | "fsevents": "~2.3.2" 2276 | } 2277 | }, 2278 | "node_modules/rollup-pluginutils": { 2279 | "version": "2.8.2", 2280 | "dev": true, 2281 | "license": "MIT", 2282 | "dependencies": { 2283 | "estree-walker": "^0.6.1" 2284 | } 2285 | }, 2286 | "node_modules/rollup-pluginutils/node_modules/estree-walker": { 2287 | "version": "0.6.1", 2288 | "dev": true, 2289 | "license": "MIT" 2290 | }, 2291 | "node_modules/run-parallel": { 2292 | "version": "1.2.0", 2293 | "dev": true, 2294 | "funding": [ 2295 | { 2296 | "type": "github", 2297 | "url": "https://github.com/sponsors/feross" 2298 | }, 2299 | { 2300 | "type": "patreon", 2301 | "url": "https://www.patreon.com/feross" 2302 | }, 2303 | { 2304 | "type": "consulting", 2305 | "url": "https://feross.org/support" 2306 | } 2307 | ], 2308 | "license": "MIT", 2309 | "dependencies": { 2310 | "queue-microtask": "^1.2.2" 2311 | } 2312 | }, 2313 | "node_modules/sade": { 2314 | "version": "1.8.1", 2315 | "dev": true, 2316 | "license": "MIT", 2317 | "dependencies": { 2318 | "mri": "^1.1.0" 2319 | }, 2320 | "engines": { 2321 | "node": ">=6" 2322 | } 2323 | }, 2324 | "node_modules/safe-buffer": { 2325 | "version": "5.2.1", 2326 | "dev": true, 2327 | "funding": [ 2328 | { 2329 | "type": "github", 2330 | "url": "https://github.com/sponsors/feross" 2331 | }, 2332 | { 2333 | "type": "patreon", 2334 | "url": "https://www.patreon.com/feross" 2335 | }, 2336 | { 2337 | "type": "consulting", 2338 | "url": "https://feross.org/support" 2339 | } 2340 | ], 2341 | "license": "MIT" 2342 | }, 2343 | "node_modules/sander": { 2344 | "version": "0.5.1", 2345 | "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", 2346 | "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", 2347 | "dev": true, 2348 | "dependencies": { 2349 | "es6-promise": "^3.1.2", 2350 | "graceful-fs": "^4.1.3", 2351 | "mkdirp": "^0.5.1", 2352 | "rimraf": "^2.5.2" 2353 | } 2354 | }, 2355 | "node_modules/sander/node_modules/mkdirp": { 2356 | "version": "0.5.6", 2357 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", 2358 | "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", 2359 | "dev": true, 2360 | "dependencies": { 2361 | "minimist": "^1.2.6" 2362 | }, 2363 | "bin": { 2364 | "mkdirp": "bin/cmd.js" 2365 | } 2366 | }, 2367 | "node_modules/sander/node_modules/rimraf": { 2368 | "version": "2.7.1", 2369 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 2370 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 2371 | "dev": true, 2372 | "dependencies": { 2373 | "glob": "^7.1.3" 2374 | }, 2375 | "bin": { 2376 | "rimraf": "bin.js" 2377 | } 2378 | }, 2379 | "node_modules/semver": { 2380 | "version": "7.3.8", 2381 | "dev": true, 2382 | "license": "ISC", 2383 | "dependencies": { 2384 | "lru-cache": "^6.0.0" 2385 | }, 2386 | "bin": { 2387 | "semver": "bin/semver.js" 2388 | }, 2389 | "engines": { 2390 | "node": ">=10" 2391 | } 2392 | }, 2393 | "node_modules/set-blocking": { 2394 | "version": "2.0.0", 2395 | "dev": true, 2396 | "license": "ISC" 2397 | }, 2398 | "node_modules/set-cookie-parser": { 2399 | "version": "2.5.1", 2400 | "dev": true, 2401 | "license": "MIT" 2402 | }, 2403 | "node_modules/shebang-command": { 2404 | "version": "2.0.0", 2405 | "dev": true, 2406 | "license": "MIT", 2407 | "dependencies": { 2408 | "shebang-regex": "^3.0.0" 2409 | }, 2410 | "engines": { 2411 | "node": ">=8" 2412 | } 2413 | }, 2414 | "node_modules/shebang-regex": { 2415 | "version": "3.0.0", 2416 | "dev": true, 2417 | "license": "MIT", 2418 | "engines": { 2419 | "node": ">=8" 2420 | } 2421 | }, 2422 | "node_modules/signal-exit": { 2423 | "version": "3.0.7", 2424 | "dev": true, 2425 | "license": "ISC" 2426 | }, 2427 | "node_modules/sirv": { 2428 | "version": "2.0.2", 2429 | "dev": true, 2430 | "license": "MIT", 2431 | "dependencies": { 2432 | "@polka/url": "^1.0.0-next.20", 2433 | "mrmime": "^1.0.0", 2434 | "totalist": "^3.0.0" 2435 | }, 2436 | "engines": { 2437 | "node": ">= 10" 2438 | } 2439 | }, 2440 | "node_modules/sorcery": { 2441 | "version": "0.10.0", 2442 | "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.10.0.tgz", 2443 | "integrity": "sha512-R5ocFmKZQFfSTstfOtHjJuAwbpGyf9qjQa1egyhvXSbM7emjrtLXtGdZsDJDABC85YBfVvrOiGWKSYXPKdvP1g==", 2444 | "dev": true, 2445 | "dependencies": { 2446 | "buffer-crc32": "^0.2.5", 2447 | "minimist": "^1.2.0", 2448 | "sander": "^0.5.0", 2449 | "sourcemap-codec": "^1.3.0" 2450 | }, 2451 | "bin": { 2452 | "sorcery": "bin/index.js" 2453 | } 2454 | }, 2455 | "node_modules/source-map-js": { 2456 | "version": "1.0.2", 2457 | "dev": true, 2458 | "license": "BSD-3-Clause", 2459 | "engines": { 2460 | "node": ">=0.10.0" 2461 | } 2462 | }, 2463 | "node_modules/sourcemap-codec": { 2464 | "version": "1.4.8", 2465 | "dev": true, 2466 | "license": "MIT" 2467 | }, 2468 | "node_modules/streamsearch": { 2469 | "version": "1.1.0", 2470 | "dev": true, 2471 | "engines": { 2472 | "node": ">=10.0.0" 2473 | } 2474 | }, 2475 | "node_modules/string_decoder": { 2476 | "version": "1.3.0", 2477 | "dev": true, 2478 | "license": "MIT", 2479 | "dependencies": { 2480 | "safe-buffer": "~5.2.0" 2481 | } 2482 | }, 2483 | "node_modules/string-width": { 2484 | "version": "4.2.3", 2485 | "dev": true, 2486 | "license": "MIT", 2487 | "dependencies": { 2488 | "emoji-regex": "^8.0.0", 2489 | "is-fullwidth-code-point": "^3.0.0", 2490 | "strip-ansi": "^6.0.1" 2491 | }, 2492 | "engines": { 2493 | "node": ">=8" 2494 | } 2495 | }, 2496 | "node_modules/strip-ansi": { 2497 | "version": "6.0.1", 2498 | "dev": true, 2499 | "license": "MIT", 2500 | "dependencies": { 2501 | "ansi-regex": "^5.0.1" 2502 | }, 2503 | "engines": { 2504 | "node": ">=8" 2505 | } 2506 | }, 2507 | "node_modules/strip-indent": { 2508 | "version": "3.0.0", 2509 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", 2510 | "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", 2511 | "dev": true, 2512 | "dependencies": { 2513 | "min-indent": "^1.0.0" 2514 | }, 2515 | "engines": { 2516 | "node": ">=8" 2517 | } 2518 | }, 2519 | "node_modules/strip-json-comments": { 2520 | "version": "3.1.1", 2521 | "dev": true, 2522 | "license": "MIT", 2523 | "engines": { 2524 | "node": ">=8" 2525 | }, 2526 | "funding": { 2527 | "url": "https://github.com/sponsors/sindresorhus" 2528 | } 2529 | }, 2530 | "node_modules/supports-color": { 2531 | "version": "7.2.0", 2532 | "dev": true, 2533 | "license": "MIT", 2534 | "dependencies": { 2535 | "has-flag": "^4.0.0" 2536 | }, 2537 | "engines": { 2538 | "node": ">=8" 2539 | } 2540 | }, 2541 | "node_modules/supports-preserve-symlinks-flag": { 2542 | "version": "1.0.0", 2543 | "dev": true, 2544 | "license": "MIT", 2545 | "engines": { 2546 | "node": ">= 0.4" 2547 | }, 2548 | "funding": { 2549 | "url": "https://github.com/sponsors/ljharb" 2550 | } 2551 | }, 2552 | "node_modules/svelte": { 2553 | "version": "3.52.0", 2554 | "dev": true, 2555 | "license": "MIT", 2556 | "engines": { 2557 | "node": ">= 8" 2558 | } 2559 | }, 2560 | "node_modules/svelte-hmr": { 2561 | "version": "0.15.0", 2562 | "dev": true, 2563 | "license": "ISC", 2564 | "engines": { 2565 | "node": "^12.20 || ^14.13.1 || >= 16" 2566 | }, 2567 | "peerDependencies": { 2568 | "svelte": ">=3.19.0" 2569 | } 2570 | }, 2571 | "node_modules/svelte-preprocess": { 2572 | "version": "4.10.7", 2573 | "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.7.tgz", 2574 | "integrity": "sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==", 2575 | "dev": true, 2576 | "hasInstallScript": true, 2577 | "dependencies": { 2578 | "@types/pug": "^2.0.4", 2579 | "@types/sass": "^1.16.0", 2580 | "detect-indent": "^6.0.0", 2581 | "magic-string": "^0.25.7", 2582 | "sorcery": "^0.10.0", 2583 | "strip-indent": "^3.0.0" 2584 | }, 2585 | "engines": { 2586 | "node": ">= 9.11.2" 2587 | }, 2588 | "peerDependencies": { 2589 | "@babel/core": "^7.10.2", 2590 | "coffeescript": "^2.5.1", 2591 | "less": "^3.11.3 || ^4.0.0", 2592 | "postcss": "^7 || ^8", 2593 | "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0", 2594 | "pug": "^3.0.0", 2595 | "sass": "^1.26.8", 2596 | "stylus": "^0.55.0", 2597 | "sugarss": "^2.0.0", 2598 | "svelte": "^3.23.0", 2599 | "typescript": "^3.9.5 || ^4.0.0" 2600 | }, 2601 | "peerDependenciesMeta": { 2602 | "@babel/core": { 2603 | "optional": true 2604 | }, 2605 | "coffeescript": { 2606 | "optional": true 2607 | }, 2608 | "less": { 2609 | "optional": true 2610 | }, 2611 | "node-sass": { 2612 | "optional": true 2613 | }, 2614 | "postcss": { 2615 | "optional": true 2616 | }, 2617 | "postcss-load-config": { 2618 | "optional": true 2619 | }, 2620 | "pug": { 2621 | "optional": true 2622 | }, 2623 | "sass": { 2624 | "optional": true 2625 | }, 2626 | "stylus": { 2627 | "optional": true 2628 | }, 2629 | "sugarss": { 2630 | "optional": true 2631 | }, 2632 | "typescript": { 2633 | "optional": true 2634 | } 2635 | } 2636 | }, 2637 | "node_modules/svelte-preprocess/node_modules/magic-string": { 2638 | "version": "0.25.9", 2639 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", 2640 | "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", 2641 | "dev": true, 2642 | "dependencies": { 2643 | "sourcemap-codec": "^1.4.8" 2644 | } 2645 | }, 2646 | "node_modules/tailwindcss": { 2647 | "version": "3.2.1", 2648 | "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.1.tgz", 2649 | "integrity": "sha512-Uw+GVSxp5CM48krnjHObqoOwlCt5Qo6nw1jlCRwfGy68dSYb/LwS9ZFidYGRiM+w6rMawkZiu1mEMAsHYAfoLg==", 2650 | "dev": true, 2651 | "dependencies": { 2652 | "arg": "^5.0.2", 2653 | "chokidar": "^3.5.3", 2654 | "color-name": "^1.1.4", 2655 | "detective": "^5.2.1", 2656 | "didyoumean": "^1.2.2", 2657 | "dlv": "^1.1.3", 2658 | "fast-glob": "^3.2.12", 2659 | "glob-parent": "^6.0.2", 2660 | "is-glob": "^4.0.3", 2661 | "lilconfig": "^2.0.6", 2662 | "micromatch": "^4.0.5", 2663 | "normalize-path": "^3.0.0", 2664 | "object-hash": "^3.0.0", 2665 | "picocolors": "^1.0.0", 2666 | "postcss": "^8.4.17", 2667 | "postcss-import": "^14.1.0", 2668 | "postcss-js": "^4.0.0", 2669 | "postcss-load-config": "^3.1.4", 2670 | "postcss-nested": "6.0.0", 2671 | "postcss-selector-parser": "^6.0.10", 2672 | "postcss-value-parser": "^4.2.0", 2673 | "quick-lru": "^5.1.1", 2674 | "resolve": "^1.22.1" 2675 | }, 2676 | "bin": { 2677 | "tailwind": "lib/cli.js", 2678 | "tailwindcss": "lib/cli.js" 2679 | }, 2680 | "engines": { 2681 | "node": ">=12.13.0" 2682 | }, 2683 | "peerDependencies": { 2684 | "postcss": "^8.0.9" 2685 | } 2686 | }, 2687 | "node_modules/tar": { 2688 | "version": "6.1.11", 2689 | "dev": true, 2690 | "license": "ISC", 2691 | "dependencies": { 2692 | "chownr": "^2.0.0", 2693 | "fs-minipass": "^2.0.0", 2694 | "minipass": "^3.0.0", 2695 | "minizlib": "^2.1.1", 2696 | "mkdirp": "^1.0.3", 2697 | "yallist": "^4.0.0" 2698 | }, 2699 | "engines": { 2700 | "node": ">= 10" 2701 | } 2702 | }, 2703 | "node_modules/text-table": { 2704 | "version": "0.2.0", 2705 | "dev": true, 2706 | "license": "MIT" 2707 | }, 2708 | "node_modules/tiny-glob": { 2709 | "version": "0.2.9", 2710 | "dev": true, 2711 | "license": "MIT", 2712 | "dependencies": { 2713 | "globalyzer": "0.1.0", 2714 | "globrex": "^0.1.2" 2715 | } 2716 | }, 2717 | "node_modules/to-regex-range": { 2718 | "version": "5.0.1", 2719 | "dev": true, 2720 | "license": "MIT", 2721 | "dependencies": { 2722 | "is-number": "^7.0.0" 2723 | }, 2724 | "engines": { 2725 | "node": ">=8.0" 2726 | } 2727 | }, 2728 | "node_modules/totalist": { 2729 | "version": "3.0.0", 2730 | "dev": true, 2731 | "license": "MIT", 2732 | "engines": { 2733 | "node": ">=6" 2734 | } 2735 | }, 2736 | "node_modules/tr46": { 2737 | "version": "0.0.3", 2738 | "dev": true, 2739 | "license": "MIT" 2740 | }, 2741 | "node_modules/type-check": { 2742 | "version": "0.4.0", 2743 | "dev": true, 2744 | "license": "MIT", 2745 | "dependencies": { 2746 | "prelude-ls": "^1.2.1" 2747 | }, 2748 | "engines": { 2749 | "node": ">= 0.8.0" 2750 | } 2751 | }, 2752 | "node_modules/type-fest": { 2753 | "version": "0.20.2", 2754 | "dev": true, 2755 | "license": "(MIT OR CC0-1.0)", 2756 | "engines": { 2757 | "node": ">=10" 2758 | }, 2759 | "funding": { 2760 | "url": "https://github.com/sponsors/sindresorhus" 2761 | } 2762 | }, 2763 | "node_modules/undici": { 2764 | "version": "5.11.0", 2765 | "dev": true, 2766 | "license": "MIT", 2767 | "dependencies": { 2768 | "busboy": "^1.6.0" 2769 | }, 2770 | "engines": { 2771 | "node": ">=12.18" 2772 | } 2773 | }, 2774 | "node_modules/update-browserslist-db": { 2775 | "version": "1.0.10", 2776 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", 2777 | "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", 2778 | "dev": true, 2779 | "funding": [ 2780 | { 2781 | "type": "opencollective", 2782 | "url": "https://opencollective.com/browserslist" 2783 | }, 2784 | { 2785 | "type": "tidelift", 2786 | "url": "https://tidelift.com/funding/github/npm/browserslist" 2787 | } 2788 | ], 2789 | "dependencies": { 2790 | "escalade": "^3.1.1", 2791 | "picocolors": "^1.0.0" 2792 | }, 2793 | "bin": { 2794 | "browserslist-lint": "cli.js" 2795 | }, 2796 | "peerDependencies": { 2797 | "browserslist": ">= 4.21.0" 2798 | } 2799 | }, 2800 | "node_modules/uri-js": { 2801 | "version": "4.4.1", 2802 | "dev": true, 2803 | "license": "BSD-2-Clause", 2804 | "dependencies": { 2805 | "punycode": "^2.1.0" 2806 | } 2807 | }, 2808 | "node_modules/util-deprecate": { 2809 | "version": "1.0.2", 2810 | "dev": true, 2811 | "license": "MIT" 2812 | }, 2813 | "node_modules/vite": { 2814 | "version": "3.1.8", 2815 | "dev": true, 2816 | "license": "MIT", 2817 | "dependencies": { 2818 | "esbuild": "^0.15.9", 2819 | "postcss": "^8.4.16", 2820 | "resolve": "^1.22.1", 2821 | "rollup": "~2.78.0" 2822 | }, 2823 | "bin": { 2824 | "vite": "bin/vite.js" 2825 | }, 2826 | "engines": { 2827 | "node": "^14.18.0 || >=16.0.0" 2828 | }, 2829 | "optionalDependencies": { 2830 | "fsevents": "~2.3.2" 2831 | }, 2832 | "peerDependencies": { 2833 | "less": "*", 2834 | "sass": "*", 2835 | "stylus": "*", 2836 | "terser": "^5.4.0" 2837 | }, 2838 | "peerDependenciesMeta": { 2839 | "less": { 2840 | "optional": true 2841 | }, 2842 | "sass": { 2843 | "optional": true 2844 | }, 2845 | "stylus": { 2846 | "optional": true 2847 | }, 2848 | "terser": { 2849 | "optional": true 2850 | } 2851 | } 2852 | }, 2853 | "node_modules/webidl-conversions": { 2854 | "version": "3.0.1", 2855 | "dev": true, 2856 | "license": "BSD-2-Clause" 2857 | }, 2858 | "node_modules/whatwg-url": { 2859 | "version": "5.0.0", 2860 | "dev": true, 2861 | "license": "MIT", 2862 | "dependencies": { 2863 | "tr46": "~0.0.3", 2864 | "webidl-conversions": "^3.0.0" 2865 | } 2866 | }, 2867 | "node_modules/which": { 2868 | "version": "2.0.2", 2869 | "dev": true, 2870 | "license": "ISC", 2871 | "dependencies": { 2872 | "isexe": "^2.0.0" 2873 | }, 2874 | "bin": { 2875 | "node-which": "bin/node-which" 2876 | }, 2877 | "engines": { 2878 | "node": ">= 8" 2879 | } 2880 | }, 2881 | "node_modules/wide-align": { 2882 | "version": "1.1.5", 2883 | "dev": true, 2884 | "license": "ISC", 2885 | "dependencies": { 2886 | "string-width": "^1.0.2 || 2 || 3 || 4" 2887 | } 2888 | }, 2889 | "node_modules/word-wrap": { 2890 | "version": "1.2.3", 2891 | "dev": true, 2892 | "license": "MIT", 2893 | "engines": { 2894 | "node": ">=0.10.0" 2895 | } 2896 | }, 2897 | "node_modules/worktop": { 2898 | "version": "0.8.0-next.14", 2899 | "dev": true, 2900 | "license": "MIT", 2901 | "dependencies": { 2902 | "mrmime": "^1.0.0", 2903 | "regexparam": "^2.0.0" 2904 | }, 2905 | "engines": { 2906 | "node": ">=12" 2907 | } 2908 | }, 2909 | "node_modules/wrappy": { 2910 | "version": "1.0.2", 2911 | "dev": true, 2912 | "license": "ISC" 2913 | }, 2914 | "node_modules/xtend": { 2915 | "version": "4.0.2", 2916 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 2917 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 2918 | "dev": true, 2919 | "engines": { 2920 | "node": ">=0.4" 2921 | } 2922 | }, 2923 | "node_modules/yallist": { 2924 | "version": "4.0.0", 2925 | "dev": true, 2926 | "license": "ISC" 2927 | }, 2928 | "node_modules/yaml": { 2929 | "version": "1.10.2", 2930 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", 2931 | "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", 2932 | "dev": true, 2933 | "engines": { 2934 | "node": ">= 6" 2935 | } 2936 | }, 2937 | "node_modules/yocto-queue": { 2938 | "version": "0.1.0", 2939 | "dev": true, 2940 | "license": "MIT", 2941 | "engines": { 2942 | "node": ">=10" 2943 | }, 2944 | "funding": { 2945 | "url": "https://github.com/sponsors/sindresorhus" 2946 | } 2947 | } 2948 | }, 2949 | "dependencies": { 2950 | "@cloudflare/workers-types": { 2951 | "version": "3.18.0", 2952 | "dev": true 2953 | }, 2954 | "@eslint/eslintrc": { 2955 | "version": "1.3.3", 2956 | "dev": true, 2957 | "requires": { 2958 | "ajv": "^6.12.4", 2959 | "debug": "^4.3.2", 2960 | "espree": "^9.4.0", 2961 | "globals": "^13.15.0", 2962 | "ignore": "^5.2.0", 2963 | "import-fresh": "^3.2.1", 2964 | "js-yaml": "^4.1.0", 2965 | "minimatch": "^3.1.2", 2966 | "strip-json-comments": "^3.1.1" 2967 | } 2968 | }, 2969 | "@humanwhocodes/config-array": { 2970 | "version": "0.11.6", 2971 | "dev": true, 2972 | "requires": { 2973 | "@humanwhocodes/object-schema": "^1.2.1", 2974 | "debug": "^4.1.1", 2975 | "minimatch": "^3.0.4" 2976 | } 2977 | }, 2978 | "@humanwhocodes/module-importer": { 2979 | "version": "1.0.1", 2980 | "dev": true 2981 | }, 2982 | "@humanwhocodes/object-schema": { 2983 | "version": "1.2.1", 2984 | "dev": true 2985 | }, 2986 | "@iarna/toml": { 2987 | "version": "2.2.5", 2988 | "dev": true 2989 | }, 2990 | "@mapbox/node-pre-gyp": { 2991 | "version": "1.0.10", 2992 | "dev": true, 2993 | "requires": { 2994 | "detect-libc": "^2.0.0", 2995 | "https-proxy-agent": "^5.0.0", 2996 | "make-dir": "^3.1.0", 2997 | "node-fetch": "^2.6.7", 2998 | "nopt": "^5.0.0", 2999 | "npmlog": "^5.0.1", 3000 | "rimraf": "^3.0.2", 3001 | "semver": "^7.3.5", 3002 | "tar": "^6.1.11" 3003 | } 3004 | }, 3005 | "@nodelib/fs.scandir": { 3006 | "version": "2.1.5", 3007 | "dev": true, 3008 | "requires": { 3009 | "@nodelib/fs.stat": "2.0.5", 3010 | "run-parallel": "^1.1.9" 3011 | } 3012 | }, 3013 | "@nodelib/fs.stat": { 3014 | "version": "2.0.5", 3015 | "dev": true 3016 | }, 3017 | "@nodelib/fs.walk": { 3018 | "version": "1.2.8", 3019 | "dev": true, 3020 | "requires": { 3021 | "@nodelib/fs.scandir": "2.1.5", 3022 | "fastq": "^1.6.0" 3023 | } 3024 | }, 3025 | "@polka/url": { 3026 | "version": "1.0.0-next.21", 3027 | "dev": true 3028 | }, 3029 | "@rollup/pluginutils": { 3030 | "version": "4.2.1", 3031 | "dev": true, 3032 | "requires": { 3033 | "estree-walker": "^2.0.1", 3034 | "picomatch": "^2.2.2" 3035 | } 3036 | }, 3037 | "@sveltejs/adapter-auto": { 3038 | "version": "1.0.0-next.84", 3039 | "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-1.0.0-next.84.tgz", 3040 | "integrity": "sha512-95NI5dZ3ZNd4vs1/N5knTcArBlWL9pBw2IANCBAcGzwVMoGPjKyyMKZt1gEX74LVwCN6RSRPZ36+6Z6HEb/ojQ==", 3041 | "dev": true, 3042 | "requires": { 3043 | "@sveltejs/adapter-cloudflare": "1.0.0-next.39", 3044 | "@sveltejs/adapter-netlify": "1.0.0-next.81", 3045 | "@sveltejs/adapter-vercel": "1.0.0-next.80" 3046 | } 3047 | }, 3048 | "@sveltejs/adapter-cloudflare": { 3049 | "version": "1.0.0-next.39", 3050 | "dev": true, 3051 | "requires": { 3052 | "@cloudflare/workers-types": "^3.14.0", 3053 | "esbuild": "^0.15.7", 3054 | "worktop": "0.8.0-next.14" 3055 | } 3056 | }, 3057 | "@sveltejs/adapter-netlify": { 3058 | "version": "1.0.0-next.81", 3059 | "dev": true, 3060 | "requires": { 3061 | "@iarna/toml": "^2.2.5", 3062 | "esbuild": "^0.15.7", 3063 | "set-cookie-parser": "^2.4.8" 3064 | } 3065 | }, 3066 | "@sveltejs/adapter-vercel": { 3067 | "version": "1.0.0-next.80", 3068 | "dev": true, 3069 | "requires": { 3070 | "@vercel/nft": "^0.22.0", 3071 | "esbuild": "^0.15.7" 3072 | } 3073 | }, 3074 | "@sveltejs/kit": { 3075 | "version": "1.0.0-next.522", 3076 | "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.522.tgz", 3077 | "integrity": "sha512-dVVrRPbXlAut4vg8kbCeZOjUZnYB7ZvDKp/yAx8InpDF0P1bvUDlc++DXFeMBdXX8bakTA3NGonWnDjqslCsZw==", 3078 | "dev": true, 3079 | "requires": { 3080 | "@sveltejs/vite-plugin-svelte": "^1.0.5", 3081 | "@types/cookie": "^0.5.1", 3082 | "cookie": "^0.5.0", 3083 | "devalue": "^4.0.0", 3084 | "kleur": "^4.1.4", 3085 | "magic-string": "^0.26.2", 3086 | "mime": "^3.0.0", 3087 | "sade": "^1.8.1", 3088 | "set-cookie-parser": "^2.4.8", 3089 | "sirv": "^2.0.2", 3090 | "tiny-glob": "^0.2.9", 3091 | "undici": "^5.11.0" 3092 | } 3093 | }, 3094 | "@sveltejs/vite-plugin-svelte": { 3095 | "version": "1.0.9", 3096 | "dev": true, 3097 | "requires": { 3098 | "@rollup/pluginutils": "^4.2.1", 3099 | "debug": "^4.3.4", 3100 | "deepmerge": "^4.2.2", 3101 | "kleur": "^4.1.5", 3102 | "magic-string": "^0.26.5", 3103 | "svelte-hmr": "^0.15.0" 3104 | } 3105 | }, 3106 | "@types/cookie": { 3107 | "version": "0.5.1", 3108 | "dev": true 3109 | }, 3110 | "@types/node": { 3111 | "version": "18.11.5", 3112 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.5.tgz", 3113 | "integrity": "sha512-3JRwhbjI+cHLAkUorhf8RnqUbFXajvzX4q6fMn5JwkgtuwfYtRQYI3u4V92vI6NJuTsbBQWWh3RZjFsuevyMGQ==", 3114 | "dev": true 3115 | }, 3116 | "@types/pug": { 3117 | "version": "2.0.6", 3118 | "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz", 3119 | "integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==", 3120 | "dev": true 3121 | }, 3122 | "@types/sass": { 3123 | "version": "1.43.1", 3124 | "resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.43.1.tgz", 3125 | "integrity": "sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==", 3126 | "dev": true, 3127 | "requires": { 3128 | "@types/node": "*" 3129 | } 3130 | }, 3131 | "@vercel/nft": { 3132 | "version": "0.22.1", 3133 | "dev": true, 3134 | "requires": { 3135 | "@mapbox/node-pre-gyp": "^1.0.5", 3136 | "acorn": "^8.6.0", 3137 | "async-sema": "^3.1.1", 3138 | "bindings": "^1.4.0", 3139 | "estree-walker": "2.0.2", 3140 | "glob": "^7.1.3", 3141 | "graceful-fs": "^4.2.9", 3142 | "micromatch": "^4.0.2", 3143 | "node-gyp-build": "^4.2.2", 3144 | "resolve-from": "^5.0.0", 3145 | "rollup-pluginutils": "^2.8.2" 3146 | } 3147 | }, 3148 | "abbrev": { 3149 | "version": "1.1.1", 3150 | "dev": true 3151 | }, 3152 | "acorn": { 3153 | "version": "8.8.0", 3154 | "dev": true 3155 | }, 3156 | "acorn-jsx": { 3157 | "version": "5.3.2", 3158 | "dev": true, 3159 | "requires": {} 3160 | }, 3161 | "acorn-node": { 3162 | "version": "1.8.2", 3163 | "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", 3164 | "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", 3165 | "dev": true, 3166 | "requires": { 3167 | "acorn": "^7.0.0", 3168 | "acorn-walk": "^7.0.0", 3169 | "xtend": "^4.0.2" 3170 | }, 3171 | "dependencies": { 3172 | "acorn": { 3173 | "version": "7.4.1", 3174 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", 3175 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", 3176 | "dev": true 3177 | } 3178 | } 3179 | }, 3180 | "acorn-walk": { 3181 | "version": "7.2.0", 3182 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", 3183 | "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", 3184 | "dev": true 3185 | }, 3186 | "agent-base": { 3187 | "version": "6.0.2", 3188 | "dev": true, 3189 | "requires": { 3190 | "debug": "4" 3191 | } 3192 | }, 3193 | "ajv": { 3194 | "version": "6.12.6", 3195 | "dev": true, 3196 | "requires": { 3197 | "fast-deep-equal": "^3.1.1", 3198 | "fast-json-stable-stringify": "^2.0.0", 3199 | "json-schema-traverse": "^0.4.1", 3200 | "uri-js": "^4.2.2" 3201 | } 3202 | }, 3203 | "ansi-regex": { 3204 | "version": "5.0.1", 3205 | "dev": true 3206 | }, 3207 | "ansi-styles": { 3208 | "version": "4.3.0", 3209 | "dev": true, 3210 | "requires": { 3211 | "color-convert": "^2.0.1" 3212 | } 3213 | }, 3214 | "anymatch": { 3215 | "version": "3.1.2", 3216 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 3217 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 3218 | "dev": true, 3219 | "requires": { 3220 | "normalize-path": "^3.0.0", 3221 | "picomatch": "^2.0.4" 3222 | } 3223 | }, 3224 | "aproba": { 3225 | "version": "2.0.0", 3226 | "dev": true 3227 | }, 3228 | "are-we-there-yet": { 3229 | "version": "2.0.0", 3230 | "dev": true, 3231 | "requires": { 3232 | "delegates": "^1.0.0", 3233 | "readable-stream": "^3.6.0" 3234 | } 3235 | }, 3236 | "arg": { 3237 | "version": "5.0.2", 3238 | "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", 3239 | "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", 3240 | "dev": true 3241 | }, 3242 | "argparse": { 3243 | "version": "2.0.1", 3244 | "dev": true 3245 | }, 3246 | "async-sema": { 3247 | "version": "3.1.1", 3248 | "dev": true 3249 | }, 3250 | "autoprefixer": { 3251 | "version": "10.4.12", 3252 | "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.12.tgz", 3253 | "integrity": "sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==", 3254 | "dev": true, 3255 | "requires": { 3256 | "browserslist": "^4.21.4", 3257 | "caniuse-lite": "^1.0.30001407", 3258 | "fraction.js": "^4.2.0", 3259 | "normalize-range": "^0.1.2", 3260 | "picocolors": "^1.0.0", 3261 | "postcss-value-parser": "^4.2.0" 3262 | } 3263 | }, 3264 | "balanced-match": { 3265 | "version": "1.0.2", 3266 | "dev": true 3267 | }, 3268 | "binary-extensions": { 3269 | "version": "2.2.0", 3270 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 3271 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 3272 | "dev": true 3273 | }, 3274 | "bindings": { 3275 | "version": "1.5.0", 3276 | "dev": true, 3277 | "requires": { 3278 | "file-uri-to-path": "1.0.0" 3279 | } 3280 | }, 3281 | "brace-expansion": { 3282 | "version": "1.1.11", 3283 | "dev": true, 3284 | "requires": { 3285 | "balanced-match": "^1.0.0", 3286 | "concat-map": "0.0.1" 3287 | } 3288 | }, 3289 | "braces": { 3290 | "version": "3.0.2", 3291 | "dev": true, 3292 | "requires": { 3293 | "fill-range": "^7.0.1" 3294 | } 3295 | }, 3296 | "browserslist": { 3297 | "version": "4.21.4", 3298 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", 3299 | "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", 3300 | "dev": true, 3301 | "requires": { 3302 | "caniuse-lite": "^1.0.30001400", 3303 | "electron-to-chromium": "^1.4.251", 3304 | "node-releases": "^2.0.6", 3305 | "update-browserslist-db": "^1.0.9" 3306 | } 3307 | }, 3308 | "buffer-crc32": { 3309 | "version": "0.2.13", 3310 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 3311 | "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", 3312 | "dev": true 3313 | }, 3314 | "busboy": { 3315 | "version": "1.6.0", 3316 | "dev": true, 3317 | "requires": { 3318 | "streamsearch": "^1.1.0" 3319 | } 3320 | }, 3321 | "callsites": { 3322 | "version": "3.1.0", 3323 | "dev": true 3324 | }, 3325 | "camelcase-css": { 3326 | "version": "2.0.1", 3327 | "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", 3328 | "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", 3329 | "dev": true 3330 | }, 3331 | "caniuse-lite": { 3332 | "version": "1.0.30001425", 3333 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001425.tgz", 3334 | "integrity": "sha512-/pzFv0OmNG6W0ym80P3NtapU0QEiDS3VuYAZMGoLLqiC7f6FJFe1MjpQDREGApeenD9wloeytmVDj+JLXPC6qw==", 3335 | "dev": true 3336 | }, 3337 | "chalk": { 3338 | "version": "4.1.2", 3339 | "dev": true, 3340 | "requires": { 3341 | "ansi-styles": "^4.1.0", 3342 | "supports-color": "^7.1.0" 3343 | } 3344 | }, 3345 | "chokidar": { 3346 | "version": "3.5.3", 3347 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 3348 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 3349 | "dev": true, 3350 | "requires": { 3351 | "anymatch": "~3.1.2", 3352 | "braces": "~3.0.2", 3353 | "fsevents": "~2.3.2", 3354 | "glob-parent": "~5.1.2", 3355 | "is-binary-path": "~2.1.0", 3356 | "is-glob": "~4.0.1", 3357 | "normalize-path": "~3.0.0", 3358 | "readdirp": "~3.6.0" 3359 | }, 3360 | "dependencies": { 3361 | "glob-parent": { 3362 | "version": "5.1.2", 3363 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 3364 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 3365 | "dev": true, 3366 | "requires": { 3367 | "is-glob": "^4.0.1" 3368 | } 3369 | } 3370 | } 3371 | }, 3372 | "chownr": { 3373 | "version": "2.0.0", 3374 | "dev": true 3375 | }, 3376 | "color-convert": { 3377 | "version": "2.0.1", 3378 | "dev": true, 3379 | "requires": { 3380 | "color-name": "~1.1.4" 3381 | } 3382 | }, 3383 | "color-name": { 3384 | "version": "1.1.4", 3385 | "dev": true 3386 | }, 3387 | "color-support": { 3388 | "version": "1.1.3", 3389 | "dev": true 3390 | }, 3391 | "concat-map": { 3392 | "version": "0.0.1", 3393 | "dev": true 3394 | }, 3395 | "console-control-strings": { 3396 | "version": "1.1.0", 3397 | "dev": true 3398 | }, 3399 | "cookie": { 3400 | "version": "0.5.0", 3401 | "dev": true 3402 | }, 3403 | "cross-spawn": { 3404 | "version": "7.0.3", 3405 | "dev": true, 3406 | "requires": { 3407 | "path-key": "^3.1.0", 3408 | "shebang-command": "^2.0.0", 3409 | "which": "^2.0.1" 3410 | } 3411 | }, 3412 | "cssesc": { 3413 | "version": "3.0.0", 3414 | "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", 3415 | "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", 3416 | "dev": true 3417 | }, 3418 | "debug": { 3419 | "version": "4.3.4", 3420 | "dev": true, 3421 | "requires": { 3422 | "ms": "2.1.2" 3423 | } 3424 | }, 3425 | "deep-is": { 3426 | "version": "0.1.4", 3427 | "dev": true 3428 | }, 3429 | "deepmerge": { 3430 | "version": "4.2.2", 3431 | "dev": true 3432 | }, 3433 | "defined": { 3434 | "version": "1.0.1", 3435 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", 3436 | "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", 3437 | "dev": true 3438 | }, 3439 | "delegates": { 3440 | "version": "1.0.0", 3441 | "dev": true 3442 | }, 3443 | "detect-indent": { 3444 | "version": "6.1.0", 3445 | "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", 3446 | "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", 3447 | "dev": true 3448 | }, 3449 | "detect-libc": { 3450 | "version": "2.0.1", 3451 | "dev": true 3452 | }, 3453 | "detective": { 3454 | "version": "5.2.1", 3455 | "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", 3456 | "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", 3457 | "dev": true, 3458 | "requires": { 3459 | "acorn-node": "^1.8.2", 3460 | "defined": "^1.0.0", 3461 | "minimist": "^1.2.6" 3462 | } 3463 | }, 3464 | "devalue": { 3465 | "version": "4.0.1", 3466 | "dev": true 3467 | }, 3468 | "didyoumean": { 3469 | "version": "1.2.2", 3470 | "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", 3471 | "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", 3472 | "dev": true 3473 | }, 3474 | "dlv": { 3475 | "version": "1.1.3", 3476 | "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", 3477 | "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", 3478 | "dev": true 3479 | }, 3480 | "doctrine": { 3481 | "version": "3.0.0", 3482 | "dev": true, 3483 | "requires": { 3484 | "esutils": "^2.0.2" 3485 | } 3486 | }, 3487 | "electron-to-chromium": { 3488 | "version": "1.4.284", 3489 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", 3490 | "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", 3491 | "dev": true 3492 | }, 3493 | "emoji-regex": { 3494 | "version": "8.0.0", 3495 | "dev": true 3496 | }, 3497 | "es6-promise": { 3498 | "version": "3.3.1", 3499 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", 3500 | "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", 3501 | "dev": true 3502 | }, 3503 | "esbuild": { 3504 | "version": "0.15.12", 3505 | "dev": true, 3506 | "requires": { 3507 | "@esbuild/android-arm": "0.15.12", 3508 | "@esbuild/linux-loong64": "0.15.12", 3509 | "esbuild-android-64": "0.15.12", 3510 | "esbuild-android-arm64": "0.15.12", 3511 | "esbuild-darwin-64": "0.15.12", 3512 | "esbuild-darwin-arm64": "0.15.12", 3513 | "esbuild-freebsd-64": "0.15.12", 3514 | "esbuild-freebsd-arm64": "0.15.12", 3515 | "esbuild-linux-32": "0.15.12", 3516 | "esbuild-linux-64": "0.15.12", 3517 | "esbuild-linux-arm": "0.15.12", 3518 | "esbuild-linux-arm64": "0.15.12", 3519 | "esbuild-linux-mips64le": "0.15.12", 3520 | "esbuild-linux-ppc64le": "0.15.12", 3521 | "esbuild-linux-riscv64": "0.15.12", 3522 | "esbuild-linux-s390x": "0.15.12", 3523 | "esbuild-netbsd-64": "0.15.12", 3524 | "esbuild-openbsd-64": "0.15.12", 3525 | "esbuild-sunos-64": "0.15.12", 3526 | "esbuild-windows-32": "0.15.12", 3527 | "esbuild-windows-64": "0.15.12", 3528 | "esbuild-windows-arm64": "0.15.12" 3529 | } 3530 | }, 3531 | "esbuild-darwin-arm64": { 3532 | "version": "0.15.12", 3533 | "dev": true, 3534 | "optional": true 3535 | }, 3536 | "escalade": { 3537 | "version": "3.1.1", 3538 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 3539 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 3540 | "dev": true 3541 | }, 3542 | "escape-string-regexp": { 3543 | "version": "4.0.0", 3544 | "dev": true 3545 | }, 3546 | "eslint": { 3547 | "version": "8.26.0", 3548 | "dev": true, 3549 | "requires": { 3550 | "@eslint/eslintrc": "^1.3.3", 3551 | "@humanwhocodes/config-array": "^0.11.6", 3552 | "@humanwhocodes/module-importer": "^1.0.1", 3553 | "@nodelib/fs.walk": "^1.2.8", 3554 | "ajv": "^6.10.0", 3555 | "chalk": "^4.0.0", 3556 | "cross-spawn": "^7.0.2", 3557 | "debug": "^4.3.2", 3558 | "doctrine": "^3.0.0", 3559 | "escape-string-regexp": "^4.0.0", 3560 | "eslint-scope": "^7.1.1", 3561 | "eslint-utils": "^3.0.0", 3562 | "eslint-visitor-keys": "^3.3.0", 3563 | "espree": "^9.4.0", 3564 | "esquery": "^1.4.0", 3565 | "esutils": "^2.0.2", 3566 | "fast-deep-equal": "^3.1.3", 3567 | "file-entry-cache": "^6.0.1", 3568 | "find-up": "^5.0.0", 3569 | "glob-parent": "^6.0.2", 3570 | "globals": "^13.15.0", 3571 | "grapheme-splitter": "^1.0.4", 3572 | "ignore": "^5.2.0", 3573 | "import-fresh": "^3.0.0", 3574 | "imurmurhash": "^0.1.4", 3575 | "is-glob": "^4.0.0", 3576 | "is-path-inside": "^3.0.3", 3577 | "js-sdsl": "^4.1.4", 3578 | "js-yaml": "^4.1.0", 3579 | "json-stable-stringify-without-jsonify": "^1.0.1", 3580 | "levn": "^0.4.1", 3581 | "lodash.merge": "^4.6.2", 3582 | "minimatch": "^3.1.2", 3583 | "natural-compare": "^1.4.0", 3584 | "optionator": "^0.9.1", 3585 | "regexpp": "^3.2.0", 3586 | "strip-ansi": "^6.0.1", 3587 | "strip-json-comments": "^3.1.0", 3588 | "text-table": "^0.2.0" 3589 | } 3590 | }, 3591 | "eslint-config-prettier": { 3592 | "version": "8.5.0", 3593 | "dev": true, 3594 | "requires": {} 3595 | }, 3596 | "eslint-plugin-svelte3": { 3597 | "version": "4.0.0", 3598 | "dev": true, 3599 | "requires": {} 3600 | }, 3601 | "eslint-scope": { 3602 | "version": "7.1.1", 3603 | "dev": true, 3604 | "requires": { 3605 | "esrecurse": "^4.3.0", 3606 | "estraverse": "^5.2.0" 3607 | } 3608 | }, 3609 | "eslint-utils": { 3610 | "version": "3.0.0", 3611 | "dev": true, 3612 | "requires": { 3613 | "eslint-visitor-keys": "^2.0.0" 3614 | }, 3615 | "dependencies": { 3616 | "eslint-visitor-keys": { 3617 | "version": "2.1.0", 3618 | "dev": true 3619 | } 3620 | } 3621 | }, 3622 | "eslint-visitor-keys": { 3623 | "version": "3.3.0", 3624 | "dev": true 3625 | }, 3626 | "espree": { 3627 | "version": "9.4.0", 3628 | "dev": true, 3629 | "requires": { 3630 | "acorn": "^8.8.0", 3631 | "acorn-jsx": "^5.3.2", 3632 | "eslint-visitor-keys": "^3.3.0" 3633 | } 3634 | }, 3635 | "esquery": { 3636 | "version": "1.4.0", 3637 | "dev": true, 3638 | "requires": { 3639 | "estraverse": "^5.1.0" 3640 | } 3641 | }, 3642 | "esrecurse": { 3643 | "version": "4.3.0", 3644 | "dev": true, 3645 | "requires": { 3646 | "estraverse": "^5.2.0" 3647 | } 3648 | }, 3649 | "estraverse": { 3650 | "version": "5.3.0", 3651 | "dev": true 3652 | }, 3653 | "estree-walker": { 3654 | "version": "2.0.2", 3655 | "dev": true 3656 | }, 3657 | "esutils": { 3658 | "version": "2.0.3", 3659 | "dev": true 3660 | }, 3661 | "fast-deep-equal": { 3662 | "version": "3.1.3", 3663 | "dev": true 3664 | }, 3665 | "fast-glob": { 3666 | "version": "3.2.12", 3667 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", 3668 | "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", 3669 | "dev": true, 3670 | "requires": { 3671 | "@nodelib/fs.stat": "^2.0.2", 3672 | "@nodelib/fs.walk": "^1.2.3", 3673 | "glob-parent": "^5.1.2", 3674 | "merge2": "^1.3.0", 3675 | "micromatch": "^4.0.4" 3676 | }, 3677 | "dependencies": { 3678 | "glob-parent": { 3679 | "version": "5.1.2", 3680 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 3681 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 3682 | "dev": true, 3683 | "requires": { 3684 | "is-glob": "^4.0.1" 3685 | } 3686 | } 3687 | } 3688 | }, 3689 | "fast-json-stable-stringify": { 3690 | "version": "2.1.0", 3691 | "dev": true 3692 | }, 3693 | "fast-levenshtein": { 3694 | "version": "2.0.6", 3695 | "dev": true 3696 | }, 3697 | "fastq": { 3698 | "version": "1.13.0", 3699 | "dev": true, 3700 | "requires": { 3701 | "reusify": "^1.0.4" 3702 | } 3703 | }, 3704 | "file-entry-cache": { 3705 | "version": "6.0.1", 3706 | "dev": true, 3707 | "requires": { 3708 | "flat-cache": "^3.0.4" 3709 | } 3710 | }, 3711 | "file-uri-to-path": { 3712 | "version": "1.0.0", 3713 | "dev": true 3714 | }, 3715 | "fill-range": { 3716 | "version": "7.0.1", 3717 | "dev": true, 3718 | "requires": { 3719 | "to-regex-range": "^5.0.1" 3720 | } 3721 | }, 3722 | "find-up": { 3723 | "version": "5.0.0", 3724 | "dev": true, 3725 | "requires": { 3726 | "locate-path": "^6.0.0", 3727 | "path-exists": "^4.0.0" 3728 | } 3729 | }, 3730 | "flat-cache": { 3731 | "version": "3.0.4", 3732 | "dev": true, 3733 | "requires": { 3734 | "flatted": "^3.1.0", 3735 | "rimraf": "^3.0.2" 3736 | } 3737 | }, 3738 | "flatted": { 3739 | "version": "3.2.7", 3740 | "dev": true 3741 | }, 3742 | "fraction.js": { 3743 | "version": "4.2.0", 3744 | "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", 3745 | "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", 3746 | "dev": true 3747 | }, 3748 | "fs-minipass": { 3749 | "version": "2.1.0", 3750 | "dev": true, 3751 | "requires": { 3752 | "minipass": "^3.0.0" 3753 | } 3754 | }, 3755 | "fs.realpath": { 3756 | "version": "1.0.0", 3757 | "dev": true 3758 | }, 3759 | "fsevents": { 3760 | "version": "2.3.2", 3761 | "dev": true, 3762 | "optional": true 3763 | }, 3764 | "function-bind": { 3765 | "version": "1.1.1", 3766 | "dev": true 3767 | }, 3768 | "gauge": { 3769 | "version": "3.0.2", 3770 | "dev": true, 3771 | "requires": { 3772 | "aproba": "^1.0.3 || ^2.0.0", 3773 | "color-support": "^1.1.2", 3774 | "console-control-strings": "^1.0.0", 3775 | "has-unicode": "^2.0.1", 3776 | "object-assign": "^4.1.1", 3777 | "signal-exit": "^3.0.0", 3778 | "string-width": "^4.2.3", 3779 | "strip-ansi": "^6.0.1", 3780 | "wide-align": "^1.1.2" 3781 | } 3782 | }, 3783 | "glob": { 3784 | "version": "7.2.3", 3785 | "dev": true, 3786 | "requires": { 3787 | "fs.realpath": "^1.0.0", 3788 | "inflight": "^1.0.4", 3789 | "inherits": "2", 3790 | "minimatch": "^3.1.1", 3791 | "once": "^1.3.0", 3792 | "path-is-absolute": "^1.0.0" 3793 | } 3794 | }, 3795 | "glob-parent": { 3796 | "version": "6.0.2", 3797 | "dev": true, 3798 | "requires": { 3799 | "is-glob": "^4.0.3" 3800 | } 3801 | }, 3802 | "globals": { 3803 | "version": "13.17.0", 3804 | "dev": true, 3805 | "requires": { 3806 | "type-fest": "^0.20.2" 3807 | } 3808 | }, 3809 | "globalyzer": { 3810 | "version": "0.1.0", 3811 | "dev": true 3812 | }, 3813 | "globrex": { 3814 | "version": "0.1.2", 3815 | "dev": true 3816 | }, 3817 | "graceful-fs": { 3818 | "version": "4.2.10", 3819 | "dev": true 3820 | }, 3821 | "grapheme-splitter": { 3822 | "version": "1.0.4", 3823 | "dev": true 3824 | }, 3825 | "has": { 3826 | "version": "1.0.3", 3827 | "dev": true, 3828 | "requires": { 3829 | "function-bind": "^1.1.1" 3830 | } 3831 | }, 3832 | "has-flag": { 3833 | "version": "4.0.0", 3834 | "dev": true 3835 | }, 3836 | "has-unicode": { 3837 | "version": "2.0.1", 3838 | "dev": true 3839 | }, 3840 | "https-proxy-agent": { 3841 | "version": "5.0.1", 3842 | "dev": true, 3843 | "requires": { 3844 | "agent-base": "6", 3845 | "debug": "4" 3846 | } 3847 | }, 3848 | "ignore": { 3849 | "version": "5.2.0", 3850 | "dev": true 3851 | }, 3852 | "import-fresh": { 3853 | "version": "3.3.0", 3854 | "dev": true, 3855 | "requires": { 3856 | "parent-module": "^1.0.0", 3857 | "resolve-from": "^4.0.0" 3858 | }, 3859 | "dependencies": { 3860 | "resolve-from": { 3861 | "version": "4.0.0", 3862 | "dev": true 3863 | } 3864 | } 3865 | }, 3866 | "imurmurhash": { 3867 | "version": "0.1.4", 3868 | "dev": true 3869 | }, 3870 | "inflight": { 3871 | "version": "1.0.6", 3872 | "dev": true, 3873 | "requires": { 3874 | "once": "^1.3.0", 3875 | "wrappy": "1" 3876 | } 3877 | }, 3878 | "inherits": { 3879 | "version": "2.0.4", 3880 | "dev": true 3881 | }, 3882 | "is-binary-path": { 3883 | "version": "2.1.0", 3884 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 3885 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 3886 | "dev": true, 3887 | "requires": { 3888 | "binary-extensions": "^2.0.0" 3889 | } 3890 | }, 3891 | "is-core-module": { 3892 | "version": "2.11.0", 3893 | "dev": true, 3894 | "requires": { 3895 | "has": "^1.0.3" 3896 | } 3897 | }, 3898 | "is-extglob": { 3899 | "version": "2.1.1", 3900 | "dev": true 3901 | }, 3902 | "is-fullwidth-code-point": { 3903 | "version": "3.0.0", 3904 | "dev": true 3905 | }, 3906 | "is-glob": { 3907 | "version": "4.0.3", 3908 | "dev": true, 3909 | "requires": { 3910 | "is-extglob": "^2.1.1" 3911 | } 3912 | }, 3913 | "is-number": { 3914 | "version": "7.0.0", 3915 | "dev": true 3916 | }, 3917 | "is-path-inside": { 3918 | "version": "3.0.3", 3919 | "dev": true 3920 | }, 3921 | "isexe": { 3922 | "version": "2.0.0", 3923 | "dev": true 3924 | }, 3925 | "js-sdsl": { 3926 | "version": "4.1.5", 3927 | "dev": true 3928 | }, 3929 | "js-yaml": { 3930 | "version": "4.1.0", 3931 | "dev": true, 3932 | "requires": { 3933 | "argparse": "^2.0.1" 3934 | } 3935 | }, 3936 | "json-schema-traverse": { 3937 | "version": "0.4.1", 3938 | "dev": true 3939 | }, 3940 | "json-stable-stringify-without-jsonify": { 3941 | "version": "1.0.1", 3942 | "dev": true 3943 | }, 3944 | "kleur": { 3945 | "version": "4.1.5", 3946 | "dev": true 3947 | }, 3948 | "levn": { 3949 | "version": "0.4.1", 3950 | "dev": true, 3951 | "requires": { 3952 | "prelude-ls": "^1.2.1", 3953 | "type-check": "~0.4.0" 3954 | } 3955 | }, 3956 | "lilconfig": { 3957 | "version": "2.0.6", 3958 | "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", 3959 | "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", 3960 | "dev": true 3961 | }, 3962 | "locate-path": { 3963 | "version": "6.0.0", 3964 | "dev": true, 3965 | "requires": { 3966 | "p-locate": "^5.0.0" 3967 | } 3968 | }, 3969 | "lodash.merge": { 3970 | "version": "4.6.2", 3971 | "dev": true 3972 | }, 3973 | "lru-cache": { 3974 | "version": "6.0.0", 3975 | "dev": true, 3976 | "requires": { 3977 | "yallist": "^4.0.0" 3978 | } 3979 | }, 3980 | "magic-string": { 3981 | "version": "0.26.7", 3982 | "dev": true, 3983 | "requires": { 3984 | "sourcemap-codec": "^1.4.8" 3985 | } 3986 | }, 3987 | "make-dir": { 3988 | "version": "3.1.0", 3989 | "dev": true, 3990 | "requires": { 3991 | "semver": "^6.0.0" 3992 | }, 3993 | "dependencies": { 3994 | "semver": { 3995 | "version": "6.3.0", 3996 | "dev": true 3997 | } 3998 | } 3999 | }, 4000 | "merge2": { 4001 | "version": "1.4.1", 4002 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 4003 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 4004 | "dev": true 4005 | }, 4006 | "micromatch": { 4007 | "version": "4.0.5", 4008 | "dev": true, 4009 | "requires": { 4010 | "braces": "^3.0.2", 4011 | "picomatch": "^2.3.1" 4012 | } 4013 | }, 4014 | "mime": { 4015 | "version": "3.0.0", 4016 | "dev": true 4017 | }, 4018 | "min-indent": { 4019 | "version": "1.0.1", 4020 | "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", 4021 | "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", 4022 | "dev": true 4023 | }, 4024 | "minimatch": { 4025 | "version": "3.1.2", 4026 | "dev": true, 4027 | "requires": { 4028 | "brace-expansion": "^1.1.7" 4029 | } 4030 | }, 4031 | "minimist": { 4032 | "version": "1.2.7", 4033 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", 4034 | "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", 4035 | "dev": true 4036 | }, 4037 | "minipass": { 4038 | "version": "3.3.4", 4039 | "dev": true, 4040 | "requires": { 4041 | "yallist": "^4.0.0" 4042 | } 4043 | }, 4044 | "minizlib": { 4045 | "version": "2.1.2", 4046 | "dev": true, 4047 | "requires": { 4048 | "minipass": "^3.0.0", 4049 | "yallist": "^4.0.0" 4050 | } 4051 | }, 4052 | "mkdirp": { 4053 | "version": "1.0.4", 4054 | "dev": true 4055 | }, 4056 | "mri": { 4057 | "version": "1.2.0", 4058 | "dev": true 4059 | }, 4060 | "mrmime": { 4061 | "version": "1.0.1", 4062 | "dev": true 4063 | }, 4064 | "ms": { 4065 | "version": "2.1.2", 4066 | "dev": true 4067 | }, 4068 | "nanoid": { 4069 | "version": "3.3.4", 4070 | "dev": true 4071 | }, 4072 | "natural-compare": { 4073 | "version": "1.4.0", 4074 | "dev": true 4075 | }, 4076 | "node-fetch": { 4077 | "version": "2.6.7", 4078 | "dev": true, 4079 | "requires": { 4080 | "whatwg-url": "^5.0.0" 4081 | } 4082 | }, 4083 | "node-gyp-build": { 4084 | "version": "4.5.0", 4085 | "dev": true 4086 | }, 4087 | "node-releases": { 4088 | "version": "2.0.6", 4089 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", 4090 | "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", 4091 | "dev": true 4092 | }, 4093 | "nopt": { 4094 | "version": "5.0.0", 4095 | "dev": true, 4096 | "requires": { 4097 | "abbrev": "1" 4098 | } 4099 | }, 4100 | "normalize-path": { 4101 | "version": "3.0.0", 4102 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 4103 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 4104 | "dev": true 4105 | }, 4106 | "normalize-range": { 4107 | "version": "0.1.2", 4108 | "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", 4109 | "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", 4110 | "dev": true 4111 | }, 4112 | "npmlog": { 4113 | "version": "5.0.1", 4114 | "dev": true, 4115 | "requires": { 4116 | "are-we-there-yet": "^2.0.0", 4117 | "console-control-strings": "^1.1.0", 4118 | "gauge": "^3.0.0", 4119 | "set-blocking": "^2.0.0" 4120 | } 4121 | }, 4122 | "object-assign": { 4123 | "version": "4.1.1", 4124 | "dev": true 4125 | }, 4126 | "object-hash": { 4127 | "version": "3.0.0", 4128 | "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", 4129 | "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", 4130 | "dev": true 4131 | }, 4132 | "once": { 4133 | "version": "1.4.0", 4134 | "dev": true, 4135 | "requires": { 4136 | "wrappy": "1" 4137 | } 4138 | }, 4139 | "optionator": { 4140 | "version": "0.9.1", 4141 | "dev": true, 4142 | "requires": { 4143 | "deep-is": "^0.1.3", 4144 | "fast-levenshtein": "^2.0.6", 4145 | "levn": "^0.4.1", 4146 | "prelude-ls": "^1.2.1", 4147 | "type-check": "^0.4.0", 4148 | "word-wrap": "^1.2.3" 4149 | } 4150 | }, 4151 | "p-limit": { 4152 | "version": "3.1.0", 4153 | "dev": true, 4154 | "requires": { 4155 | "yocto-queue": "^0.1.0" 4156 | } 4157 | }, 4158 | "p-locate": { 4159 | "version": "5.0.0", 4160 | "dev": true, 4161 | "requires": { 4162 | "p-limit": "^3.0.2" 4163 | } 4164 | }, 4165 | "parent-module": { 4166 | "version": "1.0.1", 4167 | "dev": true, 4168 | "requires": { 4169 | "callsites": "^3.0.0" 4170 | } 4171 | }, 4172 | "path-exists": { 4173 | "version": "4.0.0", 4174 | "dev": true 4175 | }, 4176 | "path-is-absolute": { 4177 | "version": "1.0.1", 4178 | "dev": true 4179 | }, 4180 | "path-key": { 4181 | "version": "3.1.1", 4182 | "dev": true 4183 | }, 4184 | "path-parse": { 4185 | "version": "1.0.7", 4186 | "dev": true 4187 | }, 4188 | "picocolors": { 4189 | "version": "1.0.0", 4190 | "dev": true 4191 | }, 4192 | "picomatch": { 4193 | "version": "2.3.1", 4194 | "dev": true 4195 | }, 4196 | "pify": { 4197 | "version": "2.3.0", 4198 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 4199 | "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", 4200 | "dev": true 4201 | }, 4202 | "postcss": { 4203 | "version": "8.4.18", 4204 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", 4205 | "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", 4206 | "dev": true, 4207 | "requires": { 4208 | "nanoid": "^3.3.4", 4209 | "picocolors": "^1.0.0", 4210 | "source-map-js": "^1.0.2" 4211 | } 4212 | }, 4213 | "postcss-import": { 4214 | "version": "14.1.0", 4215 | "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", 4216 | "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", 4217 | "dev": true, 4218 | "requires": { 4219 | "postcss-value-parser": "^4.0.0", 4220 | "read-cache": "^1.0.0", 4221 | "resolve": "^1.1.7" 4222 | } 4223 | }, 4224 | "postcss-js": { 4225 | "version": "4.0.0", 4226 | "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", 4227 | "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", 4228 | "dev": true, 4229 | "requires": { 4230 | "camelcase-css": "^2.0.1" 4231 | } 4232 | }, 4233 | "postcss-load-config": { 4234 | "version": "3.1.4", 4235 | "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", 4236 | "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", 4237 | "dev": true, 4238 | "requires": { 4239 | "lilconfig": "^2.0.5", 4240 | "yaml": "^1.10.2" 4241 | } 4242 | }, 4243 | "postcss-nested": { 4244 | "version": "6.0.0", 4245 | "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", 4246 | "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", 4247 | "dev": true, 4248 | "requires": { 4249 | "postcss-selector-parser": "^6.0.10" 4250 | } 4251 | }, 4252 | "postcss-selector-parser": { 4253 | "version": "6.0.10", 4254 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", 4255 | "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", 4256 | "dev": true, 4257 | "requires": { 4258 | "cssesc": "^3.0.0", 4259 | "util-deprecate": "^1.0.2" 4260 | } 4261 | }, 4262 | "postcss-value-parser": { 4263 | "version": "4.2.0", 4264 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 4265 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 4266 | "dev": true 4267 | }, 4268 | "prelude-ls": { 4269 | "version": "1.2.1", 4270 | "dev": true 4271 | }, 4272 | "prettier": { 4273 | "version": "2.7.1", 4274 | "dev": true 4275 | }, 4276 | "prettier-plugin-svelte": { 4277 | "version": "2.8.0", 4278 | "dev": true, 4279 | "requires": {} 4280 | }, 4281 | "punycode": { 4282 | "version": "2.1.1", 4283 | "dev": true 4284 | }, 4285 | "queue-microtask": { 4286 | "version": "1.2.3", 4287 | "dev": true 4288 | }, 4289 | "quick-lru": { 4290 | "version": "5.1.1", 4291 | "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", 4292 | "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", 4293 | "dev": true 4294 | }, 4295 | "read-cache": { 4296 | "version": "1.0.0", 4297 | "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", 4298 | "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", 4299 | "dev": true, 4300 | "requires": { 4301 | "pify": "^2.3.0" 4302 | } 4303 | }, 4304 | "readable-stream": { 4305 | "version": "3.6.0", 4306 | "dev": true, 4307 | "requires": { 4308 | "inherits": "^2.0.3", 4309 | "string_decoder": "^1.1.1", 4310 | "util-deprecate": "^1.0.1" 4311 | } 4312 | }, 4313 | "readdirp": { 4314 | "version": "3.6.0", 4315 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 4316 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 4317 | "dev": true, 4318 | "requires": { 4319 | "picomatch": "^2.2.1" 4320 | } 4321 | }, 4322 | "regexparam": { 4323 | "version": "2.0.1", 4324 | "dev": true 4325 | }, 4326 | "regexpp": { 4327 | "version": "3.2.0", 4328 | "dev": true 4329 | }, 4330 | "resolve": { 4331 | "version": "1.22.1", 4332 | "dev": true, 4333 | "requires": { 4334 | "is-core-module": "^2.9.0", 4335 | "path-parse": "^1.0.7", 4336 | "supports-preserve-symlinks-flag": "^1.0.0" 4337 | } 4338 | }, 4339 | "resolve-from": { 4340 | "version": "5.0.0", 4341 | "dev": true 4342 | }, 4343 | "reusify": { 4344 | "version": "1.0.4", 4345 | "dev": true 4346 | }, 4347 | "rimraf": { 4348 | "version": "3.0.2", 4349 | "dev": true, 4350 | "requires": { 4351 | "glob": "^7.1.3" 4352 | } 4353 | }, 4354 | "rollup": { 4355 | "version": "2.78.1", 4356 | "dev": true, 4357 | "requires": { 4358 | "fsevents": "~2.3.2" 4359 | } 4360 | }, 4361 | "rollup-pluginutils": { 4362 | "version": "2.8.2", 4363 | "dev": true, 4364 | "requires": { 4365 | "estree-walker": "^0.6.1" 4366 | }, 4367 | "dependencies": { 4368 | "estree-walker": { 4369 | "version": "0.6.1", 4370 | "dev": true 4371 | } 4372 | } 4373 | }, 4374 | "run-parallel": { 4375 | "version": "1.2.0", 4376 | "dev": true, 4377 | "requires": { 4378 | "queue-microtask": "^1.2.2" 4379 | } 4380 | }, 4381 | "sade": { 4382 | "version": "1.8.1", 4383 | "dev": true, 4384 | "requires": { 4385 | "mri": "^1.1.0" 4386 | } 4387 | }, 4388 | "safe-buffer": { 4389 | "version": "5.2.1", 4390 | "dev": true 4391 | }, 4392 | "sander": { 4393 | "version": "0.5.1", 4394 | "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", 4395 | "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", 4396 | "dev": true, 4397 | "requires": { 4398 | "es6-promise": "^3.1.2", 4399 | "graceful-fs": "^4.1.3", 4400 | "mkdirp": "^0.5.1", 4401 | "rimraf": "^2.5.2" 4402 | }, 4403 | "dependencies": { 4404 | "mkdirp": { 4405 | "version": "0.5.6", 4406 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", 4407 | "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", 4408 | "dev": true, 4409 | "requires": { 4410 | "minimist": "^1.2.6" 4411 | } 4412 | }, 4413 | "rimraf": { 4414 | "version": "2.7.1", 4415 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 4416 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 4417 | "dev": true, 4418 | "requires": { 4419 | "glob": "^7.1.3" 4420 | } 4421 | } 4422 | } 4423 | }, 4424 | "semver": { 4425 | "version": "7.3.8", 4426 | "dev": true, 4427 | "requires": { 4428 | "lru-cache": "^6.0.0" 4429 | } 4430 | }, 4431 | "set-blocking": { 4432 | "version": "2.0.0", 4433 | "dev": true 4434 | }, 4435 | "set-cookie-parser": { 4436 | "version": "2.5.1", 4437 | "dev": true 4438 | }, 4439 | "shebang-command": { 4440 | "version": "2.0.0", 4441 | "dev": true, 4442 | "requires": { 4443 | "shebang-regex": "^3.0.0" 4444 | } 4445 | }, 4446 | "shebang-regex": { 4447 | "version": "3.0.0", 4448 | "dev": true 4449 | }, 4450 | "signal-exit": { 4451 | "version": "3.0.7", 4452 | "dev": true 4453 | }, 4454 | "sirv": { 4455 | "version": "2.0.2", 4456 | "dev": true, 4457 | "requires": { 4458 | "@polka/url": "^1.0.0-next.20", 4459 | "mrmime": "^1.0.0", 4460 | "totalist": "^3.0.0" 4461 | } 4462 | }, 4463 | "sorcery": { 4464 | "version": "0.10.0", 4465 | "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.10.0.tgz", 4466 | "integrity": "sha512-R5ocFmKZQFfSTstfOtHjJuAwbpGyf9qjQa1egyhvXSbM7emjrtLXtGdZsDJDABC85YBfVvrOiGWKSYXPKdvP1g==", 4467 | "dev": true, 4468 | "requires": { 4469 | "buffer-crc32": "^0.2.5", 4470 | "minimist": "^1.2.0", 4471 | "sander": "^0.5.0", 4472 | "sourcemap-codec": "^1.3.0" 4473 | } 4474 | }, 4475 | "source-map-js": { 4476 | "version": "1.0.2", 4477 | "dev": true 4478 | }, 4479 | "sourcemap-codec": { 4480 | "version": "1.4.8", 4481 | "dev": true 4482 | }, 4483 | "streamsearch": { 4484 | "version": "1.1.0", 4485 | "dev": true 4486 | }, 4487 | "string_decoder": { 4488 | "version": "1.3.0", 4489 | "dev": true, 4490 | "requires": { 4491 | "safe-buffer": "~5.2.0" 4492 | } 4493 | }, 4494 | "string-width": { 4495 | "version": "4.2.3", 4496 | "dev": true, 4497 | "requires": { 4498 | "emoji-regex": "^8.0.0", 4499 | "is-fullwidth-code-point": "^3.0.0", 4500 | "strip-ansi": "^6.0.1" 4501 | } 4502 | }, 4503 | "strip-ansi": { 4504 | "version": "6.0.1", 4505 | "dev": true, 4506 | "requires": { 4507 | "ansi-regex": "^5.0.1" 4508 | } 4509 | }, 4510 | "strip-indent": { 4511 | "version": "3.0.0", 4512 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", 4513 | "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", 4514 | "dev": true, 4515 | "requires": { 4516 | "min-indent": "^1.0.0" 4517 | } 4518 | }, 4519 | "strip-json-comments": { 4520 | "version": "3.1.1", 4521 | "dev": true 4522 | }, 4523 | "supports-color": { 4524 | "version": "7.2.0", 4525 | "dev": true, 4526 | "requires": { 4527 | "has-flag": "^4.0.0" 4528 | } 4529 | }, 4530 | "supports-preserve-symlinks-flag": { 4531 | "version": "1.0.0", 4532 | "dev": true 4533 | }, 4534 | "svelte": { 4535 | "version": "3.52.0", 4536 | "dev": true 4537 | }, 4538 | "svelte-hmr": { 4539 | "version": "0.15.0", 4540 | "dev": true, 4541 | "requires": {} 4542 | }, 4543 | "svelte-preprocess": { 4544 | "version": "4.10.7", 4545 | "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.7.tgz", 4546 | "integrity": "sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==", 4547 | "dev": true, 4548 | "requires": { 4549 | "@types/pug": "^2.0.4", 4550 | "@types/sass": "^1.16.0", 4551 | "detect-indent": "^6.0.0", 4552 | "magic-string": "^0.25.7", 4553 | "sorcery": "^0.10.0", 4554 | "strip-indent": "^3.0.0" 4555 | }, 4556 | "dependencies": { 4557 | "magic-string": { 4558 | "version": "0.25.9", 4559 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", 4560 | "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", 4561 | "dev": true, 4562 | "requires": { 4563 | "sourcemap-codec": "^1.4.8" 4564 | } 4565 | } 4566 | } 4567 | }, 4568 | "tailwindcss": { 4569 | "version": "3.2.1", 4570 | "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.1.tgz", 4571 | "integrity": "sha512-Uw+GVSxp5CM48krnjHObqoOwlCt5Qo6nw1jlCRwfGy68dSYb/LwS9ZFidYGRiM+w6rMawkZiu1mEMAsHYAfoLg==", 4572 | "dev": true, 4573 | "requires": { 4574 | "arg": "^5.0.2", 4575 | "chokidar": "^3.5.3", 4576 | "color-name": "^1.1.4", 4577 | "detective": "^5.2.1", 4578 | "didyoumean": "^1.2.2", 4579 | "dlv": "^1.1.3", 4580 | "fast-glob": "^3.2.12", 4581 | "glob-parent": "^6.0.2", 4582 | "is-glob": "^4.0.3", 4583 | "lilconfig": "^2.0.6", 4584 | "micromatch": "^4.0.5", 4585 | "normalize-path": "^3.0.0", 4586 | "object-hash": "^3.0.0", 4587 | "picocolors": "^1.0.0", 4588 | "postcss": "^8.4.17", 4589 | "postcss-import": "^14.1.0", 4590 | "postcss-js": "^4.0.0", 4591 | "postcss-load-config": "^3.1.4", 4592 | "postcss-nested": "6.0.0", 4593 | "postcss-selector-parser": "^6.0.10", 4594 | "postcss-value-parser": "^4.2.0", 4595 | "quick-lru": "^5.1.1", 4596 | "resolve": "^1.22.1" 4597 | } 4598 | }, 4599 | "tar": { 4600 | "version": "6.1.11", 4601 | "dev": true, 4602 | "requires": { 4603 | "chownr": "^2.0.0", 4604 | "fs-minipass": "^2.0.0", 4605 | "minipass": "^3.0.0", 4606 | "minizlib": "^2.1.1", 4607 | "mkdirp": "^1.0.3", 4608 | "yallist": "^4.0.0" 4609 | } 4610 | }, 4611 | "text-table": { 4612 | "version": "0.2.0", 4613 | "dev": true 4614 | }, 4615 | "tiny-glob": { 4616 | "version": "0.2.9", 4617 | "dev": true, 4618 | "requires": { 4619 | "globalyzer": "0.1.0", 4620 | "globrex": "^0.1.2" 4621 | } 4622 | }, 4623 | "to-regex-range": { 4624 | "version": "5.0.1", 4625 | "dev": true, 4626 | "requires": { 4627 | "is-number": "^7.0.0" 4628 | } 4629 | }, 4630 | "totalist": { 4631 | "version": "3.0.0", 4632 | "dev": true 4633 | }, 4634 | "tr46": { 4635 | "version": "0.0.3", 4636 | "dev": true 4637 | }, 4638 | "type-check": { 4639 | "version": "0.4.0", 4640 | "dev": true, 4641 | "requires": { 4642 | "prelude-ls": "^1.2.1" 4643 | } 4644 | }, 4645 | "type-fest": { 4646 | "version": "0.20.2", 4647 | "dev": true 4648 | }, 4649 | "undici": { 4650 | "version": "5.11.0", 4651 | "dev": true, 4652 | "requires": { 4653 | "busboy": "^1.6.0" 4654 | } 4655 | }, 4656 | "update-browserslist-db": { 4657 | "version": "1.0.10", 4658 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", 4659 | "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", 4660 | "dev": true, 4661 | "requires": { 4662 | "escalade": "^3.1.1", 4663 | "picocolors": "^1.0.0" 4664 | } 4665 | }, 4666 | "uri-js": { 4667 | "version": "4.4.1", 4668 | "dev": true, 4669 | "requires": { 4670 | "punycode": "^2.1.0" 4671 | } 4672 | }, 4673 | "util-deprecate": { 4674 | "version": "1.0.2", 4675 | "dev": true 4676 | }, 4677 | "vite": { 4678 | "version": "3.1.8", 4679 | "dev": true, 4680 | "requires": { 4681 | "esbuild": "^0.15.9", 4682 | "fsevents": "~2.3.2", 4683 | "postcss": "^8.4.16", 4684 | "resolve": "^1.22.1", 4685 | "rollup": "~2.78.0" 4686 | } 4687 | }, 4688 | "webidl-conversions": { 4689 | "version": "3.0.1", 4690 | "dev": true 4691 | }, 4692 | "whatwg-url": { 4693 | "version": "5.0.0", 4694 | "dev": true, 4695 | "requires": { 4696 | "tr46": "~0.0.3", 4697 | "webidl-conversions": "^3.0.0" 4698 | } 4699 | }, 4700 | "which": { 4701 | "version": "2.0.2", 4702 | "dev": true, 4703 | "requires": { 4704 | "isexe": "^2.0.0" 4705 | } 4706 | }, 4707 | "wide-align": { 4708 | "version": "1.1.5", 4709 | "dev": true, 4710 | "requires": { 4711 | "string-width": "^1.0.2 || 2 || 3 || 4" 4712 | } 4713 | }, 4714 | "word-wrap": { 4715 | "version": "1.2.3", 4716 | "dev": true 4717 | }, 4718 | "worktop": { 4719 | "version": "0.8.0-next.14", 4720 | "dev": true, 4721 | "requires": { 4722 | "mrmime": "^1.0.0", 4723 | "regexparam": "^2.0.0" 4724 | } 4725 | }, 4726 | "wrappy": { 4727 | "version": "1.0.2", 4728 | "dev": true 4729 | }, 4730 | "xtend": { 4731 | "version": "4.0.2", 4732 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 4733 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 4734 | "dev": true 4735 | }, 4736 | "yallist": { 4737 | "version": "4.0.0", 4738 | "dev": true 4739 | }, 4740 | "yaml": { 4741 | "version": "1.10.2", 4742 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", 4743 | "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", 4744 | "dev": true 4745 | }, 4746 | "yocto-queue": { 4747 | "version": "0.1.0", 4748 | "dev": true 4749 | } 4750 | } 4751 | } 4752 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend2", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "lint": "prettier --plugin-search-dir . --check . && eslint .", 10 | "format": "prettier --plugin-search-dir . --write ." 11 | }, 12 | "devDependencies": { 13 | "@sveltejs/adapter-auto": "next", 14 | "@sveltejs/kit": "next", 15 | "autoprefixer": "^10.4.12", 16 | "eslint": "^8.16.0", 17 | "eslint-config-prettier": "^8.3.0", 18 | "eslint-plugin-svelte3": "^4.0.0", 19 | "postcss": "^8.4.18", 20 | "prettier": "^2.6.2", 21 | "prettier-plugin-svelte": "^2.7.0", 22 | "svelte": "^3.44.0", 23 | "svelte-preprocess": "^4.10.7", 24 | "tailwindcss": "^3.2.1", 25 | "vite": "^3.1.0" 26 | }, 27 | "type": "module" 28 | } 29 | -------------------------------------------------------------------------------- /frontend/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /frontend/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /frontend/src/lib/components/Nav.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/src/lib/config.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartgoo/sveltekit-fastapi-mongodb/1e7be3a207bec3012237f574158b6e1e51371211/frontend/src/lib/config.js -------------------------------------------------------------------------------- /frontend/src/lib/stores.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartgoo/sveltekit-fastapi-mongodb/1e7be3a207bec3012237f574158b6e1e51371211/frontend/src/lib/stores.js -------------------------------------------------------------------------------- /frontend/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /frontend/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 |
23 |

24 | Blog Posts 25 |

26 | 27 | {#await loadPosts()} 28 | ... 29 | {:then posts} 30 | {#each posts as post} 31 |

{post.title}

32 |

Publish date: {post.date}

33 |

{post.text}

34 | {/each} 35 | {/await} 36 |
-------------------------------------------------------------------------------- /frontend/src/routes/articles/+page.svelte: -------------------------------------------------------------------------------- 1 |

Articles

-------------------------------------------------------------------------------- /frontend/src/routes/contact/+page.svelte: -------------------------------------------------------------------------------- 1 |

Contact

-------------------------------------------------------------------------------- /frontend/src/routes/tutorials/+page.svelte: -------------------------------------------------------------------------------- 1 |

Tutorials

-------------------------------------------------------------------------------- /frontend/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartgoo/sveltekit-fastapi-mongodb/1e7be3a207bec3012237f574158b6e1e51371211/frontend/static/favicon.png -------------------------------------------------------------------------------- /frontend/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import preprocess from "svelte-preprocess"; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | preprocess: [ 7 | preprocess({ 8 | postcss: true, 9 | }), 10 | ], 11 | kit: { 12 | adapter: adapter() 13 | } 14 | }; 15 | 16 | export default config; -------------------------------------------------------------------------------- /frontend/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ['./src/**/*.{html,js,svelte,ts}'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | } 9 | -------------------------------------------------------------------------------- /frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | 3 | const config = { 4 | plugins: [sveltekit()] 5 | }; 6 | 7 | export default config; 8 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Summary: Dockerized SvelteKit - FastAPI - MongoDB Example Project 2 | This project is an example of how SvelteKit, FastAPI, and MongoDB can be dockerized and ran via docker compose. Note that, as of right now, this is not perfect. This project is meant to serve as an example/reference. However, it can be manually converted into a starting template. 3 | 4 | ## Getting started 5 | 1. Clone project: `git clone https://github.com/smartgoo/sveltekit-fastapi-mongodb.git` 6 | 2. `cd sveltekit-fastapi-mongodb` 7 | 3. Install SvelteKit packages: `npm install frontend/` 8 | 4. Build the containers: `docker-compose build` 9 | 5. Bring up the containers: `docker-compose up` 10 | 6. Open the web app: `http://localhost:5173/` 11 | 7. Open the FastAPI OpenAPI docs: `http://localhost:8000/docs` 12 | 13 | ## Updated To Latest Versions 14 | This project was updated on October 23 2022, and uses the latest versions available at the time. 15 | - Node v16 16 | - SvelteKit 1.0.0-next.522 17 | - Python 3.10.8 18 | - FastAPI 0.85.1 19 | 20 | ## Converting to a starter template 21 | Please note this process is incomplete, but the process of converting a starter template would look roughly like this: 22 | 1. Remove FastAPI endpoints from `backend/app/api/endpoints` and update `backend/app/api/api.py` accordingly. 23 | 2. Remove SvelteKit routes from `frontend/src/routes`. 24 | 3. Remove SvelteKit components from `frontend/src/lib`. 25 | 26 | ## Components 27 | - Frontend: [Svelte](https://svelte.dev/) with [SvelteKit](https://kit.svelte.dev/) 28 | - Backend: [FastAPI](https://fastapi.tiangolo.com/) 29 | - Database: [MongoDB](https://www.mongodb.com/) 30 | 31 | ## Roadmap 32 | I hope to add more features to this project, and convert it to a full starter template at some point. Features on the roadmap are: 33 | 1. Authentication and code to illustrate how it could work 34 | 2. Nginx with HTTPS 35 | 3. Scaffold SvelteKit (`frontend`) codebase a little bit more 36 | 4. Scaffold testing for SvelteKit and FastAPI 37 | 5. FastAPI background task examples 38 | 39 | ## A big thanks to these projects 40 | A few existing existing project templates were referenced while building this. A big thanks to these: 41 | - [FastAPI MongoDB Real World Example](https://github.com/markqiu/fastapi-mongodb-realworld-example-app) 42 | - [FastAPI Project Template](https://fastapi.tiangolo.com/project-generation/) 43 | - [Jeff Astor's FastAPI Blog Posts](https://www.jeffastor.com/blog/designing-a-robust-user-model-in-a-fastapi-app) heavily influenced authentication 44 | --------------------------------------------------------------------------------