diff --git a/.env b/.env
index 98c8196862..5110b5b506 100644
--- a/.env
+++ b/.env
@@ -5,33 +5,35 @@ DOMAIN=localhost
# Environment: local, staging, production
ENVIRONMENT=local
-PROJECT_NAME="Full Stack FastAPI Project"
+PROJECT_NAME="SOCIA"
STACK_NAME=full-stack-fastapi-project
# Backend
BACKEND_CORS_ORIGINS="http://localhost,http://localhost:5173,https://localhost,https://localhost:5173,http://localhost.tiangolo.com"
-SECRET_KEY=changethis
-FIRST_SUPERUSER=admin@example.com
-FIRST_SUPERUSER_PASSWORD=changethis
+SECRET_KEY=PDma3zqc5pq9LZVfVj7qL5bB6mC4OCIN0sKdjSiKOlI
+FIRST_SUPERUSER=arpit.singh@example.com
+FIRST_SUPERUSER_PASSWORD=SOciaSOcia
+# Otpless
+CLIENT_ID = "CLIENT_ID"
+CLIENT_SECRET = "CLIENT_SECRET"
# Emails
-SMTP_HOST=
-SMTP_USER=
-SMTP_PASSWORD=
-EMAILS_FROM_EMAIL=info@example.com
+SMTP_HOST=arpit.singh@example.com
+SMTP_USER=arpit.singh@example.com
+SMTP_PASSWORD=SOciaSOcia
+EMAILS_FROM_EMAIL=arpit.singh@example.com
SMTP_TLS=True
SMTP_SSL=False
SMTP_PORT=587
# Postgres
-POSTGRES_SERVER=localhost
-POSTGRES_PORT=5432
-POSTGRES_DB=app
-POSTGRES_USER=postgres
-POSTGRES_PASSWORD=changethis
+POSTGRES_SERVER=aws-0-ap-south-1.pooler.supabase.com
+POSTGRES_PORT=6543
+POSTGRES_USER=postgres.uiwsgdtnmovxahfgxfkj
+POSTGRES_PASSWORD=Aa1sociaaicos
+POSTGRES_DB=sociadb
SENTRY_DSN=
# Configure these with your own Docker registry images
-DOCKER_IMAGE_BACKEND=backend
-DOCKER_IMAGE_FRONTEND=frontend
+DOCKER_IMAGE_BACKEND=backend
\ No newline at end of file
diff --git a/.github/workflows/generate-client.yml b/.github/workflows/generate-client.yml
index a81f78cb51..e69de29bb2 100644
--- a/.github/workflows/generate-client.yml
+++ b/.github/workflows/generate-client.yml
@@ -1,49 +0,0 @@
-name: Generate Client
-
-on:
- pull_request:
- types:
- - opened
- - synchronize
-
-jobs:
- generate-client:
- permissions:
- contents: write
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- with:
- ref: ${{ github.head_ref }}
- token: ${{ secrets.FULL_STACK_FASTAPI_TEMPLATE_REPO_TOKEN }}
- - uses: actions/setup-node@v4
- with:
- node-version: lts/*
- - uses: actions/setup-python@v5
- with:
- python-version: '3.10'
- - name: Install dependencies
- run: npm ci
- working-directory: frontend
- - run: pip install ./backend
- - run: bash scripts/generate-client.sh
- - name: Commit changes
- run: |
- git config --local user.email "github-actions@github.com"
- git config --local user.name "github-actions"
- git add frontend/src/client
- git diff --staged --quiet || git commit -m "✨ Autogenerate frontend client"
- git push
-
- # https://github.com/marketplace/actions/alls-green#why
- generate-client-alls-green: # This job does nothing and is only used for the branch protection
- if: always()
- needs:
- - generate-client
- runs-on: ubuntu-latest
- steps:
- - name: Decide whether the needed jobs succeeded or failed
- uses: re-actors/alls-green@release/v1
- with:
- jobs: ${{ toJSON(needs) }}
-
\ No newline at end of file
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
deleted file mode 100644
index fc208993f6..0000000000
--- a/.github/workflows/playwright.yml
+++ /dev/null
@@ -1,67 +0,0 @@
-name: Playwright Tests
-
-on:
- push:
- branches:
- - master
- pull_request:
- types:
- - opened
- - synchronize
- workflow_dispatch:
- inputs:
- debug_enabled:
- description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
- required: false
- default: 'false'
-
-jobs:
-
- test:
- timeout-minutes: 60
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-node@v4
- with:
- node-version: lts/*
- - uses: actions/setup-python@v5
- with:
- python-version: '3.10'
- - name: Setup tmate session
- uses: mxschmitt/action-tmate@v3
- if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
- with:
- limit-access-to-actor: true
- - name: Install dependencies
- run: npm ci
- working-directory: frontend
- - name: Install Playwright Browsers
- run: npx playwright install --with-deps
- working-directory: frontend
- - run: docker compose build
- - run: docker compose down -v --remove-orphans
- - run: docker compose up -d
- - name: Run Playwright tests
- run: npx playwright test
- working-directory: frontend
- - run: docker compose down -v --remove-orphans
- - uses: actions/upload-artifact@v4
- if: always()
- with:
- name: playwright-report
- path: frontend/playwright-report/
- retention-days: 30
- include-hidden-files: true
-
- # https://github.com/marketplace/actions/alls-green#why
- e2e-alls-green: # This job does nothing and is only used for the branch protection
- if: always()
- needs:
- - test
- runs-on: ubuntu-latest
- steps:
- - name: Decide whether the needed jobs succeeded or failed
- uses: re-actors/alls-green@release/v1
- with:
- jobs: ${{ toJSON(needs) }}
diff --git a/.gitignore b/.gitignore
index a6dd346572..530b37eca8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,6 @@ node_modules/
/playwright-report/
/blob-report/
/playwright/.cache/
+.history/
+.DS_Store
+
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 24eae850d0..c1888bf5cd 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -16,13 +16,6 @@
"cwd": "${workspaceFolder}/backend",
"jinja": true,
"envFile": "${workspaceFolder}/.env",
- },
- {
- "type": "chrome",
- "request": "launch",
- "name": "Debug Frontend: Launch Chrome against http://localhost:5173",
- "url": "http://localhost:5173",
- "webRoot": "${workspaceFolder}/frontend"
- },
+ }
]
}
diff --git a/README.md b/README.md
index afe124f3fb..80188b0e26 100644
--- a/README.md
+++ b/README.md
@@ -216,10 +216,6 @@ The input variables, with their default values (some auto generated) are:
Backend docs: [backend/README.md](./backend/README.md).
-## Frontend Development
-
-Frontend docs: [frontend/README.md](./frontend/README.md).
-
## Deployment
Deployment docs: [deployment.md](./deployment.md).
diff --git a/backend/.gitignore b/backend/.gitignore
index 63f67bcd21..101092a3ec 100644
--- a/backend/.gitignore
+++ b/backend/.gitignore
@@ -5,4 +5,4 @@ app.egg-info
.coverage
htmlcov
.cache
-.venv
+.venv
\ No newline at end of file
diff --git a/backend/Dockerfile b/backend/Dockerfile
index c3187aeb28..57fa537edd 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -26,3 +26,5 @@ COPY ./prestart.sh /app/
COPY ./tests-start.sh /app/
COPY ./app /app/app
+
+RUN poetry run pip list
\ No newline at end of file
diff --git a/backend/app/alembic/env.py b/backend/app/alembic/env.py
index 7f29c04680..ddab70f856 100755
--- a/backend/app/alembic/env.py
+++ b/backend/app/alembic/env.py
@@ -22,7 +22,7 @@
from app.core.config import settings # noqa
target_metadata = SQLModel.metadata
-
+print("target_metadata in env:", SQLModel.metadata.tables)
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
@@ -78,7 +78,7 @@ def run_migrations_online():
context.run_migrations()
-if context.is_offline_mode():
- run_migrations_offline()
-else:
- run_migrations_online()
+# if context.is_offline_mode():
+# run_migrations_offline()
+# else:
+run_migrations_online()
diff --git a/backend/app/alembic/versions/1100c57e615e_initial_migration.py b/backend/app/alembic/versions/1100c57e615e_initial_migration.py
new file mode 100644
index 0000000000..b24dab34fb
--- /dev/null
+++ b/backend/app/alembic/versions/1100c57e615e_initial_migration.py
@@ -0,0 +1,526 @@
+"""Initial migration
+
+Revision ID: 1100c57e615e
+Revises:
+Create Date: 2024-09-28 12:41:42.435197
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel.sql.sqltypes
+
+
+# revision identifiers, used by Alembic.
+revision = '1100c57e615e'
+down_revision = None
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('foodcourt',
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('address', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('latitude', sa.Float(), nullable=True),
+ sa.Column('longitude', sa.Float(), nullable=True),
+ sa.Column('capacity', sa.Integer(), nullable=True),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('google_rating', sa.Float(), nullable=True),
+ sa.Column('instagram_handle', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('instagram_token', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('google_map_link', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('mobile_number', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('email', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('opening_time', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('closing_time', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('avg_expense_for_two', sa.Float(), nullable=True),
+ sa.Column('qr_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_foodcourt_id'), 'foodcourt', ['id'], unique=False)
+ op.create_table('nightclub',
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('address', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('latitude', sa.Float(), nullable=True),
+ sa.Column('longitude', sa.Float(), nullable=True),
+ sa.Column('capacity', sa.Integer(), nullable=True),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('google_rating', sa.Float(), nullable=True),
+ sa.Column('instagram_handle', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('instagram_token', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('google_map_link', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('mobile_number', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('email', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('opening_time', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('closing_time', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('avg_expense_for_two', sa.Float(), nullable=True),
+ sa.Column('qr_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_nightclub_id'), 'nightclub', ['id'], unique=False)
+ op.create_table('restaurant',
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('address', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('latitude', sa.Float(), nullable=True),
+ sa.Column('longitude', sa.Float(), nullable=True),
+ sa.Column('capacity', sa.Integer(), nullable=True),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('google_rating', sa.Float(), nullable=True),
+ sa.Column('instagram_handle', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('instagram_token', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('google_map_link', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('mobile_number', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('email', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('opening_time', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('closing_time', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('avg_expense_for_two', sa.Float(), nullable=True),
+ sa.Column('qr_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_restaurant_id'), 'restaurant', ['id'], unique=False)
+ op.create_table('user_business',
+ sa.Column('email', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True),
+ sa.Column('phone_number', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('is_active', sa.Boolean(), nullable=False),
+ sa.Column('is_superuser', sa.Boolean(), nullable=False),
+ sa.Column('full_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('registration_date', sa.DateTime(), nullable=False),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_user_business_email'), 'user_business', ['email'], unique=True)
+ op.create_index(op.f('ix_user_business_id'), 'user_business', ['id'], unique=False)
+ op.create_index(op.f('ix_user_business_phone_number'), 'user_business', ['phone_number'], unique=True)
+ op.create_table('user_public',
+ sa.Column('email', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True),
+ sa.Column('phone_number', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('is_active', sa.Boolean(), nullable=False),
+ sa.Column('is_superuser', sa.Boolean(), nullable=False),
+ sa.Column('full_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('date_of_birth', sa.DateTime(), nullable=True),
+ sa.Column('gender', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('registration_date', sa.DateTime(), nullable=False),
+ sa.Column('profile_picture', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('preferences', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_user_public_email'), 'user_public', ['email'], unique=True)
+ op.create_index(op.f('ix_user_public_id'), 'user_public', ['id'], unique=False)
+ op.create_index(op.f('ix_user_public_phone_number'), 'user_public', ['phone_number'], unique=True)
+ op.create_table('event',
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('nightclub_id', sa.Uuid(), nullable=False),
+ sa.Column('title', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('start_time', sa.DateTime(), nullable=False),
+ sa.Column('end_time', sa.DateTime(), nullable=False),
+ sa.Column('image_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('age_restriction', sa.Integer(), nullable=True),
+ sa.Column('dress_code', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.ForeignKeyConstraint(['nightclub_id'], ['nightclub.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_event_id'), 'event', ['id'], unique=False)
+ op.create_table('foodcourtuserbusinesslink',
+ sa.Column('foodcourt_id', sa.Uuid(), nullable=False),
+ sa.Column('user_business_id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['foodcourt_id'], ['foodcourt.id'], ),
+ sa.ForeignKeyConstraint(['user_business_id'], ['user_business.id'], ),
+ sa.PrimaryKeyConstraint('foodcourt_id', 'user_business_id')
+ )
+ op.create_table('group',
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('nightclub_id', sa.Uuid(), nullable=True),
+ sa.Column('created_at', sa.DateTime(), nullable=False),
+ sa.Column('admin_user_id', sa.Uuid(), nullable=False),
+ sa.Column('table_number', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.ForeignKeyConstraint(['admin_user_id'], ['user_public.id'], ),
+ sa.ForeignKeyConstraint(['nightclub_id'], ['nightclub.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_group_id'), 'group', ['id'], unique=False)
+ op.create_table('nightclub_menu',
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('menu_type', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('nightclub_id', sa.Uuid(), nullable=False),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['nightclub_id'], ['nightclub.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_nightclub_menu_id'), 'nightclub_menu', ['id'], unique=False)
+ op.create_table('nightclubuserbusinesslink',
+ sa.Column('nightclub_id', sa.Uuid(), nullable=False),
+ sa.Column('user_business_id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['nightclub_id'], ['nightclub.id'], ),
+ sa.ForeignKeyConstraint(['user_business_id'], ['user_business.id'], ),
+ sa.PrimaryKeyConstraint('nightclub_id', 'user_business_id')
+ )
+ op.create_table('payment_source_nightclub',
+ sa.Column('user_id', sa.Uuid(), nullable=False),
+ sa.Column('source_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('gateway_transaction_id', sa.Uuid(), nullable=True),
+ sa.Column('payment_time', sa.DateTime(), nullable=False),
+ sa.Column('amount', sa.Float(), nullable=False),
+ sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('retry_count', sa.Integer(), nullable=False),
+ sa.Column('last_attempt_time', sa.DateTime(), nullable=True),
+ sa.ForeignKeyConstraint(['user_id'], ['user_public.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_payment_source_nightclub_id'), 'payment_source_nightclub', ['id'], unique=False)
+ op.create_table('payment_source_qsr',
+ sa.Column('user_id', sa.Uuid(), nullable=False),
+ sa.Column('source_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('gateway_transaction_id', sa.Uuid(), nullable=True),
+ sa.Column('payment_time', sa.DateTime(), nullable=False),
+ sa.Column('amount', sa.Float(), nullable=False),
+ sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('retry_count', sa.Integer(), nullable=False),
+ sa.Column('last_attempt_time', sa.DateTime(), nullable=True),
+ sa.ForeignKeyConstraint(['user_id'], ['user_public.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_payment_source_qsr_id'), 'payment_source_qsr', ['id'], unique=False)
+ op.create_table('payment_source_restaurant',
+ sa.Column('user_id', sa.Uuid(), nullable=False),
+ sa.Column('source_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('gateway_transaction_id', sa.Uuid(), nullable=True),
+ sa.Column('payment_time', sa.DateTime(), nullable=False),
+ sa.Column('amount', sa.Float(), nullable=False),
+ sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('retry_count', sa.Integer(), nullable=False),
+ sa.Column('last_attempt_time', sa.DateTime(), nullable=True),
+ sa.ForeignKeyConstraint(['user_id'], ['user_public.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_payment_source_restaurant_id'), 'payment_source_restaurant', ['id'], unique=False)
+ op.create_table('pickup_location',
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('nightclub_id', sa.Uuid(), nullable=False),
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.ForeignKeyConstraint(['nightclub_id'], ['nightclub.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_pickup_location_id'), 'pickup_location', ['id'], unique=False)
+ op.create_table('qsr',
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('address', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('latitude', sa.Float(), nullable=True),
+ sa.Column('longitude', sa.Float(), nullable=True),
+ sa.Column('capacity', sa.Integer(), nullable=True),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('google_rating', sa.Float(), nullable=True),
+ sa.Column('instagram_handle', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('instagram_token', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('google_map_link', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('mobile_number', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('email', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('opening_time', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('closing_time', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('avg_expense_for_two', sa.Float(), nullable=True),
+ sa.Column('qr_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('foodcourt_id', sa.Uuid(), nullable=True),
+ sa.ForeignKeyConstraint(['foodcourt_id'], ['foodcourt.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_qsr_id'), 'qsr', ['id'], unique=False)
+ op.create_table('restaurant_menu',
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('menu_type', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('restaurant_id', sa.Uuid(), nullable=False),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['restaurant_id'], ['restaurant.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_restaurant_menu_id'), 'restaurant_menu', ['id'], unique=False)
+ op.create_table('restaurantuserbusinesslink',
+ sa.Column('restaurant_id', sa.Uuid(), nullable=False),
+ sa.Column('user_business_id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['restaurant_id'], ['restaurant.id'], ),
+ sa.ForeignKeyConstraint(['user_business_id'], ['user_business.id'], ),
+ sa.PrimaryKeyConstraint('restaurant_id', 'user_business_id')
+ )
+ op.create_table('clubvisit',
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('user_id', sa.Uuid(), nullable=False),
+ sa.Column('group_id', sa.Uuid(), nullable=True),
+ sa.Column('nightclub_id', sa.Uuid(), nullable=False),
+ sa.Column('entry_time', sa.DateTime(), nullable=False),
+ sa.Column('exit_time', sa.DateTime(), nullable=True),
+ sa.Column('cover_charge', sa.Float(), nullable=True),
+ sa.Column('total_bill', sa.Float(), nullable=True),
+ sa.ForeignKeyConstraint(['group_id'], ['group.id'], ),
+ sa.ForeignKeyConstraint(['nightclub_id'], ['nightclub.id'], ),
+ sa.ForeignKeyConstraint(['user_id'], ['user_public.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_table('event_booking',
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('user_id', sa.Uuid(), nullable=False),
+ sa.Column('event_id', sa.Uuid(), nullable=False),
+ sa.Column('booking_time', sa.DateTime(), nullable=False),
+ sa.Column('total_amount', sa.Float(), nullable=False),
+ sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.ForeignKeyConstraint(['event_id'], ['event.id'], ),
+ sa.ForeignKeyConstraint(['user_id'], ['user_public.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_table('group_wallet',
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('group_id', sa.Uuid(), nullable=False),
+ sa.Column('balance', sa.Float(), nullable=False),
+ sa.ForeignKeyConstraint(['group_id'], ['group.id'], ),
+ sa.PrimaryKeyConstraint('id'),
+ sa.UniqueConstraint('group_id')
+ )
+ op.create_index(op.f('ix_group_wallet_id'), 'group_wallet', ['id'], unique=False)
+ op.create_table('groupmembers',
+ sa.Column('group_id', sa.Uuid(), nullable=False),
+ sa.Column('user_id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['group_id'], ['group.id'], ),
+ sa.ForeignKeyConstraint(['user_id'], ['user_public.id'], ),
+ sa.PrimaryKeyConstraint('group_id', 'user_id')
+ )
+ op.create_table('nightclub_order',
+ sa.Column('user_id', sa.Uuid(), nullable=False),
+ sa.Column('note', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('order_time', sa.DateTime(), nullable=False),
+ sa.Column('total_amount', sa.Float(), nullable=False),
+ sa.Column('taxes_and_charges', sa.Float(), nullable=True),
+ sa.Column('cover_charge_used', sa.Float(), nullable=True),
+ sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('service_type', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('venue_id', sa.Uuid(), nullable=True),
+ sa.Column('payment_id', sa.Uuid(), nullable=True),
+ sa.Column('pickup_location_id', sa.Uuid(), nullable=True),
+ sa.ForeignKeyConstraint(['payment_id'], ['payment_source_nightclub.id'], ),
+ sa.ForeignKeyConstraint(['pickup_location_id'], ['pickup_location.id'], ),
+ sa.ForeignKeyConstraint(['user_id'], ['user_public.id'], ),
+ sa.ForeignKeyConstraint(['venue_id'], ['nightclub.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_nightclub_order_id'), 'nightclub_order', ['id'], unique=False)
+ op.create_table('qsr_menu',
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('menu_type', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('qsr_id', sa.Uuid(), nullable=False),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['qsr_id'], ['qsr.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_qsr_menu_id'), 'qsr_menu', ['id'], unique=False)
+ op.create_table('qsr_order',
+ sa.Column('user_id', sa.Uuid(), nullable=False),
+ sa.Column('pickup_location_id', sa.Uuid(), nullable=True),
+ sa.Column('note', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('order_time', sa.DateTime(), nullable=False),
+ sa.Column('total_amount', sa.Float(), nullable=False),
+ sa.Column('taxes_and_charges', sa.Float(), nullable=True),
+ sa.Column('cover_charge_used', sa.Float(), nullable=True),
+ sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('service_type', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('venue_id', sa.Uuid(), nullable=False),
+ sa.Column('payment_id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['payment_id'], ['payment_source_qsr.id'], ),
+ sa.ForeignKeyConstraint(['pickup_location_id'], ['pickup_location.id'], ),
+ sa.ForeignKeyConstraint(['user_id'], ['user_public.id'], ),
+ sa.ForeignKeyConstraint(['venue_id'], ['qsr.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_qsr_order_id'), 'qsr_order', ['id'], unique=False)
+ op.create_table('qsruserbusinesslink',
+ sa.Column('qsr_id', sa.Uuid(), nullable=False),
+ sa.Column('user_business_id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['qsr_id'], ['qsr.id'], ),
+ sa.ForeignKeyConstraint(['user_business_id'], ['user_business.id'], ),
+ sa.PrimaryKeyConstraint('qsr_id', 'user_business_id')
+ )
+ op.create_table('restaurant_order',
+ sa.Column('user_id', sa.Uuid(), nullable=False),
+ sa.Column('pickup_location_id', sa.Uuid(), nullable=True),
+ sa.Column('note', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('order_time', sa.DateTime(), nullable=False),
+ sa.Column('total_amount', sa.Float(), nullable=False),
+ sa.Column('taxes_and_charges', sa.Float(), nullable=True),
+ sa.Column('cover_charge_used', sa.Float(), nullable=True),
+ sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('service_type', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('venue_id', sa.Uuid(), nullable=True),
+ sa.Column('payment_id', sa.Uuid(), nullable=True),
+ sa.ForeignKeyConstraint(['payment_id'], ['payment_source_restaurant.id'], ),
+ sa.ForeignKeyConstraint(['pickup_location_id'], ['pickup_location.id'], ),
+ sa.ForeignKeyConstraint(['user_id'], ['user_public.id'], ),
+ sa.ForeignKeyConstraint(['venue_id'], ['restaurant.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_restaurant_order_id'), 'restaurant_order', ['id'], unique=False)
+ op.create_table('event_offering',
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('event_id', sa.Uuid(), nullable=False),
+ sa.Column('event_booking_id', sa.Uuid(), nullable=False),
+ sa.Column('offering_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('price', sa.Float(), nullable=False),
+ sa.Column('total_guests_per_pass', sa.Integer(), nullable=False),
+ sa.Column('cover_charge', sa.Float(), nullable=True),
+ sa.Column('additional_charges', sa.Float(), nullable=True),
+ sa.Column('availability', sa.Integer(), nullable=False),
+ sa.ForeignKeyConstraint(['event_booking_id'], ['event_booking.id'], ),
+ sa.ForeignKeyConstraint(['event_id'], ['event.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_event_offering_id'), 'event_offering', ['id'], unique=False)
+ op.create_table('group_nightclub_order_link',
+ sa.Column('group_id', sa.Uuid(), nullable=False),
+ sa.Column('nightclub_order_id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['group_id'], ['group.id'], ),
+ sa.ForeignKeyConstraint(['nightclub_order_id'], ['nightclub_order.id'], ),
+ sa.PrimaryKeyConstraint('group_id', 'nightclub_order_id')
+ )
+ op.create_table('groupwallettopup',
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('group_wallet_id', sa.Uuid(), nullable=False),
+ sa.Column('amount', sa.Float(), nullable=False),
+ sa.Column('topup_time', sa.DateTime(), nullable=False),
+ sa.ForeignKeyConstraint(['group_wallet_id'], ['group_wallet.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_groupwallettopup_id'), 'groupwallettopup', ['id'], unique=False)
+ op.create_table('menu_category',
+ sa.Column('qsr_menu_id', sa.Uuid(), nullable=True),
+ sa.Column('restaurant_menu_id', sa.Uuid(), nullable=True),
+ sa.Column('nightclub_menu_id', sa.Uuid(), nullable=True),
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['nightclub_menu_id'], ['nightclub_menu.id'], ),
+ sa.ForeignKeyConstraint(['qsr_menu_id'], ['qsr_menu.id'], ),
+ sa.ForeignKeyConstraint(['restaurant_menu_id'], ['restaurant_menu.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_menu_category_id'), 'menu_category', ['id'], unique=False)
+ op.create_table('payment_event',
+ sa.Column('user_id', sa.Uuid(), nullable=False),
+ sa.Column('source_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('gateway_transaction_id', sa.Uuid(), nullable=True),
+ sa.Column('payment_time', sa.DateTime(), nullable=False),
+ sa.Column('amount', sa.Float(), nullable=False),
+ sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('event_booking_id', sa.Uuid(), nullable=True),
+ sa.ForeignKeyConstraint(['event_booking_id'], ['event_booking.id'], ),
+ sa.ForeignKeyConstraint(['user_id'], ['user_public.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_payment_event_id'), 'payment_event', ['id'], unique=False)
+ op.create_table('menu_item',
+ sa.Column('category_id', sa.Uuid(), nullable=False),
+ sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
+ sa.Column('price', sa.Float(), nullable=False),
+ sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('image_url', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('is_veg', sa.Boolean(), nullable=True),
+ sa.Column('ingredients', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('abv', sa.Float(), nullable=True),
+ sa.Column('ibu', sa.Integer(), nullable=True),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.ForeignKeyConstraint(['category_id'], ['menu_category.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ op.create_index(op.f('ix_menu_item_id'), 'menu_item', ['id'], unique=False)
+ op.create_table('orderitem',
+ sa.Column('order_item_id', sa.Uuid(), nullable=False),
+ sa.Column('nightclub_order_id', sa.Uuid(), nullable=True),
+ sa.Column('restaurant_order_id', sa.Uuid(), nullable=True),
+ sa.Column('qsr_order_id', sa.Uuid(), nullable=True),
+ sa.Column('item_id', sa.Uuid(), nullable=False),
+ sa.Column('quantity', sa.Integer(), nullable=False),
+ sa.ForeignKeyConstraint(['item_id'], ['menu_item.id'], ),
+ sa.ForeignKeyConstraint(['nightclub_order_id'], ['nightclub_order.id'], ),
+ sa.ForeignKeyConstraint(['qsr_order_id'], ['qsr_order.id'], ),
+ sa.ForeignKeyConstraint(['restaurant_order_id'], ['restaurant_order.id'], ),
+ sa.PrimaryKeyConstraint('order_item_id')
+ )
+ op.create_index(op.f('ix_orderitem_order_item_id'), 'orderitem', ['order_item_id'], unique=False)
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_index(op.f('ix_orderitem_order_item_id'), table_name='orderitem')
+ op.drop_table('orderitem')
+ op.drop_index(op.f('ix_menu_item_id'), table_name='menu_item')
+ op.drop_table('menu_item')
+ op.drop_index(op.f('ix_payment_event_id'), table_name='payment_event')
+ op.drop_table('payment_event')
+ op.drop_index(op.f('ix_menu_category_id'), table_name='menu_category')
+ op.drop_table('menu_category')
+ op.drop_index(op.f('ix_groupwallettopup_id'), table_name='groupwallettopup')
+ op.drop_table('groupwallettopup')
+ op.drop_table('group_nightclub_order_link')
+ op.drop_index(op.f('ix_event_offering_id'), table_name='event_offering')
+ op.drop_table('event_offering')
+ op.drop_index(op.f('ix_restaurant_order_id'), table_name='restaurant_order')
+ op.drop_table('restaurant_order')
+ op.drop_table('qsruserbusinesslink')
+ op.drop_index(op.f('ix_qsr_order_id'), table_name='qsr_order')
+ op.drop_table('qsr_order')
+ op.drop_index(op.f('ix_qsr_menu_id'), table_name='qsr_menu')
+ op.drop_table('qsr_menu')
+ op.drop_index(op.f('ix_nightclub_order_id'), table_name='nightclub_order')
+ op.drop_table('nightclub_order')
+ op.drop_table('groupmembers')
+ op.drop_index(op.f('ix_group_wallet_id'), table_name='group_wallet')
+ op.drop_table('group_wallet')
+ op.drop_table('event_booking')
+ op.drop_table('clubvisit')
+ op.drop_table('restaurantuserbusinesslink')
+ op.drop_index(op.f('ix_restaurant_menu_id'), table_name='restaurant_menu')
+ op.drop_table('restaurant_menu')
+ op.drop_index(op.f('ix_qsr_id'), table_name='qsr')
+ op.drop_table('qsr')
+ op.drop_index(op.f('ix_pickup_location_id'), table_name='pickup_location')
+ op.drop_table('pickup_location')
+ op.drop_index(op.f('ix_payment_source_restaurant_id'), table_name='payment_source_restaurant')
+ op.drop_table('payment_source_restaurant')
+ op.drop_index(op.f('ix_payment_source_qsr_id'), table_name='payment_source_qsr')
+ op.drop_table('payment_source_qsr')
+ op.drop_index(op.f('ix_payment_source_nightclub_id'), table_name='payment_source_nightclub')
+ op.drop_table('payment_source_nightclub')
+ op.drop_table('nightclubuserbusinesslink')
+ op.drop_index(op.f('ix_nightclub_menu_id'), table_name='nightclub_menu')
+ op.drop_table('nightclub_menu')
+ op.drop_index(op.f('ix_group_id'), table_name='group')
+ op.drop_table('group')
+ op.drop_table('foodcourtuserbusinesslink')
+ op.drop_index(op.f('ix_event_id'), table_name='event')
+ op.drop_table('event')
+ op.drop_index(op.f('ix_user_public_phone_number'), table_name='user_public')
+ op.drop_index(op.f('ix_user_public_id'), table_name='user_public')
+ op.drop_index(op.f('ix_user_public_email'), table_name='user_public')
+ op.drop_table('user_public')
+ op.drop_index(op.f('ix_user_business_phone_number'), table_name='user_business')
+ op.drop_index(op.f('ix_user_business_id'), table_name='user_business')
+ op.drop_index(op.f('ix_user_business_email'), table_name='user_business')
+ op.drop_table('user_business')
+ op.drop_index(op.f('ix_restaurant_id'), table_name='restaurant')
+ op.drop_table('restaurant')
+ op.drop_index(op.f('ix_nightclub_id'), table_name='nightclub')
+ op.drop_table('nightclub')
+ op.drop_index(op.f('ix_foodcourt_id'), table_name='foodcourt')
+ op.drop_table('foodcourt')
+ # ### end Alembic commands ###
diff --git a/backend/app/alembic/versions/1a31ce608336_add_cascade_delete_relationships.py b/backend/app/alembic/versions/1a31ce608336_add_cascade_delete_relationships.py
deleted file mode 100644
index 10e47a1456..0000000000
--- a/backend/app/alembic/versions/1a31ce608336_add_cascade_delete_relationships.py
+++ /dev/null
@@ -1,37 +0,0 @@
-"""Add cascade delete relationships
-
-Revision ID: 1a31ce608336
-Revises: d98dd8ec85a3
-Create Date: 2024-07-31 22:24:34.447891
-
-"""
-from alembic import op
-import sqlalchemy as sa
-import sqlmodel.sql.sqltypes
-
-
-# revision identifiers, used by Alembic.
-revision = '1a31ce608336'
-down_revision = 'd98dd8ec85a3'
-branch_labels = None
-depends_on = None
-
-
-def upgrade():
- # ### commands auto generated by Alembic - please adjust! ###
- op.alter_column('item', 'owner_id',
- existing_type=sa.UUID(),
- nullable=False)
- op.drop_constraint('item_owner_id_fkey', 'item', type_='foreignkey')
- op.create_foreign_key(None, 'item', 'user', ['owner_id'], ['id'], ondelete='CASCADE')
- # ### end Alembic commands ###
-
-
-def downgrade():
- # ### commands auto generated by Alembic - please adjust! ###
- op.drop_constraint(None, 'item', type_='foreignkey')
- op.create_foreign_key('item_owner_id_fkey', 'item', 'user', ['owner_id'], ['id'])
- op.alter_column('item', 'owner_id',
- existing_type=sa.UUID(),
- nullable=True)
- # ### end Alembic commands ###
diff --git a/backend/app/alembic/versions/375a3d9f95aa_added_qr_codes_to_foodcourt.py b/backend/app/alembic/versions/375a3d9f95aa_added_qr_codes_to_foodcourt.py
new file mode 100644
index 0000000000..28e957474a
--- /dev/null
+++ b/backend/app/alembic/versions/375a3d9f95aa_added_qr_codes_to_foodcourt.py
@@ -0,0 +1,29 @@
+"""added qr_codes to foodcourt
+
+Revision ID: 375a3d9f95aa
+Revises: fe4249d074a6
+Create Date: 2024-10-05 07:58:40.774421
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel.sql.sqltypes
+
+
+# revision identifiers, used by Alembic.
+revision = '375a3d9f95aa'
+down_revision = 'fe4249d074a6'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ pass
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ pass
+ # ### end Alembic commands ###
diff --git a/backend/app/alembic/versions/50ffb0a7eef5_initial_migration.py b/backend/app/alembic/versions/50ffb0a7eef5_initial_migration.py
new file mode 100644
index 0000000000..e5d215b7bb
--- /dev/null
+++ b/backend/app/alembic/versions/50ffb0a7eef5_initial_migration.py
@@ -0,0 +1,35 @@
+"""Initial migration
+
+Revision ID: 50ffb0a7eef5
+Revises: 1100c57e615e
+Create Date: 2024-09-28 13:06:36.733410
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel.sql.sqltypes
+
+
+# revision identifiers, used by Alembic.
+revision = '50ffb0a7eef5'
+down_revision = '1100c57e615e'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('orderitem', sa.Column('id', sa.Uuid(), nullable=False))
+ op.drop_index('ix_orderitem_order_item_id', table_name='orderitem')
+ op.create_index(op.f('ix_orderitem_id'), 'orderitem', ['id'], unique=False)
+ op.drop_column('orderitem', 'order_item_id')
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('orderitem', sa.Column('order_item_id', sa.UUID(), autoincrement=False, nullable=False))
+ op.drop_index(op.f('ix_orderitem_id'), table_name='orderitem')
+ op.create_index('ix_orderitem_order_item_id', 'orderitem', ['order_item_id'], unique=False)
+ op.drop_column('orderitem', 'id')
+ # ### end Alembic commands ###
diff --git a/backend/app/alembic/versions/9c0a54914c78_add_max_length_for_string_varchar_.py b/backend/app/alembic/versions/9c0a54914c78_add_max_length_for_string_varchar_.py
deleted file mode 100755
index 78a41773b9..0000000000
--- a/backend/app/alembic/versions/9c0a54914c78_add_max_length_for_string_varchar_.py
+++ /dev/null
@@ -1,69 +0,0 @@
-"""Add max length for string(varchar) fields in User and Items models
-
-Revision ID: 9c0a54914c78
-Revises: e2412789c190
-Create Date: 2024-06-17 14:42:44.639457
-
-"""
-from alembic import op
-import sqlalchemy as sa
-import sqlmodel.sql.sqltypes
-
-
-# revision identifiers, used by Alembic.
-revision = '9c0a54914c78'
-down_revision = 'e2412789c190'
-branch_labels = None
-depends_on = None
-
-
-def upgrade():
- # Adjust the length of the email field in the User table
- op.alter_column('user', 'email',
- existing_type=sa.String(),
- type_=sa.String(length=255),
- existing_nullable=False)
-
- # Adjust the length of the full_name field in the User table
- op.alter_column('user', 'full_name',
- existing_type=sa.String(),
- type_=sa.String(length=255),
- existing_nullable=True)
-
- # Adjust the length of the title field in the Item table
- op.alter_column('item', 'title',
- existing_type=sa.String(),
- type_=sa.String(length=255),
- existing_nullable=False)
-
- # Adjust the length of the description field in the Item table
- op.alter_column('item', 'description',
- existing_type=sa.String(),
- type_=sa.String(length=255),
- existing_nullable=True)
-
-
-def downgrade():
- # Revert the length of the email field in the User table
- op.alter_column('user', 'email',
- existing_type=sa.String(length=255),
- type_=sa.String(),
- existing_nullable=False)
-
- # Revert the length of the full_name field in the User table
- op.alter_column('user', 'full_name',
- existing_type=sa.String(length=255),
- type_=sa.String(),
- existing_nullable=True)
-
- # Revert the length of the title field in the Item table
- op.alter_column('item', 'title',
- existing_type=sa.String(length=255),
- type_=sa.String(),
- existing_nullable=False)
-
- # Revert the length of the description field in the Item table
- op.alter_column('item', 'description',
- existing_type=sa.String(length=255),
- type_=sa.String(),
- existing_nullable=True)
diff --git a/backend/app/alembic/versions/a392ecf44925_c.py b/backend/app/alembic/versions/a392ecf44925_c.py
new file mode 100644
index 0000000000..e38427df1f
--- /dev/null
+++ b/backend/app/alembic/versions/a392ecf44925_c.py
@@ -0,0 +1,31 @@
+"""c
+
+Revision ID: a392ecf44925
+Revises: 50ffb0a7eef5
+Create Date: 2024-09-28 18:47:47.766797
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel.sql.sqltypes
+
+
+# revision identifiers, used by Alembic.
+revision = 'a392ecf44925'
+down_revision = '50ffb0a7eef5'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('user_business', sa.Column('refresh_token', sqlmodel.sql.sqltypes.AutoString(), nullable=True))
+ op.add_column('user_public', sa.Column('refresh_token', sqlmodel.sql.sqltypes.AutoString(), nullable=True))
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_column('user_public', 'refresh_token')
+ op.drop_column('user_business', 'refresh_token')
+ # ### end Alembic commands ###
diff --git a/backend/app/alembic/versions/d98dd8ec85a3_edit_replace_id_integers_in_all_models_.py b/backend/app/alembic/versions/d98dd8ec85a3_edit_replace_id_integers_in_all_models_.py
deleted file mode 100755
index 37af1fa215..0000000000
--- a/backend/app/alembic/versions/d98dd8ec85a3_edit_replace_id_integers_in_all_models_.py
+++ /dev/null
@@ -1,90 +0,0 @@
-"""Edit replace id integers in all models to use UUID instead
-
-Revision ID: d98dd8ec85a3
-Revises: 9c0a54914c78
-Create Date: 2024-07-19 04:08:04.000976
-
-"""
-from alembic import op
-import sqlalchemy as sa
-import sqlmodel.sql.sqltypes
-from sqlalchemy.dialects import postgresql
-
-
-# revision identifiers, used by Alembic.
-revision = 'd98dd8ec85a3'
-down_revision = '9c0a54914c78'
-branch_labels = None
-depends_on = None
-
-
-def upgrade():
- # Ensure uuid-ossp extension is available
- op.execute('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"')
-
- # Create a new UUID column with a default UUID value
- op.add_column('user', sa.Column('new_id', postgresql.UUID(as_uuid=True), default=sa.text('uuid_generate_v4()')))
- op.add_column('item', sa.Column('new_id', postgresql.UUID(as_uuid=True), default=sa.text('uuid_generate_v4()')))
- op.add_column('item', sa.Column('new_owner_id', postgresql.UUID(as_uuid=True), nullable=True))
-
- # Populate the new columns with UUIDs
- op.execute('UPDATE "user" SET new_id = uuid_generate_v4()')
- op.execute('UPDATE item SET new_id = uuid_generate_v4()')
- op.execute('UPDATE item SET new_owner_id = (SELECT new_id FROM "user" WHERE "user".id = item.owner_id)')
-
- # Set the new_id as not nullable
- op.alter_column('user', 'new_id', nullable=False)
- op.alter_column('item', 'new_id', nullable=False)
-
- # Drop old columns and rename new columns
- op.drop_constraint('item_owner_id_fkey', 'item', type_='foreignkey')
- op.drop_column('item', 'owner_id')
- op.alter_column('item', 'new_owner_id', new_column_name='owner_id')
-
- op.drop_column('user', 'id')
- op.alter_column('user', 'new_id', new_column_name='id')
-
- op.drop_column('item', 'id')
- op.alter_column('item', 'new_id', new_column_name='id')
-
- # Create primary key constraint
- op.create_primary_key('user_pkey', 'user', ['id'])
- op.create_primary_key('item_pkey', 'item', ['id'])
-
- # Recreate foreign key constraint
- op.create_foreign_key('item_owner_id_fkey', 'item', 'user', ['owner_id'], ['id'])
-
-def downgrade():
- # Reverse the upgrade process
- op.add_column('user', sa.Column('old_id', sa.Integer, autoincrement=True))
- op.add_column('item', sa.Column('old_id', sa.Integer, autoincrement=True))
- op.add_column('item', sa.Column('old_owner_id', sa.Integer, nullable=True))
-
- # Populate the old columns with default values
- # Generate sequences for the integer IDs if not exist
- op.execute('CREATE SEQUENCE IF NOT EXISTS user_id_seq AS INTEGER OWNED BY "user".old_id')
- op.execute('CREATE SEQUENCE IF NOT EXISTS item_id_seq AS INTEGER OWNED BY item.old_id')
-
- op.execute('SELECT setval(\'user_id_seq\', COALESCE((SELECT MAX(old_id) + 1 FROM "user"), 1), false)')
- op.execute('SELECT setval(\'item_id_seq\', COALESCE((SELECT MAX(old_id) + 1 FROM item), 1), false)')
-
- op.execute('UPDATE "user" SET old_id = nextval(\'user_id_seq\')')
- op.execute('UPDATE item SET old_id = nextval(\'item_id_seq\'), old_owner_id = (SELECT old_id FROM "user" WHERE "user".id = item.owner_id)')
-
- # Drop new columns and rename old columns back
- op.drop_constraint('item_owner_id_fkey', 'item', type_='foreignkey')
- op.drop_column('item', 'owner_id')
- op.alter_column('item', 'old_owner_id', new_column_name='owner_id')
-
- op.drop_column('user', 'id')
- op.alter_column('user', 'old_id', new_column_name='id')
-
- op.drop_column('item', 'id')
- op.alter_column('item', 'old_id', new_column_name='id')
-
- # Create primary key constraint
- op.create_primary_key('user_pkey', 'user', ['id'])
- op.create_primary_key('item_pkey', 'item', ['id'])
-
- # Recreate foreign key constraint
- op.create_foreign_key('item_owner_id_fkey', 'item', 'user', ['owner_id'], ['id'])
diff --git a/backend/app/alembic/versions/e2412789c190_initialize_models.py b/backend/app/alembic/versions/e2412789c190_initialize_models.py
deleted file mode 100644
index 7529ea91fa..0000000000
--- a/backend/app/alembic/versions/e2412789c190_initialize_models.py
+++ /dev/null
@@ -1,54 +0,0 @@
-"""Initialize models
-
-Revision ID: e2412789c190
-Revises:
-Create Date: 2023-11-24 22:55:43.195942
-
-"""
-import sqlalchemy as sa
-import sqlmodel.sql.sqltypes
-from alembic import op
-
-# revision identifiers, used by Alembic.
-revision = "e2412789c190"
-down_revision = None
-branch_labels = None
-depends_on = None
-
-
-def upgrade():
- # ### commands auto generated by Alembic - please adjust! ###
- op.create_table(
- "user",
- sa.Column("email", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
- sa.Column("is_active", sa.Boolean(), nullable=False),
- sa.Column("is_superuser", sa.Boolean(), nullable=False),
- sa.Column("full_name", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
- sa.Column("id", sa.Integer(), nullable=False),
- sa.Column(
- "hashed_password", sqlmodel.sql.sqltypes.AutoString(), nullable=False
- ),
- sa.PrimaryKeyConstraint("id"),
- )
- op.create_index(op.f("ix_user_email"), "user", ["email"], unique=True)
- op.create_table(
- "item",
- sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
- sa.Column("id", sa.Integer(), nullable=False),
- sa.Column("title", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
- sa.Column("owner_id", sa.Integer(), nullable=False),
- sa.ForeignKeyConstraint(
- ["owner_id"],
- ["user.id"],
- ),
- sa.PrimaryKeyConstraint("id"),
- )
- # ### end Alembic commands ###
-
-
-def downgrade():
- # ### commands auto generated by Alembic - please adjust! ###
- op.drop_table("item")
- op.drop_index(op.f("ix_user_email"), table_name="user")
- op.drop_table("user")
- # ### end Alembic commands ###
diff --git a/backend/app/alembic/versions/fe4249d074a6_added_qr_codes_to_foodcourt.py b/backend/app/alembic/versions/fe4249d074a6_added_qr_codes_to_foodcourt.py
new file mode 100644
index 0000000000..64bb0b66c4
--- /dev/null
+++ b/backend/app/alembic/versions/fe4249d074a6_added_qr_codes_to_foodcourt.py
@@ -0,0 +1,41 @@
+"""added qr_codes to foodcourt
+
+Revision ID: fe4249d074a6
+Revises: a392ecf44925
+Create Date: 2024-10-05 07:51:04.040718
+
+"""
+from alembic import op
+import sqlalchemy as sa
+import sqlmodel.sql.sqltypes
+
+
+# revision identifiers, used by Alembic.
+revision = 'fe4249d074a6'
+down_revision = 'a392ecf44925'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('qr_codes',
+ sa.Column('table_number', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
+ sa.Column('id', sa.Uuid(), nullable=False),
+ sa.Column('foodcourt_id', sa.Uuid(), nullable=True),
+ sa.Column('qsr_id', sa.Uuid(), nullable=True),
+ sa.Column('nightclub_id', sa.Uuid(), nullable=True),
+ sa.Column('restaurant_id', sa.Uuid(), nullable=True),
+ sa.ForeignKeyConstraint(['foodcourt_id'], ['foodcourt.id'], ),
+ sa.ForeignKeyConstraint(['nightclub_id'], ['nightclub.id'], ),
+ sa.ForeignKeyConstraint(['qsr_id'], ['qsr.id'], ),
+ sa.ForeignKeyConstraint(['restaurant_id'], ['restaurant.id'], ),
+ sa.PrimaryKeyConstraint('id')
+ )
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_table('qr_codes')
+ # ### end Alembic commands ###
diff --git a/backend/app/api/deps.py b/backend/app/api/deps.py
index c2b83c841d..5f65d667e8 100644
--- a/backend/app/api/deps.py
+++ b/backend/app/api/deps.py
@@ -1,22 +1,15 @@
-from collections.abc import Generator
-from typing import Annotated
-
-import jwt
-from fastapi import Depends, HTTPException, status
-from fastapi.security import OAuth2PasswordBearer
-from jwt.exceptions import InvalidTokenError
-from pydantic import ValidationError
-from sqlmodel import Session
-
-from app.core import security
+from app.models.auth import TokenBlacklist
+from fastapi import Depends, HTTPException, Query, status
+from sqlalchemy.orm import Session
+from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer, OAuth2PasswordBearer
+from app.models.user import UserPublic, UserBusiness
+from app.core.security import get_jwt_payload
+from typing import Annotated, Generator, Optional, Union
from app.core.config import settings
from app.core.db import engine
-from app.models import TokenPayload, User
-
-reusable_oauth2 = OAuth2PasswordBearer(
- tokenUrl=f"{settings.API_V1_STR}/login/access-token"
-)
+# OAuth2PasswordBearer to extract the token from the request header
+bearer_scheme = HTTPBearer()
def get_db() -> Generator[Session, None, None]:
with Session(engine) as session:
@@ -24,34 +17,114 @@ def get_db() -> Generator[Session, None, None]:
SessionDep = Annotated[Session, Depends(get_db)]
-TokenDep = Annotated[str, Depends(reusable_oauth2)]
+# # Check if the token is blacklisted (optional)
+# def is_token_blacklisted(session: Session, user_id: str, provided_token: str) -> bool:
+# """
+# Checks if the provided token is blacklisted by comparing it with the one stored in the user record.
+
+# Args:
+# session (Session): SQLAlchemy session to query the database.
+# user_id (str): The ID of the user.
+# provided_token (str): The provided refresh token to check.
+
+# Returns:
+# bool: True if the token is blacklisted (invalid), False otherwise.
+# """
+# # Fetch the user from the database using the user_id
+# user = session.query(UserPublic).filter(UserPublic.id == user_id).first()
+
+# if not user:
+# raise HTTPException(status_code=404, detail="User not found")
+
+# # Check if the provided token matches the stored refresh token
+# if user.refresh_token != provided_token:
+# # The token does not match, consider it invalid or blacklisted
+# return True
-def get_current_user(session: SessionDep, token: TokenDep) -> User:
+# # If the token matches, it's not blacklisted
+# return False
+
+# Dependency to get the current user
+async def get_current_user(
+ credentials: Annotated[HTTPAuthorizationCredentials, Depends(bearer_scheme)],
+ session: SessionDep
+) -> Union[UserPublic, UserBusiness]:
+ # print('credentials.credentials ', credentials.credentials)
try:
- payload = jwt.decode(
- token, settings.SECRET_KEY, algorithms=[security.ALGORITHM]
+ print('credentials.credentials ', credentials.credentials)
+ # Verify and decode the token (ensure this is as fast as possible)
+ token_data = get_jwt_payload(credentials.credentials)
+ user_id = token_data.sub
+ print('hhuuuser_id ', user_id)
+ # Query both user types in a single call, using a union if possible
+ user = (
+ session.query(UserPublic)
+ .filter(UserPublic.id == user_id)
+ .first()
+ ) or (
+ session.query(UserBusiness)
+ .filter(UserBusiness.id == user_id)
+ .first()
)
- token_data = TokenPayload(**payload)
- except (InvalidTokenError, ValidationError):
- raise HTTPException(
- status_code=status.HTTP_403_FORBIDDEN,
- detail="Could not validate credentials",
- )
- user = session.get(User, token_data.sub)
- if not user:
- raise HTTPException(status_code=404, detail="User not found")
- if not user.is_active:
- raise HTTPException(status_code=400, detail="Inactive user")
- return user
+ # If no user is found or the user is inactive, raise an error
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="User not found",
+ )
+ if not user.is_active:
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail="Inactive user",
+ )
-CurrentUser = Annotated[User, Depends(get_current_user)]
+ return user
+ except Exception:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Could not validate credentials"
+ )
+
+# Dependency to get the business user
+async def get_business_user(
+ credentials: Annotated[HTTPAuthorizationCredentials, Depends(bearer_scheme)],
+ session: SessionDep
+) -> UserBusiness:
+ current_user = await get_current_user(credentials, session)
+ if not isinstance(current_user, UserBusiness):
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail="Not a business user",
+ )
+ return current_user
-def get_current_active_superuser(current_user: CurrentUser) -> User:
+# Dependency to get the superuser
+async def get_super_user(
+ credentials: Annotated[HTTPAuthorizationCredentials, Depends(bearer_scheme)],
+ session: SessionDep
+) -> UserBusiness:
+ current_user = await get_business_user(credentials, session)
if not current_user.is_superuser:
raise HTTPException(
- status_code=403, detail="The user doesn't have enough privileges"
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail="Not a superuser",
)
return current_user
+
+# Dependency to get any public user
+async def get_public_user(
+ credentials: Annotated[HTTPAuthorizationCredentials, Depends(bearer_scheme)],
+ session: SessionDep
+) -> UserPublic:
+ print('credentials.credentials ', credentials.credentials)
+ current_user = await get_current_user(credentials, session)
+ # print('current_user ', current_user)
+ if not isinstance(current_user, UserPublic):
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail="Not a public user",
+ )
+ return current_user
\ No newline at end of file
diff --git a/backend/app/api/main.py b/backend/app/api/main.py
index 09e0663fc3..19e3999739 100644
--- a/backend/app/api/main.py
+++ b/backend/app/api/main.py
@@ -1,9 +1,12 @@
from fastapi import APIRouter
-from app.api.routes import items, login, users, utils
+from app.api.routes import venues, menu, users, login, qrcode, carousel
+
api_router = APIRouter()
-api_router.include_router(login.router, tags=["login"])
+api_router.include_router(venues.router, prefix="/venues", tags=["venues"])
+api_router.include_router(menu.router, prefix="/menu", tags=["menu"])
api_router.include_router(users.router, prefix="/users", tags=["users"])
-api_router.include_router(utils.router, prefix="/utils", tags=["utils"])
-api_router.include_router(items.router, prefix="/items", tags=["items"])
+api_router.include_router(login.router, tags=["login"])
+api_router.include_router(qrcode.router, tags=["qrcode"])
+api_router.include_router(carousel.router, prefix="/carousel", tags=["carousel"])
diff --git a/backend/app/api/routes/carousel.py b/backend/app/api/routes/carousel.py
new file mode 100644
index 0000000000..d768939ba2
--- /dev/null
+++ b/backend/app/api/routes/carousel.py
@@ -0,0 +1,54 @@
+import uuid
+import h3
+from fastapi import APIRouter, Depends, Path
+from sqlmodel import select
+from typing import List
+from datetime import datetime, timezone
+from app.models.carousel_poster import CarouselPoster
+from app.schema.carousel_poster import CarouselPosterCreate, CarouselPosterRead
+from app.api.deps import SessionDep
+from app.utils import get_h3_index
+from app.crud import create_record, delete_record, update_record
+
+router = APIRouter()
+
+@router.get("/poster/", response_model=List[CarouselPoster])
+async def get_carousel_posters(latitude: float, longitude: float, session: SessionDep, radius: int = 3000):
+ user_h3_index = get_h3_index(latitude=latitude, longitude=longitude)
+
+ distance_in_km = radius / 1000
+ k_ring_size = int(distance_in_km / 1.2)
+
+ nearby_h3_indexes = h3.k_ring(user_h3_index, k_ring_size)
+
+ posters = session.execute(
+ select(CarouselPoster)
+ .where(CarouselPoster.h3_index.in_(nearby_h3_indexes))
+ # .where(CarouselPoster.expires_at > current_time)
+ ).scalars().all()
+
+ return posters
+
+@router.post("/poster/", response_model=CarouselPosterRead)
+async def create_carousel_poster(poster: CarouselPosterCreate, session: SessionDep):
+ h3_index = get_h3_index(latitude=poster.latitude, longitude=poster.longitude, resolution=9)
+ carousel_poster_obj = CarouselPoster(
+ **poster.model_dump(),
+ h3_index=h3_index
+ )
+
+ return create_record(session=session, model=CarouselPoster, obj_in=carousel_poster_obj)
+
+
+@router.put("/poster/{poster_id}", response_model=CarouselPosterRead)
+async def update_carousel_poster(
+ poster_id: uuid.UUID,
+ updated_data: CarouselPosterCreate,
+ session: SessionDep
+):
+ return update_record(session=session, record_id=poster_id, obj_in=updated_data, model=CarouselPoster)
+
+
+@router.delete("/poster/{poster_id}")
+async def delete_carousel_poster(poster_id: uuid.UUID, session: SessionDep):
+ return delete_record(session=session, model=CarouselPoster, record_id=poster_id)
\ No newline at end of file
diff --git a/backend/app/api/routes/items.py b/backend/app/api/routes/items.py
deleted file mode 100644
index 67196c2366..0000000000
--- a/backend/app/api/routes/items.py
+++ /dev/null
@@ -1,109 +0,0 @@
-import uuid
-from typing import Any
-
-from fastapi import APIRouter, HTTPException
-from sqlmodel import func, select
-
-from app.api.deps import CurrentUser, SessionDep
-from app.models import Item, ItemCreate, ItemPublic, ItemsPublic, ItemUpdate, Message
-
-router = APIRouter()
-
-
-@router.get("/", response_model=ItemsPublic)
-def read_items(
- session: SessionDep, current_user: CurrentUser, skip: int = 0, limit: int = 100
-) -> Any:
- """
- Retrieve items.
- """
-
- if current_user.is_superuser:
- count_statement = select(func.count()).select_from(Item)
- count = session.exec(count_statement).one()
- statement = select(Item).offset(skip).limit(limit)
- items = session.exec(statement).all()
- else:
- count_statement = (
- select(func.count())
- .select_from(Item)
- .where(Item.owner_id == current_user.id)
- )
- count = session.exec(count_statement).one()
- statement = (
- select(Item)
- .where(Item.owner_id == current_user.id)
- .offset(skip)
- .limit(limit)
- )
- items = session.exec(statement).all()
-
- return ItemsPublic(data=items, count=count)
-
-
-@router.get("/{id}", response_model=ItemPublic)
-def read_item(session: SessionDep, current_user: CurrentUser, id: uuid.UUID) -> Any:
- """
- Get item by ID.
- """
- item = session.get(Item, id)
- if not item:
- raise HTTPException(status_code=404, detail="Item not found")
- if not current_user.is_superuser and (item.owner_id != current_user.id):
- raise HTTPException(status_code=400, detail="Not enough permissions")
- return item
-
-
-@router.post("/", response_model=ItemPublic)
-def create_item(
- *, session: SessionDep, current_user: CurrentUser, item_in: ItemCreate
-) -> Any:
- """
- Create new item.
- """
- item = Item.model_validate(item_in, update={"owner_id": current_user.id})
- session.add(item)
- session.commit()
- session.refresh(item)
- return item
-
-
-@router.put("/{id}", response_model=ItemPublic)
-def update_item(
- *,
- session: SessionDep,
- current_user: CurrentUser,
- id: uuid.UUID,
- item_in: ItemUpdate,
-) -> Any:
- """
- Update an item.
- """
- item = session.get(Item, id)
- if not item:
- raise HTTPException(status_code=404, detail="Item not found")
- if not current_user.is_superuser and (item.owner_id != current_user.id):
- raise HTTPException(status_code=400, detail="Not enough permissions")
- update_dict = item_in.model_dump(exclude_unset=True)
- item.sqlmodel_update(update_dict)
- session.add(item)
- session.commit()
- session.refresh(item)
- return item
-
-
-@router.delete("/{id}")
-def delete_item(
- session: SessionDep, current_user: CurrentUser, id: uuid.UUID
-) -> Message:
- """
- Delete an item.
- """
- item = session.get(Item, id)
- if not item:
- raise HTTPException(status_code=404, detail="Item not found")
- if not current_user.is_superuser and (item.owner_id != current_user.id):
- raise HTTPException(status_code=400, detail="Not enough permissions")
- session.delete(item)
- session.commit()
- return Message(message="Item deleted successfully")
diff --git a/backend/app/api/routes/login.py b/backend/app/api/routes/login.py
index fe7e94d5c1..5fc9ae0fc7 100644
--- a/backend/app/api/routes/login.py
+++ b/backend/app/api/routes/login.py
@@ -1,124 +1,128 @@
-from datetime import timedelta
-from typing import Annotated, Any
-
-from fastapi import APIRouter, Depends, HTTPException
-from fastapi.responses import HTMLResponse
-from fastapi.security import OAuth2PasswordRequestForm
-
-from app import crud
-from app.api.deps import CurrentUser, SessionDep, get_current_active_superuser
-from app.core import security
+from typing import Annotated, Union
+from app.models.auth import RefreshTokenPayload, UserAuthResponse
+from fastapi import APIRouter, Depends, FastAPI, HTTPException
+import OTPLessAuthSDK
+from app.models.user import UserBusiness, UserPublic # Import your UserPublic model
+from app.api.deps import SessionDep, get_current_user
+from datetime import datetime, timedelta, timezone
+from app.core.security import create_access_token, create_refresh_token, get_jwt_payload # Adjust the import based on your structure
from app.core.config import settings
-from app.core.security import get_password_hash
-from app.models import Message, NewPassword, Token, UserPublic
-from app.utils import (
- generate_password_reset_token,
- generate_reset_password_email,
- send_email,
- verify_password_reset_token,
-)
+from app.models.auth import OtplessToken
+from fastapi.datastructures import QueryParams
router = APIRouter()
-@router.post("/login/access-token")
-def login_access_token(
- session: SessionDep, form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
-) -> Token:
- """
- OAuth2 compatible token login, get an access token for future requests
- """
- user = crud.authenticate(
- session=session, email=form_data.username, password=form_data.password
- )
- if not user:
- raise HTTPException(status_code=400, detail="Incorrect email or password")
- elif not user.is_active:
- raise HTTPException(status_code=400, detail="Inactive user")
- access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
- return Token(
- access_token=security.create_access_token(
- user.id, expires_delta=access_token_expires
+@router.post("/verify_token", response_model=UserAuthResponse)
+async def verify_token(request: OtplessToken, session: SessionDep):
+ try:
+ # Verify the token using OTPLess SDK
+ # Uncomment and implement token verification with OTPLess
+ # user_details = OTPLessAuthSDK.UserDetail.verify_token(
+ # request.otpless_token,
+ # settings.CLIENT_ID,
+ # settings.CLIENT_SECRET
+ # )
+
+ # Simulated user details for demonstration
+ phone_number = "8130181469" # Replace this with the actual phone number from the SDK response
+
+ # Check for the user by phone number
+ user = session.query(UserPublic).filter(UserPublic.phone_number == phone_number).first()
+
+ if not user:
+ # Create a new user if not found
+ user = UserPublic(
+ phone_number=phone_number,
+ is_active=True,
+ registration_date=datetime.now(timezone.utc),
+ )
+ session.add(user)
+ session.commit()
+ session.refresh(user)
+
+ # Create tokens
+ access_token = create_access_token(subject=str(user.id), expires_delta=timedelta(minutes=30))
+ refresh_token = create_refresh_token(subject=str(user.id))
+
+ # Store the new refresh token in the user's record
+ user.refresh_token = refresh_token.token
+ session.add(user) # Add the updated user to the session
+ session.commit() # Commit the changes to the database
+
+ return UserAuthResponse(
+ access_token=access_token,
+ refresh_token=refresh_token,
+ issued_at=datetime.now(timezone.utc)
)
- )
+ except Exception as e:
+ raise HTTPException(status_code=400, detail=str(e))
+
+
+@router.post("/refresh_token", response_model=UserAuthResponse)
+async def refresh_token(request: RefreshTokenPayload, session: SessionDep):
+ try:
+ # Decode and validate the refresh token payload
+ payload = get_jwt_payload(request.refresh_token)
+
+ # Extract the user ID (sub) from the payload
+ user_id = payload.sub
+
+ # Fetch the user from the database using the user ID
+ user = (
+ session.query(UserPublic)
+ .filter(UserPublic.id == user_id)
+ .first()
+ ) or (
+ session.query(UserBusiness)
+ .filter(UserBusiness.id == user_id)
+ .first()
+ )
+
+ if not user:
+ raise HTTPException(status_code=404, detail="User not found")
+
+ # Verify if the refresh token in the database matches the provided token
+ if user.refresh_token != request.refresh_token:
+ raise HTTPException(status_code=401, detail="Invalid refresh token")
+
+ # Check if the token has expired
+ current_time = datetime.now(timezone.utc)
+ if payload.exp and datetime.fromtimestamp(payload.exp, timezone.utc) < current_time:
+ raise HTTPException(status_code=401, detail="Refresh token expired")
+
+ # If valid, generate new tokens
+ new_access_token = create_access_token(subject=user_id, expires_delta=timedelta(minutes=30))
+ new_refresh_token = create_refresh_token(subject=user_id)
+
+ # Update the user's refresh token in the database
+ user.refresh_token = new_refresh_token.token
+ session.add(user)
+ session.commit()
+
+ # Return the new tokens and issue time
+ return UserAuthResponse(
+ access_token=new_access_token,
+ refresh_token=new_refresh_token,
+ issued_at=current_time
+ )
-@router.post("/login/test-token", response_model=UserPublic)
-def test_token(current_user: CurrentUser) -> Any:
- """
- Test access token
- """
- return current_user
+ except Exception as e:
+ raise HTTPException(status_code=400, detail=str(e))
+@router.get("/logout")
+async def logout(
+ session: SessionDep,
+ current_user: Annotated[Union[UserPublic, UserBusiness], Depends(get_current_user)]):
+ try:
+ # Invalidate the refresh token by setting it to None or an empty string
+ current_user.refresh_token = None
+ session.add(current_user)
+ session.commit()
-@router.post("/password-recovery/{email}")
-def recover_password(email: str, session: SessionDep) -> Message:
- """
- Password Recovery
- """
- user = crud.get_user_by_email(session=session, email=email)
+ return {"message": "Logout successful, refresh token invalidated"}
- if not user:
- raise HTTPException(
- status_code=404,
- detail="The user with this email does not exist in the system.",
- )
- password_reset_token = generate_password_reset_token(email=email)
- email_data = generate_reset_password_email(
- email_to=user.email, email=email, token=password_reset_token
- )
- send_email(
- email_to=user.email,
- subject=email_data.subject,
- html_content=email_data.html_content,
- )
- return Message(message="Password recovery email sent")
-
-
-@router.post("/reset-password/")
-def reset_password(session: SessionDep, body: NewPassword) -> Message:
- """
- Reset password
- """
- email = verify_password_reset_token(token=body.token)
- if not email:
- raise HTTPException(status_code=400, detail="Invalid token")
- user = crud.get_user_by_email(session=session, email=email)
- if not user:
- raise HTTPException(
- status_code=404,
- detail="The user with this email does not exist in the system.",
- )
- elif not user.is_active:
- raise HTTPException(status_code=400, detail="Inactive user")
- hashed_password = get_password_hash(password=body.new_password)
- user.hashed_password = hashed_password
- session.add(user)
- session.commit()
- return Message(message="Password updated successfully")
-
-
-@router.post(
- "/password-recovery-html-content/{email}",
- dependencies=[Depends(get_current_active_superuser)],
- response_class=HTMLResponse,
-)
-def recover_password_html_content(email: str, session: SessionDep) -> Any:
- """
- HTML Content for Password Recovery
- """
- user = crud.get_user_by_email(session=session, email=email)
-
- if not user:
- raise HTTPException(
- status_code=404,
- detail="The user with this username does not exist in the system.",
- )
- password_reset_token = generate_password_reset_token(email=email)
- email_data = generate_reset_password_email(
- email_to=user.email, email=email, token=password_reset_token
- )
-
- return HTMLResponse(
- content=email_data.html_content, headers={"subject:": email_data.subject}
- )
+ except Exception as e:
+ raise HTTPException(status_code=400, detail=str(e))
+
\ No newline at end of file
diff --git a/backend/app/api/routes/menu.py b/backend/app/api/routes/menu.py
new file mode 100644
index 0000000000..3be858f6c3
--- /dev/null
+++ b/backend/app/api/routes/menu.py
@@ -0,0 +1,211 @@
+import uuid
+from app.schema.menu import MenuCategoryRead, MenuItemRead, NightclubMenuCreate, NightclubMenuRead, MenuCategoryCreate, MenuItemCreate, QSRMenuCreate, QSRMenuRead, RestaurantMenuCreate, RestaurantMenuRead
+from app.models.menu import NightclubMenu, QSRMenu, RestaurantMenu
+from app.models.menu_category import MenuCategory
+from app.models.menu_item import MenuItem
+from sqlmodel import select
+from fastapi import APIRouter
+from typing import List
+from app.api.deps import SessionDep
+from app.crud import (
+ get_record_by_id,
+ create_record,
+ update_record,
+ patch_record,
+ delete_record
+)
+
+router = APIRouter()
+
+# Get all menus for a nightclub
+@router.get("/nightclubs/{nightclub_id}/menus/", response_model=List[NightclubMenuRead])
+async def read_nightclub_menus(nightclub_id: uuid.UUID, session: SessionDep):
+ """
+ Retrieve all menus for a specific nightclub.
+ """
+ menus = session.exec(select(NightclubMenu).where(NightclubMenu.nightclub_id == nightclub_id)).all()
+ return menus
+
+# Get a specific menu
+@router.get("/nightclubs/menus/{menu_id}", response_model=NightclubMenuRead)
+async def read_nightclub_menu(menu_id: uuid.UUID, session: SessionDep):
+ """
+ Retrieve a specific menu by ID for a nightclub.
+ """
+ return get_record_by_id(session, NightclubMenu, menu_id)
+
+# Create a new menu
+@router.post("/nightclubs/menus/", response_model=NightclubMenuRead)
+async def create_nightclub_menu( menu: NightclubMenuCreate, session: SessionDep):
+ """
+ Create a new menu for a nightclub.
+ """
+ return create_record(session, NightclubMenu, menu)
+
+# Update a menu
+@router.put("/nightclubs/menus/{menu_id}", response_model=NightclubMenuRead)
+async def update_nightclub_menu(menu_id: uuid.UUID, updated_menu: NightclubMenuCreate, session: SessionDep):
+ """
+ Update an existing menu for a nightclub.
+ """
+ return update_record(session, NightclubMenu, menu_id, updated_menu)
+
+# PATCH a menu for partial updates
+@router.patch("/nightclubs/menus/{menu_id}", response_model=NightclubMenuRead)
+async def patch_nightclub_menu(menu_id: uuid.UUID, updated_menu: NightclubMenuCreate, session: SessionDep):
+ """
+ Partially update an existing menu for a venue (Nightclub, Restaurant, QSR).
+ """
+ return patch_record(session, NightclubMenu, menu_id, updated_menu)
+
+# Delete a menu
+@router.delete("/nightclubs/menus/{menu_id}", response_model=None)
+async def delete_nightclub_menu(menu_id: uuid.UUID, session: SessionDep):
+ """
+ Delete a menu by ID for a nightclub.
+ """
+ return delete_record(session, NightclubMenu, menu_id)
+
+# Get all menus for a qsr
+@router.get("/qsrs/{qsr_id}/menus/", response_model=List[QSRMenuRead])
+async def read_qsr_menus(qsr_id: uuid.UUID, session: SessionDep):
+ """
+ Retrieve all menus for a specific qsr.
+ """
+ menus = session.exec(select(QSRMenu).where(QSRMenu.qsr_id == qsr_id)).all()
+ return menus
+
+# Get a specific menu
+@router.get("/qsrs/menus/{menu_id}", response_model=QSRMenuRead)
+async def read_qsr_menu(menu_id: uuid.UUID, session: SessionDep):
+ """
+ Retrieve a specific menu by ID for a qsr.
+ """
+ return get_record_by_id(session, QSRMenu, menu_id)
+
+# Create a new menu
+@router.post("/qsrs/menus/", response_model=QSRMenuRead)
+async def create_qsr_menu( menu: QSRMenuCreate, session: SessionDep):
+ """
+ Create a new menu for a qsr.
+ """
+ return create_record(session, QSRMenu, menu)
+
+# Update a menu
+@router.put("/qsrs/menus/{menu_id}", response_model=QSRMenuRead)
+async def update_qsr_menu(menu_id: uuid.UUID, updated_menu: QSRMenuCreate, session: SessionDep):
+ """
+ Update an existing menu for a qsr.
+ """
+ return update_record(session, QSRMenu, menu_id, updated_menu)
+
+# PATCH a menu for partial updates
+@router.patch("/qsrs/menus/{menu_id}", response_model=QSRMenuRead)
+async def patch_qsr_menu(menu_id: uuid.UUID, updated_menu: QSRMenuCreate, session: SessionDep):
+ """
+ Partially update an existing menu for a venue (QSR, Restaurant, QSR).
+ """
+ return patch_record(session, QSRMenu, menu_id, updated_menu)
+
+# Delete a menu
+@router.delete("/qsrs/menus/{menu_id}", response_model=None)
+async def delete_qsr_menu(menu_id: uuid.UUID, session: SessionDep):
+ """
+ Delete a menu by ID for a qsr.
+ """
+ return delete_record(session, QSRMenu, menu_id)
+
+# Get all menus for a restaurant
+@router.get("/restaurants/{restaurant_id}/menus/", response_model=List[RestaurantMenuRead])
+async def read_restaurant_menus(restaurant_id: uuid.UUID, session: SessionDep):
+ """
+ Retrieve all menus for a specific restaurant.
+ """
+ menus = session.exec(select(RestaurantMenu).where(RestaurantMenu.restaurant_id == restaurant_id)).all()
+ return menus
+
+# Get a specific menu
+@router.get("/restaurants/menus/{menu_id}", response_model=RestaurantMenuRead)
+async def read_restaurant_menu(menu_id: uuid.UUID, session: SessionDep):
+ """
+ Retrieve a specific menu by ID for a restaurant.
+ """
+ return get_record_by_id(session, RestaurantMenu, menu_id)
+
+# Create a new menu
+@router.post("/restaurants/menus/", response_model=RestaurantMenuRead)
+async def create_restaurant_menu( menu: RestaurantMenuCreate, session: SessionDep):
+ """
+ Create a new menu for a restaurant.
+ """
+ return create_record(session, RestaurantMenu, menu)
+
+# Update a menu
+@router.put("/restaurants/menus/{menu_id}", response_model=RestaurantMenuRead)
+async def update_restaurant_menu(menu_id: uuid.UUID, updated_menu: RestaurantMenuCreate, session: SessionDep):
+ """
+ Update an existing menu for a restaurant.
+ """
+ return update_record(session, RestaurantMenu, menu_id, updated_menu)
+
+# PATCH a menu for partial updates
+@router.patch("/restaurants/menus/{menu_id}", response_model=RestaurantMenuRead)
+async def patch_restaurant_menu(menu_id: uuid.UUID, updated_menu: RestaurantMenuCreate, session: SessionDep):
+ """
+ Partially update an existing menu for a venue (Restaurant, Restaurant, QSR).
+ """
+ return patch_record(session, RestaurantMenu, menu_id, updated_menu)
+
+# Delete a menu
+@router.delete("/restaurants/menus/{menu_id}", response_model=None)
+async def delete_restaurant_menu(menu_id: uuid.UUID, session: SessionDep):
+ """
+ Delete a menu by ID for a restaurant.
+ """
+ return delete_record(session, RestaurantMenu, menu_id)
+
+# CRUD operations for Menu Categories
+
+# Create a new category
+@router.post("/nightclubs/menus/categories/", response_model=MenuCategoryRead)
+async def create_menu_category(category: MenuCategoryCreate, session: SessionDep):
+ return create_record(session, MenuCategory, category)
+
+# Update a category
+@router.put("/nightclubs/menus/categories/{category_id}", response_model=MenuCategoryRead)
+async def update_menu_category(category_id: uuid.UUID, updated_category: MenuCategoryCreate, session: SessionDep):
+ """
+ Update an existing category for a specific menu.
+ """
+ return update_record(session, MenuCategory, category_id, updated_category)
+
+# Delete a category
+@router.delete("/nightclubs/menus/categories/{category_id}", response_model=None)
+async def delete_menu_category(category_id: uuid.UUID, session: SessionDep):
+ """
+ Delete a category by ID from a specific menu.
+ """
+ return delete_record(session, MenuCategory, category_id)
+
+# CRUD operations for Menu Items
+
+# Create a new item
+@router.post("/nightclubs/menus/categories/items/", response_model=MenuItemRead)
+async def create_menu_item(item: MenuItemCreate, session: SessionDep):
+ return create_record(session, MenuItem, item)
+
+# Update an item
+@router.put("/nightclubs/menus/categories/items/{item_id}", response_model=MenuItemRead)
+async def update_menu_item(item_id: uuid.UUID, updated_item: MenuItemCreate, session: SessionDep):
+ """
+ Update an existing item under a specific category of a menu.
+ """
+ return update_record(session, MenuItem, item_id, updated_item)
+
+# Delete an item
+@router.delete("/nightclubs/menus/categories/items/{item_id}", response_model=None)
+async def delete_menu_item(item_id: uuid.UUID, session: SessionDep):
+ """
+ Delete an item by ID from a specific category of a menu.
+ """
+ return delete_record(session, MenuItem, item_id)
\ No newline at end of file
diff --git a/backend/app/api/routes/qrcode.py b/backend/app/api/routes/qrcode.py
new file mode 100644
index 0000000000..cd02362b4b
--- /dev/null
+++ b/backend/app/api/routes/qrcode.py
@@ -0,0 +1,112 @@
+from pathlib import Path
+import uuid
+from fastapi import APIRouter, Depends, HTTPException, Request
+from fastapi.responses import HTMLResponse, RedirectResponse
+from fastapi.templating import Jinja2Templates
+from jinja2 import Template
+from sqlalchemy import UUID
+from sqlmodel import select
+from typing import List
+from app.api.deps import SessionDep
+from app.models.qrcode import QRCode # Ensure you have this import for your model
+from app.schema.qrcode import QRCodeCreate, QRCodeRead # Ensure you have these imports for your schemas
+from app.crud import (
+ get_all_records,
+ get_record_by_id,
+ create_record,
+ update_record,
+ patch_record,
+ delete_record
+)
+
+router = APIRouter()
+
+# Get all QR codes
+@router.get("/qr_codes/", response_model=List[QRCodeRead])
+async def read_qr_codes(session: SessionDep):
+ # Retrieve all QR codes
+ return get_all_records(session, QRCode)
+
+# Get a specific QR code
+@router.get("/qr_codes/{qr_code_id}", response_model=QRCodeRead)
+async def read_qr_code(qr_code_id: uuid.UUID, session: SessionDep):
+ """
+ Retrieve a specific QR code by ID.
+ """
+ return get_record_by_id(session, QRCode, qr_code_id)
+
+# Create a new QR code
+@router.post("/qr_codes/", response_model=QRCodeRead)
+async def create_qr_code(qr_code: QRCodeCreate, session: SessionDep):
+ """
+ Create a new QR code.
+ """
+ return create_record(session, QRCode, qr_code)
+
+# Update a QR code
+@router.put("/qr_codes/{qr_code_id}", response_model=QRCodeRead)
+async def update_qr_code(qr_code_id: uuid.UUID, updated_qr_code: QRCodeCreate, session: SessionDep):
+ """
+ Update an existing QR code.
+ """
+ return update_record(session, QRCode, qr_code_id, updated_qr_code)
+
+# PATCH a QR code for partial updates
+@router.patch("/qr_codes/{qr_code_id}", response_model=QRCodeRead)
+async def patch_qr_code(qr_code_id: uuid.UUID, updated_qr_code: QRCodeCreate, session: SessionDep):
+ """
+ Partially update an existing QR code.
+ """
+ return patch_record(session, QRCode, qr_code_id, updated_qr_code)
+
+# Delete a QR code
+@router.delete("/qr_codes/{qr_code_id}", response_model=None)
+async def delete_qr_code(qr_code_id: uuid.UUID, session: SessionDep):
+ """
+ Delete a QR code by ID.
+ """
+ return delete_record(session, QRCode, qr_code_id)
+
+@router.get("/scan/{qr_id}", response_class=HTMLResponse)
+async def scan_qr_code(qr_id: uuid.UUID, session: SessionDep):
+ """
+ Scan a QR code to determine its associated venue and redirect appropriately.
+ """
+ # Retrieve the QR code from the database
+ qr_code_result = session.execute(select(QRCode).where(QRCode.id == qr_id)).one_or_none()
+
+ if not qr_code_result:
+ raise HTTPException(status_code=404, detail="QR code not found.")
+
+ qr_code = qr_code_result[0]
+ # Determine the venue type and ID from the QR code
+ venue_type, venue_id = None, None
+
+ if qr_code.foodcourt_id:
+ venue_type = "foodcourt"
+ venue_id = qr_code.foodcourt_id
+ elif qr_code.qsr_id:
+ venue_type = "qsr"
+ venue_id = qr_code.qsr_id
+ elif qr_code.nightclub_id:
+ venue_type = "nightclub"
+ venue_id = qr_code.nightclub_id
+ elif qr_code.restaurant_id:
+ venue_type = "restaurant"
+ venue_id = qr_code.restaurant_id
+
+ if not venue_type or not venue_id:
+ raise HTTPException(status_code=400, detail="No associated venue found.")
+
+ # Load the landing page HTML template
+ template_path = Path(__file__).parent.parent.parent / "static" / "landing_page.html"
+ print('template_path:', template_path)
+ try:
+ template_str = template_path.read_text()
+ except FileNotFoundError:
+ raise HTTPException(status_code=500, detail="Landing page template not found.")
+
+ # Use string.Template to replace placeholders in the HTML
+ template = Template(template_str)
+ html_content = template.render(venueId=venue_id, venueType=venue_type)
+ return HTMLResponse(content=html_content)
\ No newline at end of file
diff --git a/backend/app/api/routes/users.py b/backend/app/api/routes/users.py
index c636b094ee..b41f6f6a77 100644
--- a/backend/app/api/routes/users.py
+++ b/backend/app/api/routes/users.py
@@ -1,228 +1,148 @@
+from typing import List, Union
import uuid
-from typing import Any
-
-from fastapi import APIRouter, Depends, HTTPException
-from sqlmodel import col, delete, func, select
-
-from app import crud
-from app.api.deps import (
- CurrentUser,
- SessionDep,
- get_current_active_superuser,
-)
-from app.core.config import settings
-from app.core.security import get_password_hash, verify_password
-from app.models import (
- Item,
- Message,
- UpdatePassword,
- User,
- UserCreate,
- UserPublic,
- UserRegister,
- UsersPublic,
- UserUpdate,
- UserUpdateMe,
-)
-from app.utils import generate_new_account_email, send_email
+from fastapi import APIRouter, Query, HTTPException, Depends
+from app.api.deps import SessionDep, get_business_user, get_current_user, get_public_user, get_super_user
+from app.models import UserBusiness, UserPublic
+from app.crud import get_all_records, get_record_by_id, create_record, update_record, delete_record, patch_record
router = APIRouter()
-
-@router.get(
- "/",
- dependencies=[Depends(get_current_active_superuser)],
- response_model=UsersPublic,
-)
-def read_users(session: SessionDep, skip: int = 0, limit: int = 100) -> Any:
+@router.get("/user-businesses/", response_model=List[UserBusiness])
+async def read_user_businesses(
+ session: SessionDep,
+ skip: int = Query(0, alias="page", ge=0),
+ limit: int = Query(10, le=100),
+ current_user: UserBusiness = Depends(get_super_user)
+):
"""
- Retrieve users.
+ Retrieve a paginated list of user businesses.
+ - **skip**: The page number (starting from 0)
+ - **limit**: The number of items per page
"""
+ return get_all_records(session, UserBusiness, skip=skip, limit=limit)
- count_statement = select(func.count()).select_from(User)
- count = session.exec(count_statement).one()
-
- statement = select(User).offset(skip).limit(limit)
- users = session.exec(statement).all()
-
- return UsersPublic(data=users, count=count)
-
-
-@router.post(
- "/", dependencies=[Depends(get_current_active_superuser)], response_model=UserPublic
-)
-def create_user(*, session: SessionDep, user_in: UserCreate) -> Any:
- """
- Create new user.
- """
- user = crud.get_user_by_email(session=session, email=user_in.email)
- if user:
- raise HTTPException(
- status_code=400,
- detail="The user with this email already exists in the system.",
- )
-
- user = crud.create_user(session=session, user_create=user_in)
- if settings.emails_enabled and user_in.email:
- email_data = generate_new_account_email(
- email_to=user_in.email, username=user_in.email, password=user_in.password
- )
- send_email(
- email_to=user_in.email,
- subject=email_data.subject,
- html_content=email_data.html_content,
- )
- return user
-
-
-@router.patch("/me", response_model=UserPublic)
-def update_user_me(
- *, session: SessionDep, user_in: UserUpdateMe, current_user: CurrentUser
-) -> Any:
+@router.get("/user-businesses/{user_business_id}", response_model=UserBusiness)
+async def read_user_business(
+ user_business_id: uuid.UUID,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_super_user)
+):
"""
- Update own user.
+ Retrieve a single user business by ID.
+ - **user_business_id**: The ID of the user business to retrieve
"""
+ return get_record_by_id(session, UserBusiness, user_business_id)
- if user_in.email:
- existing_user = crud.get_user_by_email(session=session, email=user_in.email)
- if existing_user and existing_user.id != current_user.id:
- raise HTTPException(
- status_code=409, detail="User with this email already exists"
- )
- user_data = user_in.model_dump(exclude_unset=True)
- current_user.sqlmodel_update(user_data)
- session.add(current_user)
- session.commit()
- session.refresh(current_user)
- return current_user
-
-
-@router.patch("/me/password", response_model=Message)
-def update_password_me(
- *, session: SessionDep, body: UpdatePassword, current_user: CurrentUser
-) -> Any:
- """
- Update own password.
- """
- if not verify_password(body.current_password, current_user.hashed_password):
- raise HTTPException(status_code=400, detail="Incorrect password")
- if body.current_password == body.new_password:
- raise HTTPException(
- status_code=400, detail="New password cannot be the same as the current one"
- )
- hashed_password = get_password_hash(body.new_password)
- current_user.hashed_password = hashed_password
- session.add(current_user)
- session.commit()
- return Message(message="Password updated successfully")
-
-
-@router.get("/me", response_model=UserPublic)
-def read_user_me(current_user: CurrentUser) -> Any:
+@router.get("/me/user-businesses/{user_business_id}", response_model=UserBusiness)
+async def read_user_business_me(
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_super_user)
+):
"""
- Get current user.
+ Retrieve a single user business by ID.
+ - **user_business_id**: The ID of the user business to retrieve
"""
- return current_user
-
-
-@router.delete("/me", response_model=Message)
-def delete_user_me(session: SessionDep, current_user: CurrentUser) -> Any:
- """
- Delete own user.
- """
- if current_user.is_superuser:
- raise HTTPException(
- status_code=403, detail="Super users are not allowed to delete themselves"
- )
- statement = delete(Item).where(col(Item.owner_id) == current_user.id)
- session.exec(statement) # type: ignore
- session.delete(current_user)
- session.commit()
- return Message(message="User deleted successfully")
+ return get_record_by_id(session, UserBusiness, current_user.id)
-@router.post("/signup", response_model=UserPublic)
-def register_user(session: SessionDep, user_in: UserRegister) -> Any:
- """
- Create new user without the need to be logged in.
- """
- user = crud.get_user_by_email(session=session, email=user_in.email)
- if user:
- raise HTTPException(
- status_code=400,
- detail="The user with this email already exists in the system",
- )
- user_create = UserCreate.model_validate(user_in)
- user = crud.create_user(session=session, user_create=user_create)
- return user
-
+@router.post("/user-businesses/", response_model=UserBusiness)
+async def create_user_business(
+ user_business: UserBusiness,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_super_user)
+):
+ """
+ Create a new user business.
+ - **user_business**: The user business data to create
+ """
+ return create_record(session, UserBusiness, user_business)
-@router.get("/{user_id}", response_model=UserPublic)
-def read_user_by_id(
- user_id: uuid.UUID, session: SessionDep, current_user: CurrentUser
-) -> Any:
- """
- Get a specific user by id.
- """
- user = session.get(User, user_id)
- if user == current_user:
- return user
- if not current_user.is_superuser:
- raise HTTPException(
- status_code=403,
- detail="The user doesn't have enough privileges",
- )
- return user
+@router.put("/user-businesses/{user_business_id}", response_model=UserBusiness)
+async def update_user_business(
+ user_business: UserBusiness,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_current_user)
+):
+ """
+ Update an existing user business.
+ - **user_business_id**: The ID of the user business to update
+ - **user_business**: The updated user business data
+ """
+ return update_record(session, UserBusiness, current_user.id, user_business)
+@router.delete("/user-businesses/{user_business_id}", response_model=UserBusiness)
+async def delete_user_business(
+ user_business_id: uuid.UUID,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_super_user)
+):
+ """
+ Delete a user business by ID.
+ - **user_business_id**: The ID of the user business to delete
+ """
+ delete_record(session, UserBusiness, user_business_id)
+ return {"message": f"UserBusiness with ID {user_business_id} has been deleted."}
-@router.patch(
- "/{user_id}",
- dependencies=[Depends(get_current_active_superuser)],
- response_model=UserPublic,
-)
-def update_user(
- *,
+@router.get("/user-public/", response_model=List[UserPublic])
+async def read_user_public(
session: SessionDep,
- user_id: uuid.UUID,
- user_in: UserUpdate,
-) -> Any:
+ skip: int = Query(0, alias="page", ge=0),
+ limit: int = Query(10, le=100),
+ current_user: UserBusiness = Depends(get_business_user)
+):
"""
- Update a user.
+ Retrieve a paginated list of user public.
+ - **skip**: The page number (starting from 0)
+ - **limit**: The number of items per page
"""
+ return get_all_records(session, UserPublic, skip=skip, limit=limit)
- db_user = session.get(User, user_id)
- if not db_user:
- raise HTTPException(
- status_code=404,
- detail="The user with this id does not exist in the system",
- )
- if user_in.email:
- existing_user = crud.get_user_by_email(session=session, email=user_in.email)
- if existing_user and existing_user.id != user_id:
- raise HTTPException(
- status_code=409, detail="User with this email already exists"
- )
+@router.get("/user-public/{user_public_id}", response_model=UserPublic)
+async def read_user_public(
+ user_public_id: uuid.UUID,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_business_user)
+):
+ """
+ Retrieve a single user public by ID.
+ - **user_public_id**: The ID of the user public to retrieve
+ """
+ return get_record_by_id(session, UserPublic, user_public_id)
- db_user = crud.update_user(session=session, db_user=db_user, user_in=user_in)
- return db_user
+@router.get("/me/user-public/", response_model=UserPublic)
+async def read_user_public_me(
+ session: SessionDep,
+ current_user: UserPublic = Depends(get_public_user)
+):
+ print("current_user : ",current_user)
+ """
+ Retrieve a single user public by ID.
+ - **user_public_id**: The ID of the user public to retrieve
+ """
+ return get_record_by_id(session, UserPublic, current_user.id)
+@router.put("/me/user-public/", response_model=UserPublic)
+async def update_user_public_me(
+ user_public: UserPublic,
+ session: SessionDep,
+ current_user: UserPublic = Depends(get_public_user)
+):
+ """
+ Update an existing user public.
+ - **user_public_id**: The ID of the user public to update
+ - **user_public**: The updated user public data
+ """
+ return update_record(session, UserPublic, current_user.id , user_public)
-@router.delete("/{user_id}", dependencies=[Depends(get_current_active_superuser)])
-def delete_user(
- session: SessionDep, current_user: CurrentUser, user_id: uuid.UUID
-) -> Message:
- """
- Delete a user.
- """
- user = session.get(User, user_id)
- if not user:
- raise HTTPException(status_code=404, detail="User not found")
- if user == current_user:
- raise HTTPException(
- status_code=403, detail="Super users are not allowed to delete themselves"
- )
- statement = delete(Item).where(col(Item.owner_id) == user_id)
- session.exec(statement) # type: ignore
- session.delete(user)
- session.commit()
- return Message(message="User deleted successfully")
+@router.delete("/user-public/{user_public_id}", response_model=UserPublic)
+async def delete_user_public(
+ user_public_id: uuid.UUID,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_super_user)
+):
+ """
+ Delete a user public by ID.
+ - **user_public_id**: The ID of the user public to delete
+ """
+ delete_record(session, UserPublic, user_public_id)
+ return {"message": f"UserPublic with ID {user_public_id} has been deleted."}
\ No newline at end of file
diff --git a/backend/app/api/routes/utils.py b/backend/app/api/routes/utils.py
index 82f6d2b821..e69de29bb2 100644
--- a/backend/app/api/routes/utils.py
+++ b/backend/app/api/routes/utils.py
@@ -1,26 +0,0 @@
-from fastapi import APIRouter, Depends
-from pydantic.networks import EmailStr
-
-from app.api.deps import get_current_active_superuser
-from app.models import Message
-from app.utils import generate_test_email, send_email
-
-router = APIRouter()
-
-
-@router.post(
- "/test-email/",
- dependencies=[Depends(get_current_active_superuser)],
- status_code=201,
-)
-def test_email(email_to: EmailStr) -> Message:
- """
- Test emails.
- """
- email_data = generate_test_email(email_to=email_to)
- send_email(
- email_to=email_to,
- subject=email_data.subject,
- html_content=email_data.html_content,
- )
- return Message(message="Test email sent")
diff --git a/backend/app/api/routes/venues.py b/backend/app/api/routes/venues.py
new file mode 100644
index 0000000000..2709baa4c8
--- /dev/null
+++ b/backend/app/api/routes/venues.py
@@ -0,0 +1,217 @@
+import uuid
+from app.schema.venue import FoodcourtCreate, FoodcourtRead, NightclubCreate, NightclubRead, QSRCreate, QSRRead, RestaurantCreate, RestaurantRead
+from app.models.user import UserBusiness, UserPublic
+from fastapi import APIRouter, Depends, HTTPException, Query
+from typing import List, Union
+
+from app.models.venue import Nightclub, Restaurant, QSR, Foodcourt
+from app.api.deps import SessionDep, get_business_user, get_current_user, get_super_user
+from app.crud import (
+ get_all_records,
+ get_record_by_id,
+ create_record,
+ update_record,
+ delete_record
+)
+
+router = APIRouter()
+
+# CRUD operations for Nightclubs
+
+@router.get("/nightclubs/", response_model=List[NightclubRead])
+async def read_nightclubs(
+ session: SessionDep,
+ skip: int = Query(0, alias="page", ge=0),
+ limit: int = Query(10, le=100),
+ current_user: Union[UserPublic, UserBusiness] = Depends(get_current_user)
+):
+ """
+ Retrieve a paginated list of nightclubs.
+ - **skip**: The page number (starting from 0)
+ - **limit**: The number of items per page
+ """
+ nightclubs = get_all_records(session, Nightclub, skip=skip, limit=limit)
+ return nightclubs
+
+@router.get("/nightclubs/{venue_id}", response_model=NightclubRead)
+async def read_nightclub(
+ venue_id: uuid.UUID, session: SessionDep,
+ current_user: Union[UserPublic, UserBusiness] = Depends(get_current_user)
+):
+ nightclub = get_record_by_id(session, Nightclub, venue_id)
+ if not nightclub:
+ raise HTTPException(status_code=404, detail="Nightclub not found")
+ return nightclub
+
+@router.post("/nightclubs/", response_model=NightclubRead)
+async def create_nightclub(
+ nightclub: NightclubCreate,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_business_user)
+):
+ return create_record(session, Nightclub, nightclub)
+
+@router.put("/nightclubs/{venue_id}", response_model=Nightclub)
+async def update_nightclub(
+ venue_id: uuid.UUID,
+ updated_nightclub: NightclubCreate,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_business_user)
+ ):
+ return update_record(session, Nightclub, venue_id, updated_nightclub)
+
+@router.delete("/nightclubs/{venue_id}", response_model=None)
+async def delete_nightclub(
+ venue_id: uuid.UUID,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_super_user)
+):
+ return delete_record(session, Nightclub, venue_id)
+
+@router.get("/restaurants/", response_model=List[RestaurantRead])
+async def read_restaurants(
+ session: SessionDep,
+ skip: int = Query(0, alias="page", ge=0),
+ limit: int = Query(10, le=100),
+ current_user: Union[UserPublic, UserBusiness] = Depends(get_current_user)
+):
+ """
+ Retrieve a paginated list of restaurants.
+ - **skip**: The page number (starting from 0)
+ - **limit**: The number of items per page
+ """
+ restaurants = get_all_records(session, Restaurant, skip=skip, limit=limit)
+ return restaurants
+
+@router.get("/restaurants/{venue_id}", response_model=RestaurantRead)
+async def read_restaurant(
+ venue_id: uuid.UUID, session: SessionDep,
+ current_user: Union[UserPublic, UserBusiness] = Depends(get_current_user)):
+ restaurant = get_record_by_id(session, Restaurant, venue_id)
+ if not restaurant:
+ raise HTTPException(status_code=404, detail="restaurant not found")
+ return restaurant
+
+@router.post("/restaurants/", response_model=RestaurantRead)
+async def create_restaurant(
+ restaurant: RestaurantCreate,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_business_user)
+):
+ return create_record(session, Restaurant, restaurant)
+
+@router.put("/restaurants/{venue_id}", response_model=Restaurant)
+async def update_restaurant(
+ venue_id: uuid.UUID,
+ updated_restaurant: RestaurantCreate,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_business_user)
+ ):
+ return update_record(session, Restaurant, venue_id, updated_restaurant)
+
+@router.delete("/restaurants/{venue_id}", response_model=None)
+async def delete_restaurant(
+ venue_id: uuid.UUID,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_super_user)
+):
+ return delete_record(session, Restaurant, venue_id)
+
+@router.get("/qsrs/", response_model=List[QSRRead])
+async def read_qsrs(
+ session: SessionDep,
+ skip: int = Query(0, alias="page", ge=0),
+ limit: int = Query(10, le=100),
+ current_user: Union[UserPublic, UserBusiness] = Depends(get_current_user)
+):
+ """
+ Retrieve a paginated list of qsrs.
+ - **skip**: The page number (starting from 0)
+ - **limit**: The number of items per page
+ """
+ qsrs = get_all_records(session, QSR, skip=skip, limit=limit)
+ return qsrs
+
+@router.get("/qsrs/{venue_id}", response_model=QSRRead)
+async def read_qsr(
+ venue_id: uuid.UUID, session: SessionDep ,
+ current_user: Union[UserPublic, UserBusiness] = Depends(get_current_user)):
+ qsr = get_record_by_id(session, QSR, venue_id)
+ if not qsr:
+ raise HTTPException(status_code=404, detail="QSR not found")
+ return qsr
+
+@router.post("/qsrs/", response_model=QSRRead)
+async def create_qsr(
+ qsr: QSRCreate,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_business_user)
+):
+ return create_record(session, QSR, qsr)
+
+@router.put("/qsrs/{venue_id}", response_model=QSR)
+async def update_qsr(
+ venue_id: uuid.UUID,
+ updated_qsr: QSRCreate,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_business_user)
+ ):
+ return update_record(session, QSR, venue_id, updated_qsr)
+
+@router.delete("/qsrs/{venue_id}", response_model=None)
+async def delete_qsr(
+ venue_id: uuid.UUID,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_super_user)
+):
+ return delete_record(session, QSR, venue_id)
+
+@router.get("/foodcourts/", response_model=List[FoodcourtRead])
+async def read_foodcourts(
+ session: SessionDep,
+ skip: int = Query(0, alias="page", ge=0),
+ limit: int = Query(10, le=100),
+ current_user: Union[UserPublic, UserBusiness] = Depends(get_current_user)
+):
+ """
+ Retrieve a paginated list of foodcourts.
+ - **skip**: The page number (starting from 0)
+ - **limit**: The number of items per page
+ """
+ foodcourts = get_all_records(session, Foodcourt, skip=skip, limit=limit)
+ return foodcourts
+
+@router.get("/foodcourts/{venue_id}", response_model=FoodcourtRead)
+async def read_foodcourt(
+ venue_id: uuid.UUID, session: SessionDep ,
+ current_user: Union[UserPublic, UserBusiness] = Depends(get_current_user)):
+ foodcourt = get_record_by_id(session, Foodcourt, venue_id)
+ if not foodcourt:
+ raise HTTPException(status_code=404, detail="foodcourt not found")
+ return foodcourt
+
+@router.post("/foodcourts/", response_model=FoodcourtRead)
+async def create_foodcourt(
+ foodcourt: FoodcourtCreate,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_business_user)
+):
+ return create_record(session, Foodcourt, foodcourt)
+
+@router.put("/foodcourts/{venue_id}", response_model=Foodcourt)
+async def update_foodcourt(
+ venue_id: uuid.UUID,
+ updated_foodcourt: FoodcourtCreate,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_business_user),
+ ):
+ return update_record(session, Foodcourt, venue_id, updated_foodcourt)
+
+@router.delete("/foodcourts/{venue_id}", response_model=None)
+async def delete_foodcourt(
+ venue_id: uuid.UUID,
+ session: SessionDep,
+ current_user: UserBusiness = Depends(get_super_user)
+
+):
+ return delete_record(session, Foodcourt, venue_id)
\ No newline at end of file
diff --git a/backend/app/backend_pre_start.py b/backend/app/backend_pre_start.py
index c2f8e29ae1..9b9a3c3b81 100644
--- a/backend/app/backend_pre_start.py
+++ b/backend/app/backend_pre_start.py
@@ -28,7 +28,6 @@ def init(db_engine: Engine) -> None:
logger.error(e)
raise e
-
def main() -> None:
logger.info("Initializing service")
init(engine)
diff --git a/backend/app/core/config.py b/backend/app/core/config.py
index 1e3a440c1c..4afe4e6d36 100644
--- a/backend/app/core/config.py
+++ b/backend/app/core/config.py
@@ -1,16 +1,13 @@
import secrets
import warnings
-from typing import Annotated, Any, Literal
-
+from typing import Annotated, Any, ClassVar, Literal
from pydantic import (
AnyUrl,
BeforeValidator,
HttpUrl,
- PostgresDsn,
computed_field,
model_validator,
)
-from pydantic_core import MultiHostUrl
from pydantic_settings import BaseSettings, SettingsConfigDict
from typing_extensions import Self
@@ -30,10 +27,15 @@ class Settings(BaseSettings):
API_V1_STR: str = "/api/v1"
SECRET_KEY: str = secrets.token_urlsafe(32)
# 60 minutes * 24 hours * 8 days = 8 days
- ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8
+ ACCESS_TOKEN_EXPIRE_MINUTES: int = 60
DOMAIN: str = "localhost"
ENVIRONMENT: Literal["local", "staging", "production"] = "local"
+ # Add CLIENT_ID and CLIENT_SECRET
+ CLIENT_ID: str
+ CLIENT_SECRET: str
+ REFRESH_TOKEN_EXPIRE_DAYS: ClassVar[int] = 365 # Use ClassVar if it's a constant
+ ALGORITHM: str = "HS256"
@computed_field # type: ignore[prop-decorator]
@property
def server_host(self) -> str:
@@ -56,15 +58,8 @@ def server_host(self) -> str:
@computed_field # type: ignore[prop-decorator]
@property
- def SQLALCHEMY_DATABASE_URI(self) -> PostgresDsn:
- return MultiHostUrl.build(
- scheme="postgresql+psycopg",
- username=self.POSTGRES_USER,
- password=self.POSTGRES_PASSWORD,
- host=self.POSTGRES_SERVER,
- port=self.POSTGRES_PORT,
- path=self.POSTGRES_DB,
- )
+ def SQLALCHEMY_DATABASE_URI(self) -> str:
+ return f"postgresql://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}@{self.POSTGRES_SERVER}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}"
SMTP_TLS: bool = True
SMTP_SSL: bool = False
@@ -113,8 +108,10 @@ def _enforce_non_default_secrets(self) -> Self:
self._check_default_secret(
"FIRST_SUPERUSER_PASSWORD", self.FIRST_SUPERUSER_PASSWORD
)
+ print(f"FIRST_SUPERUSER_PASSWORD: {self.FIRST_SUPERUSER_PASSWORD}")
return self
-
-settings = Settings() # type: ignore
+print("About to initialize Settings...")
+settings = Settings()
+print("Settings initialized.")
diff --git a/backend/app/core/db.py b/backend/app/core/db.py
index d260a856d2..e8eb7671d2 100644
--- a/backend/app/core/db.py
+++ b/backend/app/core/db.py
@@ -1,34 +1,50 @@
-from sqlmodel import Session, create_engine, select
-
-from app import crud
+from datetime import datetime
+from sqlmodel import Session, create_engine
+from app.models.user import UserBusiness
from app.core.config import settings
-from app.models import User, UserCreate
+print("SQLALCHEMY_DATABASE_URI : ", str(settings.SQLALCHEMY_DATABASE_URI))
engine = create_engine(str(settings.SQLALCHEMY_DATABASE_URI))
-
-
-# make sure all SQLModel models are imported (app.models) before initializing DB
-# otherwise, SQLModel might fail to initialize relationships properly
-# for more details: https://github.com/fastapi/full-stack-fastapi-template/issues/28
-
-
-def init_db(session: Session) -> None:
- # Tables should be created with Alembic migrations
- # But if you don't want to use migrations, create
- # the tables un-commenting the next lines
- # from sqlmodel import SQLModel
-
- # from app.core.engine import engine
- # This works because the models are already imported and registered from app.models
- # SQLModel.metadata.create_all(engine)
-
- user = session.exec(
- select(User).where(User.email == settings.FIRST_SUPERUSER)
- ).first()
- if not user:
- user_in = UserCreate(
- email=settings.FIRST_SUPERUSER,
- password=settings.FIRST_SUPERUSER_PASSWORD,
- is_superuser=True,
- )
- user = crud.create_user(session=session, user_create=user_in)
+print("engine created : ")
+
+connection = engine.connect()
+print("Connection successful!")
+connection.close()
+
+def init_db() -> None:
+ """
+ Initialize the database with the necessary default data.
+ Assumes that database schema is up-to-date due to Alembic migrations.
+ """
+ # Example: Create the superuser if it does not exist
+ with Session(engine) as session:
+ print("here")
+ # Check for existing superuser
+ # superuser = session.exec(
+ # select(UserBusiness).where(UserBusiness.email == settings.FIRST_SUPERUSER)
+ # ).first()
+ # print("heree")
+
+ # if not superuser:
+ # print("here1")
+ # user_in = UserBusiness(
+ # email=settings.FIRST_SUPERUSER,
+ # phone_number=None,
+ # is_active=True,
+ # is_superuser=True,
+ # full_name="Superuser",
+ # registration_date=datetime.utcnow()
+ # )
+ # print("here2")
+ # # Create superuser in the database
+ # session.add(user_in)
+ # print("here3")
+ # session.commit()
+ # print("here4")
+ # session.refresh(user_in)
+
+ # Other initial setup tasks can go here
+ # Example: Create default Nightclub, Foodcourt, etc.
+ # ...
+
+ print("Database initialization complete.")
\ No newline at end of file
diff --git a/backend/app/core/security.py b/backend/app/core/security.py
index 7aff7cfb32..0e0046cd04 100644
--- a/backend/app/core/security.py
+++ b/backend/app/core/security.py
@@ -1,27 +1,69 @@
from datetime import datetime, timedelta, timezone
-from typing import Any
-
-import jwt
-from passlib.context import CryptContext
-
+from fastapi import HTTPException, status
+from jwt.exceptions import InvalidTokenError # Import the correct exception
from app.core.config import settings
+from app.models.auth import AccessToken, RefreshToken, TokenModel
+import jwt
+import uuid # For generating unique token ID
-pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
+ALGORITHM = "HS256"
+def get_jwt_payload(token: str) -> TokenModel:
+ try:
+ # Decode the token using the secret key and algorithm
+ payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
+ print('payload ', payload)
+ # Create and return a TokenModel instance with the decoded payload
+ return TokenModel(sub=payload.get("sub"), exp=payload.get("exp"))
-ALGORITHM = "HS256"
+ except jwt.ExpiredSignatureError:
+ # Handle expired token
+ raise HTTPException(status_code=401, detail="Token has expired")
+ except jwt.ExpiredSignatureError:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Token has expired"
+ )
+ except jwt.InvalidTokenError:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Invalid token"
+ )
+ except Exception as e:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail=f"Token validation failed: {str(e)}"
+ )
+def create_access_token(subject: str, expires_delta: timedelta | None = None) -> AccessToken:
+ if expires_delta:
+ expire = datetime.now(timezone.utc) + expires_delta
+ else:
+ expire = datetime.now(timezone.utc) + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
-def create_access_token(subject: str | Any, expires_delta: timedelta) -> str:
- expire = datetime.now(timezone.utc) + expires_delta
- to_encode = {"exp": expire, "sub": str(subject)}
+ jti = str(uuid.uuid4())
+ to_encode = {"exp": expire, "sub": str(subject), "jti": jti}
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=ALGORITHM)
- return encoded_jwt
+ # Create an instance of AccessToken with the encoded JWT and expiration time
+ access_token = AccessToken(
+ token=encoded_jwt,
+ expires_at=expire,
+ token_type="Bearer"
+ )
+
+ return access_token
-def verify_password(plain_password: str, hashed_password: str) -> bool:
- return pwd_context.verify(plain_password, hashed_password)
+def create_refresh_token(subject: str) -> RefreshToken:
+ expire = datetime.now(timezone.utc) + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS)
+ jti = str(uuid.uuid4())
+ to_encode = {"sub": str(subject), "exp": expire, "jti": jti}
+ encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=ALGORITHM)
+ # Create an instance of RefreshToken with the encoded JWT and expiration time
+ refresh_token = RefreshToken(
+ token=encoded_jwt,
+ expires_at=expire
+ )
-def get_password_hash(password: str) -> str:
- return pwd_context.hash(password)
+ return refresh_token
\ No newline at end of file
diff --git a/backend/app/crud.py b/backend/app/crud.py
index 905bf48724..b541fa78ea 100644
--- a/backend/app/crud.py
+++ b/backend/app/crud.py
@@ -1,54 +1,166 @@
+import datetime
import uuid
-from typing import Any
-
-from sqlmodel import Session, select
-
-from app.core.security import get_password_hash, verify_password
-from app.models import Item, ItemCreate, User, UserCreate, UserUpdate
-
-
-def create_user(*, session: Session, user_create: UserCreate) -> User:
- db_obj = User.model_validate(
- user_create, update={"hashed_password": get_password_hash(user_create.password)}
- )
- session.add(db_obj)
- session.commit()
- session.refresh(db_obj)
- return db_obj
-
-
-def update_user(*, session: Session, db_user: User, user_in: UserUpdate) -> Any:
- user_data = user_in.model_dump(exclude_unset=True)
- extra_data = {}
- if "password" in user_data:
- password = user_data["password"]
- hashed_password = get_password_hash(password)
- extra_data["hashed_password"] = hashed_password
- db_user.sqlmodel_update(user_data, update=extra_data)
- session.add(db_user)
- session.commit()
- session.refresh(db_user)
- return db_user
-
-
-def get_user_by_email(*, session: Session, email: str) -> User | None:
- statement = select(User).where(User.email == email)
- session_user = session.exec(statement).first()
- return session_user
-
-
-def authenticate(*, session: Session, email: str, password: str) -> User | None:
- db_user = get_user_by_email(session=session, email=email)
- if not db_user:
- return None
- if not verify_password(password, db_user.hashed_password):
- return None
- return db_user
-
-
-def create_item(*, session: Session, item_in: ItemCreate, owner_id: uuid.UUID) -> Item:
- db_item = Item.model_validate(item_in, update={"owner_id": owner_id})
- session.add(db_item)
- session.commit()
- session.refresh(db_item)
- return db_item
+from fastapi import HTTPException
+from sqlmodel import SQLModel, Session, select
+from typing import List, Type
+
+# Generic CRUD function to get all records with pagination
+def get_all_records(
+ session: Session, model: Type[SQLModel], skip: int = 0, limit: int = 10
+) -> List[SQLModel]:
+ """
+ Retrieve a paginated list of records.
+ - **session**: Database session
+ - **model**: SQLModel class (e.g., Nightclub, Restaurant, QSR, Foodcourt)
+ - **skip**: Number of records to skip
+ - **limit**: Number of records to return
+ """
+ try:
+ statement = select(model).offset(skip).limit(limit)
+ result = session.execute(statement).scalars().all()
+ return result
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Error retrieving {model.__name__} records: {str(e)}")
+
+# Function to get a single record by ID
+def get_record_by_id(
+ session: Session, model: Type[SQLModel], record_id: uuid.UUID
+) -> SQLModel:
+ """
+ Retrieve a single record by ID.
+ - **session**: Database session
+ - **model**: SQLModel class (e.g., Nightclub, Restaurant, QSR, Foodcourt)
+ - **record_id**: ID of the record to retrieve
+ """
+ try:
+ statement = select(model).where(model.id == record_id)
+ result = session.execute(statement).scalars().first()
+ if not result:
+ raise HTTPException(status_code=404, detail=f"{model.__name__} with ID {record_id} not found.")
+ return result
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Error retrieving {model.__name__} record: {str(e)}")
+
+# Function to create a new record
+# Create a new record
+def create_record(
+ session: Session, model: Type[SQLModel], obj_in: SQLModel
+) -> SQLModel:
+ """
+ Create a new record with automatic `created_at` and `updated_at` timestamps.
+ - **session**: Database session
+ - **model**: SQLModel class (e.g., Nightclub, Restaurant, QSR, Foodcourt)
+ - **obj_in**: Data to create the new record
+ """
+ try:
+ # Prepare the data for creation
+ obj_data = obj_in.model_dump()
+
+ # Set `created_at` and `updated_at` timestamps
+ obj_data['created_at'] = datetime.utcnow()
+ obj_data['updated_at'] = datetime.utcnow()
+
+ # Create the new object
+ obj = model(**obj_data)
+ session.add(obj)
+ session.commit()
+ session.refresh(obj)
+ return obj
+ except Exception as e:
+ session.rollback()
+ raise HTTPException(status_code=500, detail=f"Error creating {model.__name__}: {str(e)}")
+
+
+# Update an existing record
+def update_record(
+ session: Session, model: Type[SQLModel], record_id: uuid.UUID, obj_in: SQLModel
+) -> SQLModel:
+ """
+ Update an existing record with automatic `updated_at` timestamp.
+ - **session**: Database session
+ - **model**: SQLModel class (e.g., Nightclub, Restaurant, QSR, Foodcourt)
+ - **record_id**: ID of the record to update
+ - **obj_in**: Data to update the record
+ """
+ try:
+ # Retrieve the existing record
+ obj = get_record_by_id(session, model, record_id)
+
+ # Convert incoming data
+ obj_data = obj_in.model_dump()
+
+ # Update the fields
+ for field, value in obj_data.items():
+ setattr(obj, field, value)
+
+ # Set `updated_at` to the current time
+ obj.updated_at = datetime.utcnow()
+
+ # Commit the changes
+ session.add(obj)
+ session.commit()
+ session.refresh(obj)
+ return obj
+ except HTTPException as e:
+ raise e
+ except Exception as e:
+ session.rollback()
+ raise HTTPException(status_code=500, detail=f"Error updating {model.__name__}: {str(e)}")
+
+
+# Partially update an existing record
+def patch_record(
+ session: Session, model: Type[SQLModel], record_id: uuid.UUID, obj_in: SQLModel
+) -> SQLModel:
+ """
+ Partially update an existing record with automatic `updated_at` timestamp.
+ - **session**: Database session
+ - **model**: SQLModel class (e.g., Nightclub, Restaurant, QSR)
+ - **record_id**: ID of the record to update
+ - **obj_in**: Partial data to update the record
+ """
+ try:
+ # Get the existing record from the database
+ obj = get_record_by_id(session, model, record_id)
+
+ # Convert the incoming data
+ obj_data = obj_in.model_dump()
+
+ # Update the fields on the object
+ for field, value in obj_data.items():
+ setattr(obj, field, value)
+
+ # Set `updated_at` to the current time
+ obj.updated_at = datetime.utcnow()
+
+ # Commit the changes
+ session.add(obj)
+ session.commit()
+ session.refresh(obj)
+
+ return obj
+ except HTTPException as e:
+ raise e
+ except Exception as e:
+ session.rollback()
+ raise HTTPException(status_code=500, detail=f"Error updating {model.__name__}: {str(e)}")
+
+# Function to delete a record
+def delete_record(
+ session: Session, model: Type[SQLModel], record_id: uuid.UUID
+) -> None:
+ """
+ Delete a record by ID.
+ - **session**: Database session
+ - **model**: SQLModel class (e.g., Nightclub, Restaurant, QSR, Foodcourt)
+ - **record_id**: ID of the record to delete
+ """
+ try:
+ obj = get_record_by_id(session, model, record_id)
+ session.delete(obj)
+ session.commit()
+ except HTTPException as e:
+ raise e
+ except Exception as e:
+ session.rollback()
+ raise HTTPException(status_code=500, detail=f"Error deleting {model.__name__} with ID {record_id}: {str(e)}")
\ No newline at end of file
diff --git a/backend/app/initial_data.py b/backend/app/initial_data.py
index d806c3d381..e72da8788f 100644
--- a/backend/app/initial_data.py
+++ b/backend/app/initial_data.py
@@ -9,8 +9,7 @@
def init() -> None:
- with Session(engine) as session:
- init_db(session)
+ init_db()
def main() -> None:
diff --git a/backend/app/main.py b/backend/app/main.py
index 4c252a1722..35b4454ea3 100644
--- a/backend/app/main.py
+++ b/backend/app/main.py
@@ -1,3 +1,4 @@
+from fastapi.staticfiles import StaticFiles
import sentry_sdk
from fastapi import FastAPI
from fastapi.routing import APIRoute
@@ -20,6 +21,8 @@ def custom_generate_unique_id(route: APIRoute) -> str:
generate_unique_id_function=custom_generate_unique_id,
)
+# app.mount("/static", StaticFiles(directory="app/static"), name="static")
+
# Set all CORS enabled origins
if settings.BACKEND_CORS_ORIGINS:
app.add_middleware(
diff --git a/backend/app/models.py b/backend/app/models.py
deleted file mode 100644
index 90ef5559e3..0000000000
--- a/backend/app/models.py
+++ /dev/null
@@ -1,114 +0,0 @@
-import uuid
-
-from pydantic import EmailStr
-from sqlmodel import Field, Relationship, SQLModel
-
-
-# Shared properties
-class UserBase(SQLModel):
- email: EmailStr = Field(unique=True, index=True, max_length=255)
- is_active: bool = True
- is_superuser: bool = False
- full_name: str | None = Field(default=None, max_length=255)
-
-
-# Properties to receive via API on creation
-class UserCreate(UserBase):
- password: str = Field(min_length=8, max_length=40)
-
-
-class UserRegister(SQLModel):
- email: EmailStr = Field(max_length=255)
- password: str = Field(min_length=8, max_length=40)
- full_name: str | None = Field(default=None, max_length=255)
-
-
-# Properties to receive via API on update, all are optional
-class UserUpdate(UserBase):
- email: EmailStr | None = Field(default=None, max_length=255) # type: ignore
- password: str | None = Field(default=None, min_length=8, max_length=40)
-
-
-class UserUpdateMe(SQLModel):
- full_name: str | None = Field(default=None, max_length=255)
- email: EmailStr | None = Field(default=None, max_length=255)
-
-
-class UpdatePassword(SQLModel):
- current_password: str = Field(min_length=8, max_length=40)
- new_password: str = Field(min_length=8, max_length=40)
-
-
-# Database model, database table inferred from class name
-class User(UserBase, table=True):
- id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
- hashed_password: str
- items: list["Item"] = Relationship(back_populates="owner", cascade_delete=True)
-
-
-# Properties to return via API, id is always required
-class UserPublic(UserBase):
- id: uuid.UUID
-
-
-class UsersPublic(SQLModel):
- data: list[UserPublic]
- count: int
-
-
-# Shared properties
-class ItemBase(SQLModel):
- title: str = Field(min_length=1, max_length=255)
- description: str | None = Field(default=None, max_length=255)
-
-
-# Properties to receive on item creation
-class ItemCreate(ItemBase):
- pass
-
-
-# Properties to receive on item update
-class ItemUpdate(ItemBase):
- title: str | None = Field(default=None, min_length=1, max_length=255) # type: ignore
-
-
-# Database model, database table inferred from class name
-class Item(ItemBase, table=True):
- id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
- title: str = Field(max_length=255)
- owner_id: uuid.UUID = Field(
- foreign_key="user.id", nullable=False, ondelete="CASCADE"
- )
- owner: User | None = Relationship(back_populates="items")
-
-
-# Properties to return via API, id is always required
-class ItemPublic(ItemBase):
- id: uuid.UUID
- owner_id: uuid.UUID
-
-
-class ItemsPublic(SQLModel):
- data: list[ItemPublic]
- count: int
-
-
-# Generic message
-class Message(SQLModel):
- message: str
-
-
-# JSON payload containing access token
-class Token(SQLModel):
- access_token: str
- token_type: str = "bearer"
-
-
-# Contents of JWT token
-class TokenPayload(SQLModel):
- sub: str | None = None
-
-
-class NewPassword(SQLModel):
- token: str
- new_password: str = Field(min_length=8, max_length=40)
diff --git a/backend/app/models/__init__.py b/backend/app/models/__init__.py
new file mode 100644
index 0000000000..4e4eab4cac
--- /dev/null
+++ b/backend/app/models/__init__.py
@@ -0,0 +1,32 @@
+from sqlmodel import SQLModel
+
+# Import all your models here
+from .club_visit import ClubVisit
+from .event import Event
+from .event_booking import EventBooking
+from .event_offering import EventOffering
+from .group import Group
+from .group_wallet import GroupWallet
+from .group_wallet_topup import GroupWalletTopup
+from .menu import RestaurantMenu, NightclubMenu, QSRMenu
+from .menu_category import MenuCategory
+from .menu_item import MenuItem
+from .order import NightclubOrder, RestaurantOrder, QSROrder
+from .order_item import OrderItem
+from .pickup_location import PickupLocation
+from .user import UserBusiness, UserPublic
+from .venue import Nightclub, QSR, Restaurant, Foodcourt
+from .payment import PaymentOrderNightclub, PaymentOrderRestaurant, PaymentOrderQSR, PaymentEvent
+
+# Make all models accessible when importing app.models
+__all__ = [
+ "SQLModel", "ClubVisit", "Event", "EventBooking", "EventOffering", "Group", "GroupWallet",
+ "GroupWalletTopup", "RestaurantMenu", "NightclubMenu", "QSRMenu", "MenuCategory",
+ "MenuItem", "NightclubOrder", "RestaurantOrder", "QSROrder", "OrderItem",
+ "PickupLocation", "UserBusiness", "UserPublic", "Nightclub", "QSR", "Restaurant",
+ "Foodcourt", "PaymentOrderNightclub", "PaymentOrderRestaurant", "PaymentOrderQSR",
+ "PaymentEvent"
+]
+
+
+print("target_metadata in init:", SQLModel.metadata.tables)
\ No newline at end of file
diff --git a/backend/app/models/auth.py b/backend/app/models/auth.py
new file mode 100644
index 0000000000..e86339e5a7
--- /dev/null
+++ b/backend/app/models/auth.py
@@ -0,0 +1,64 @@
+from sqlmodel import SQLModel, Field
+from datetime import datetime, timezone
+import uuid
+from typing import Optional
+from pydantic import EmailStr
+
+class TokenBlacklist(SQLModel, table=True):
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
+ jti: str = Field(index=True, unique=True) # Store JWT ID (jti)
+ user_id: uuid.UUID = Field(nullable=False)
+ created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), nullable=False)
+
+class OtplessPhoneAuthDetails(SQLModel):
+ mode: str
+ phone_number: str
+ country_code: str
+ auth_state: str
+
+class OtplessEmailAuthDetails(SQLModel):
+ email: EmailStr
+ mode: str
+ auth_state: str
+
+class AuthenticationDetails(SQLModel):
+ phone: OtplessPhoneAuthDetails
+ email: OtplessEmailAuthDetails
+
+class OtplessVerifyTokenResponse(SQLModel):
+ name: str
+ email: EmailStr
+ first_name: str
+ last_name: str
+ family_name: str
+ phone_number: str
+ national_phone_number: str
+ country_code: str
+ email_verified: bool
+ auth_time: str
+ authentication_details: AuthenticationDetails
+
+class OtplessToken(SQLModel):
+ otpless_token: str
+
+class TokenModel(SQLModel):
+ sub: str
+ exp: Optional[int] = None
+
+class RefreshTokenPayload(SQLModel):
+ refresh_token: str
+
+class AccessToken(SQLModel):
+ token: str
+ expires_at: datetime
+ token_type: str = "Bearer"
+
+class RefreshToken(SQLModel):
+ token: str
+ expires_at: datetime
+
+class UserAuthResponse(SQLModel):
+ access_token: AccessToken
+ refresh_token: RefreshToken
+ issued_at: datetime
+
\ No newline at end of file
diff --git a/backend/app/models/base_model.py b/backend/app/models/base_model.py
new file mode 100644
index 0000000000..6ef666c69a
--- /dev/null
+++ b/backend/app/models/base_model.py
@@ -0,0 +1,7 @@
+from sqlmodel import SQLModel, Field
+from datetime import datetime
+from typing import Optional
+
+class BaseTimeModel(SQLModel):
+ created_at: Optional[datetime] = Field(default_factory=datetime.now(datetime.timezone.utc), nullable=False)
+ updated_at: Optional[datetime] = Field(default_factory=datetime.now(datetime.timezone.utc), nullable=False)
\ No newline at end of file
diff --git a/backend/app/models/carousel_poster.py b/backend/app/models/carousel_poster.py
new file mode 100644
index 0000000000..ca54cf8ead
--- /dev/null
+++ b/backend/app/models/carousel_poster.py
@@ -0,0 +1,30 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional
+from datetime import datetime
+
+class CarouselPosterBase(SQLModel):
+ image_url: str = Field(nullable=False)
+ deep_link: str = Field(nullable=False)
+ latitude: float = Field(nullable=False)
+ longitude: float = Field(nullable=False)
+ expires_at: datetime = Field(nullable=False)
+
+ # Foreign keys [Optional]
+ event_id: Optional[uuid.UUID] = Field(default=None, foreign_key="event.id")
+ nightclub_id: Optional[uuid.UUID] = Field(default=None, foreign_key="nightclub.id")
+ foodcourt_id: Optional[uuid.UUID] = Field(default=None, foreign_key="foodcourt.id")
+ qsr_id: Optional[uuid.UUID] = Field(default=None, foreign_key="qsr.id")
+ restaurant_id: Optional[uuid.UUID] = Field(default=None, foreign_key="restaurant.id")
+
+class CarouselPoster(CarouselPosterBase, table=True):
+ __tablename__ = "carousel_poster"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ h3_index: str = Field(nullable=False)
+
+ # Relationships [Optional]
+ event: Optional["Event"] = Relationship(back_populates="carousel_posters")
+ nightclub: Optional["Nightclub"] = Relationship(back_populates="carousel_posters")
+ foodcourt: Optional["Foodcourt"] = Relationship(back_populates="carousel_posters")
+ qsr: Optional["QSR"] = Relationship(back_populates="carousel_posters")
+ restaurant: Optional["Restaurant"] = Relationship(back_populates="carousel_posters")
\ No newline at end of file
diff --git a/backend/app/models/club_visit.py b/backend/app/models/club_visit.py
new file mode 100644
index 0000000000..4b8bd4949d
--- /dev/null
+++ b/backend/app/models/club_visit.py
@@ -0,0 +1,20 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional
+from datetime import datetime
+
+class ClubVisit(SQLModel, table=True):
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
+ user_id: Optional[uuid.UUID] = Field(foreign_key="user_public.id", nullable=False)
+ group_id: Optional[uuid.UUID] = Field(foreign_key="group.id", nullable=True)
+ nightclub_id: Optional[uuid.UUID] = Field(foreign_key="nightclub.id", nullable=False)
+ entry_time: datetime = Field(nullable=False)
+ exit_time: Optional[datetime] = Field(nullable=True)
+ cover_charge: Optional[float] = Field(nullable=True)
+ total_bill: Optional[float] = Field(nullable=True)
+
+ # Relationships
+ user: Optional["UserPublic"] = Relationship(back_populates="club_visits")
+ group: Optional["Group"] = Relationship(back_populates="club_visits")
+ nightclub: Optional["Nightclub"] = Relationship(back_populates="club_visits")
+
diff --git a/backend/app/models/event.py b/backend/app/models/event.py
new file mode 100644
index 0000000000..2cdb6bf361
--- /dev/null
+++ b/backend/app/models/event.py
@@ -0,0 +1,20 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional, List
+from datetime import datetime
+
+class Event(SQLModel, table=True):
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ nightclub_id: uuid.UUID = Field(foreign_key="nightclub.id", nullable=False)
+ title: str = Field(nullable=False)
+ start_time: datetime = Field(nullable=False)
+ end_time: datetime = Field(nullable=False)
+ image_url: Optional[str] = Field(nullable=True)
+ age_restriction: Optional[int] = Field(nullable=True)
+ dress_code: Optional[str] = Field(nullable=True)
+
+ # Relationships
+ nightclub: Optional["Nightclub"] = Relationship(back_populates="events")
+ offerings: List["EventOffering"] = Relationship(back_populates="event")
+ event_bookings: List["EventBooking"] = Relationship(back_populates="event")
+ carousel_posters: Optional[List["CarouselPoster"]] = Relationship(back_populates="event")
\ No newline at end of file
diff --git a/backend/app/models/event_booking.py b/backend/app/models/event_booking.py
new file mode 100644
index 0000000000..e28e1eb381
--- /dev/null
+++ b/backend/app/models/event_booking.py
@@ -0,0 +1,20 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional, List
+from datetime import datetime
+
+class EventBooking(SQLModel, table=True):
+ __tablename__ = "event_booking"
+
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
+ user_id: Optional[uuid.UUID] = Field(foreign_key="user_public.id", nullable=False)
+ event_id: Optional[uuid.UUID] = Field(foreign_key="event.id", nullable=False)
+ booking_time: datetime = Field(nullable=False)
+ total_amount: float = Field(nullable=False)
+ status: str = Field(nullable=False)
+
+ # Relationships
+ user: Optional["UserPublic"] = Relationship(back_populates="event_bookings")
+ event: Optional["Event"] = Relationship(back_populates="event_bookings")
+ payment: Optional["PaymentEvent"] = Relationship(back_populates="event_booking", sa_relationship_kwargs={"uselist": False})
+ event_offerings: List["EventOffering"] = Relationship(back_populates="event_booking")
\ No newline at end of file
diff --git a/backend/app/models/event_offering.py b/backend/app/models/event_offering.py
new file mode 100644
index 0000000000..27db18d4be
--- /dev/null
+++ b/backend/app/models/event_offering.py
@@ -0,0 +1,22 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional
+from typing import List
+
+# Stag, couple etc
+class EventOffering(SQLModel, table=True):
+ __tablename__ = "event_offering"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ event_id: uuid.UUID = Field(foreign_key="event.id", nullable=False)
+ event_booking_id: uuid.UUID = Field(foreign_key="event_booking.id", nullable=False)
+ offering_type: str = Field(nullable=False)
+ description: str = Field(nullable=False)
+ price: float = Field(nullable=False)
+ total_guests_per_pass: int = Field(nullable=False)
+ cover_charge: Optional[float] = Field(nullable=True)
+ additional_charges: Optional[float] = Field(nullable=True)
+ availability: int = Field(nullable=False)
+
+ # Relationships
+ event: Optional["Event"] = Relationship(back_populates="offerings")
+ event_booking: Optional["EventBooking"] = Relationship(back_populates="event_offerings")
\ No newline at end of file
diff --git a/backend/app/models/group.py b/backend/app/models/group.py
new file mode 100644
index 0000000000..3f90a1886b
--- /dev/null
+++ b/backend/app/models/group.py
@@ -0,0 +1,31 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional, List
+from datetime import datetime, timezone
+
+class GroupMembers(SQLModel, table=True):
+ group_id: uuid.UUID = Field(foreign_key="group.id", primary_key=True)
+ user_id: uuid.UUID = Field(foreign_key="user_public.id", primary_key=True)
+
+class GroupNightclubOrderLink(SQLModel, table=True):
+ __tablename__ = "group_nightclub_order_link"
+
+ group_id: uuid.UUID = Field(foreign_key="group.id", primary_key=True)
+ nightclub_order_id: uuid.UUID = Field( foreign_key="nightclub_order.id", primary_key=True)
+
+class Group(SQLModel, table=True):
+ __tablename__ = "group"
+
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ nightclub_id: Optional[uuid.UUID] = Field(foreign_key="nightclub.id")
+ created_at: datetime = Field(default=datetime.now(timezone.utc))
+ admin_user_id: uuid.UUID = Field(foreign_key="user_public.id", nullable=False)
+ table_number: Optional[str] = Field(default=None)
+
+ # Relationships
+ admin_user: Optional["UserPublic"] = Relationship(back_populates="managed_groups")
+ wallet: Optional["GroupWallet"] = Relationship(back_populates="group")
+ members: List["UserPublic"] = Relationship(back_populates="groups", link_model=GroupMembers)
+ club_visits: List["ClubVisit"] = Relationship(back_populates="group")
+ nightclub_orders: List["NightclubOrder"] = Relationship(back_populates="groups", link_model=GroupNightclubOrderLink)
+ nightclubs: List["Nightclub"] = Relationship(back_populates="group")
\ No newline at end of file
diff --git a/backend/app/models/group_wallet.py b/backend/app/models/group_wallet.py
new file mode 100644
index 0000000000..007418e3ba
--- /dev/null
+++ b/backend/app/models/group_wallet.py
@@ -0,0 +1,14 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional, List
+
+# (TODO) Added another model : Group wallet transactions
+class GroupWallet(SQLModel, table=True):
+ __tablename__ = "group_wallet"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ group_id: uuid.UUID = Field(foreign_key="group.id", nullable=False, unique=True)
+ balance: float = Field(default=0.0, nullable=False)
+
+ # Relationships
+ group: Optional["Group"] = Relationship(back_populates="wallet")
+ topups: List["GroupWalletTopup"] = Relationship(back_populates="group_wallet")
diff --git a/backend/app/models/group_wallet_topup.py b/backend/app/models/group_wallet_topup.py
new file mode 100644
index 0000000000..61f10c80d8
--- /dev/null
+++ b/backend/app/models/group_wallet_topup.py
@@ -0,0 +1,14 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional
+from datetime import datetime
+
+
+class GroupWalletTopup(SQLModel, table=True):
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ group_wallet_id: uuid.UUID = Field(foreign_key="group_wallet.id", nullable=False)
+ amount: float = Field(nullable=False)
+ topup_time: datetime = Field(nullable=False)
+
+ # Relationships
+ group_wallet: Optional["GroupWallet"] = Relationship(back_populates="topups")
\ No newline at end of file
diff --git a/backend/app/models/menu.py b/backend/app/models/menu.py
new file mode 100644
index 0000000000..0aa46454c3
--- /dev/null
+++ b/backend/app/models/menu.py
@@ -0,0 +1,43 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional, List
+
+class MenuBase(SQLModel):
+ name: str = Field(nullable=False)
+ description: Optional[str] = Field(default=None)
+ menu_type: Optional[str] = Field(default=None) # Type of menu (e.g., "Food", "Drink")
+
+class QSRMenuBase(MenuBase):
+ qsr_id: uuid.UUID = Field(foreign_key="qsr.id", nullable=False)
+
+class QSRMenu(QSRMenuBase, table=True):
+ __tablename__= "qsr_menu"
+
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+
+ # Relationships
+ qsr: "QSR" = Relationship(back_populates="menu")
+ categories: List["MenuCategory"] = Relationship(back_populates="qsr_menu")
+
+class RestaurantMenuBase(MenuBase):
+ restaurant_id: uuid.UUID = Field(foreign_key="restaurant.id", nullable=False)
+
+class RestaurantMenu(RestaurantMenuBase, table=True):
+ __tablename__= "restaurant_menu"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+
+ # Relationships
+ restaurant: "Restaurant" = Relationship(back_populates="menu")
+ categories: List["MenuCategory"] = Relationship(back_populates="restaurant_menu")
+
+class NightclubMenuBase(MenuBase):
+ nightclub_id: uuid.UUID = Field(foreign_key="nightclub.id", nullable=False)
+
+class NightclubMenu(NightclubMenuBase, table=True):
+ __tablename__= "nightclub_menu"
+
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+
+ # Relationships
+ nightclub: "Nightclub" = Relationship(back_populates="menu")
+ categories: List["MenuCategory"] = Relationship(back_populates="nightclub_menu")
diff --git a/backend/app/models/menu_category.py b/backend/app/models/menu_category.py
new file mode 100644
index 0000000000..e6df4dbe0f
--- /dev/null
+++ b/backend/app/models/menu_category.py
@@ -0,0 +1,40 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional, List
+from pydantic import model_validator
+
+class MenuCategoryBase(SQLModel):
+ qsr_menu_id: Optional[uuid.UUID] = Field(default=None, foreign_key="qsr_menu.id")
+ restaurant_menu_id: Optional[uuid.UUID] = Field(default=None, foreign_key="restaurant_menu.id")
+ nightclub_menu_id: Optional[uuid.UUID] = Field(default=None, foreign_key="nightclub_menu.id")
+ name: str = Field(nullable=False)
+
+ @model_validator(mode="before")
+ def check_only_one_menu_id(cls, values):
+ # Convert to a regular dictionary
+ values_dict = dict(values)
+ print("values ", values_dict)
+
+ # Use .get() to safely access values
+ qsr_menu_id = values_dict.get('qsr_menu_id')
+ restaurant_menu_id = values_dict.get('restaurant_menu_id')
+ nightclub_menu_id = values_dict.get('nightclub_menu_id')
+
+ # Count how many of these fields are set (not None)
+ menu_ids = [qsr_menu_id, restaurant_menu_id, nightclub_menu_id]
+ if sum(id is not None for id in menu_ids) != 1:
+ raise ValueError("You must set exactly one of qsr_menu_id, restaurant_menu_id, or nightclub_menu_id.")
+
+ return values
+
+class MenuCategory(MenuCategoryBase, table=True):
+ __tablename__ = "menu_category"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+
+ # Relationships
+ menu_items: List["MenuItem"] = Relationship(back_populates="category")
+
+ # Relationships with specific menu types
+ qsr_menu: Optional["QSRMenu"] = Relationship(back_populates="categories")
+ restaurant_menu: Optional["RestaurantMenu"] = Relationship(back_populates="categories")
+ nightclub_menu: Optional["NightclubMenu"] = Relationship(back_populates="categories")
\ No newline at end of file
diff --git a/backend/app/models/menu_item.py b/backend/app/models/menu_item.py
new file mode 100644
index 0000000000..063b2be15a
--- /dev/null
+++ b/backend/app/models/menu_item.py
@@ -0,0 +1,21 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional
+
+class MenuItemBase(SQLModel):
+ category_id: uuid.UUID = Field(foreign_key="menu_category.id", nullable=False)
+ name: str = Field(nullable=False)
+ price: float = Field(nullable=False)
+ description: Optional[str] = Field(default=None)
+ image_url: Optional[str] = Field(default=None)
+ is_veg: Optional[bool] = Field(default=None)
+ ingredients: Optional[str] = Field(default=None)
+ abv: Optional[float] = Field(default=None)
+ ibu: Optional[int] = Field(default=None)
+
+class MenuItem(MenuItemBase, table=True):
+ __tablename__="menu_item"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+
+ # Relationships
+ category: Optional["MenuCategory"] = Relationship(back_populates="menu_items")
\ No newline at end of file
diff --git a/backend/app/models/order.py b/backend/app/models/order.py
new file mode 100644
index 0000000000..571a2e4908
--- /dev/null
+++ b/backend/app/models/order.py
@@ -0,0 +1,58 @@
+import uuid
+from app.models.group import GroupNightclubOrderLink
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional, List
+from datetime import datetime
+
+
+class OrderBase(SQLModel):
+ user_id: uuid.UUID = Field(foreign_key="user_public.id")
+ pickup_location_id: Optional[uuid.UUID] = Field(default=None, foreign_key="pickup_location.id")
+ note: Optional[str] = Field(nullable=True)
+ order_time: datetime = Field(nullable=False)
+ total_amount: float = Field(nullable=False)
+ taxes_and_charges: Optional[float] = Field(default=None)
+ cover_charge_used: Optional[float] = Field(default=None)
+ status: str = Field(nullable=False)
+ service_type: Optional[str] = Field(default=None)
+
+class NightclubOrder(OrderBase, table=True):
+ __tablename__ = "nightclub_order"
+
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ venue_id: Optional[uuid.UUID] = Field(default=None, foreign_key="nightclub.id")
+ payment_id: Optional[uuid.UUID] = Field(default=None, foreign_key="payment_source_nightclub.id")
+ pickup_location_id: Optional[uuid.UUID] = Field(default=None, foreign_key="pickup_location.id")
+ # Relationships
+ user: Optional["UserPublic"] = Relationship(back_populates="nightclub_orders")
+ nightclub: Optional["Nightclub"] = Relationship(back_populates="orders")
+ pickup_location: Optional["PickupLocation"] = Relationship(back_populates="orders")
+ payment: Optional["PaymentOrderNightclub"] = Relationship(back_populates="order", sa_relationship_kwargs={"uselist": False})
+ groups: List["Group"] = Relationship(back_populates="nightclub_orders", link_model=GroupNightclubOrderLink) # Many-to-many
+ order_items: List["OrderItem"] = Relationship(back_populates="nightclub_order")
+
+class RestaurantOrder(OrderBase, table=True):
+ __tablename__ = "restaurant_order"
+
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ venue_id: Optional[uuid.UUID] = Field(default=None, foreign_key="restaurant.id")
+ payment_id: Optional[uuid.UUID] = Field(default=None, foreign_key="payment_source_restaurant.id")
+
+ # Relationships
+ user: Optional["UserPublic"] = Relationship(back_populates="restaurant_orders")
+ restaurant: Optional["Restaurant"] = Relationship(back_populates="orders")
+ payment: Optional["PaymentOrderRestaurant"] = Relationship(back_populates="order", sa_relationship_kwargs={"uselist": False})
+ order_items: List["OrderItem"] = Relationship(back_populates="restaurant_order")
+
+class QSROrder(OrderBase, table=True):
+ __tablename__ = "qsr_order"
+
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ venue_id: uuid.UUID = Field(default=None, foreign_key="qsr.id")
+ payment_id: uuid.UUID = Field(default=None, foreign_key="payment_source_qsr.id")
+
+ # Relationships
+ user: Optional["UserPublic"] = Relationship(back_populates="qsr_orders")
+ qsr: Optional["QSR"] = Relationship(back_populates="orders")
+ payment: Optional["PaymentOrderQSR"] = Relationship(back_populates="order", sa_relationship_kwargs={"uselist": False})
+ order_items: List["OrderItem"] = Relationship(back_populates="qsr_order")
\ No newline at end of file
diff --git a/backend/app/models/order_item.py b/backend/app/models/order_item.py
new file mode 100644
index 0000000000..0e0447ab26
--- /dev/null
+++ b/backend/app/models/order_item.py
@@ -0,0 +1,17 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional
+
+
+class OrderItem(SQLModel, table=True):
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ nightclub_order_id: Optional[uuid.UUID] = Field(default=None, foreign_key="nightclub_order.id")
+ restaurant_order_id: Optional[uuid.UUID] = Field(default=None, foreign_key="restaurant_order.id")
+ qsr_order_id: Optional[uuid.UUID] = Field(default=None, foreign_key="qsr_order.id")
+ item_id: uuid.UUID = Field(foreign_key="menu_item.id", nullable=False)
+ quantity: int = Field(nullable=False)
+
+ # Relationships
+ nightclub_order: Optional["NightclubOrder"] = Relationship(back_populates="order_items")
+ restaurant_order: Optional["RestaurantOrder"] = Relationship(back_populates="order_items")
+ qsr_order: Optional["QSROrder"] = Relationship(back_populates="order_items")
\ No newline at end of file
diff --git a/backend/app/models/payment.py b/backend/app/models/payment.py
new file mode 100644
index 0000000000..d47db3c729
--- /dev/null
+++ b/backend/app/models/payment.py
@@ -0,0 +1,44 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional
+from datetime import datetime
+
+class PaymentBase(SQLModel):
+ user_id: uuid.UUID = Field(foreign_key="user_public.id", nullable=False)
+ source_type: str = Field(nullable=False) # Changed to str
+ gateway_transaction_id: Optional[uuid.UUID] = Field(default=None)
+ payment_time: datetime = Field(nullable=False)
+ amount: float = Field(nullable=False)
+ status: str = Field(nullable=False) # e.g., Paid, Pending, Failed
+ source_type: str = Field(nullable=False)
+
+class PaymentOrderNightclub(PaymentBase, table=True):
+ __tablename__ = "payment_source_nightclub"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ retry_count: int = Field(default=0)
+ last_attempt_time: Optional[datetime] = Field(default=None)
+ order: "NightclubOrder" = Relationship(back_populates="payment", sa_relationship_kwargs={"uselist": False})
+ user: Optional["UserPublic"] = Relationship(back_populates="nightclub_payments")
+
+class PaymentOrderQSR(PaymentBase, table=True):
+ __tablename__ = "payment_source_qsr"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ retry_count: int = Field(default=0)
+ last_attempt_time: Optional[datetime] = Field(default=None)
+ order: "QSROrder" = Relationship(back_populates="payment", sa_relationship_kwargs={"uselist": False})
+ user: Optional["UserPublic"] = Relationship(back_populates="qsr_payments")
+
+class PaymentOrderRestaurant(PaymentBase, table=True):
+ __tablename__ = "payment_source_restaurant"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ retry_count: int = Field(default=0)
+ last_attempt_time: Optional[datetime] = Field(default=None)
+ order: "RestaurantOrder" = Relationship(back_populates="payment", sa_relationship_kwargs={"uselist": False})
+ user: Optional["UserPublic"] = Relationship(back_populates="restaurant_payments")
+
+class PaymentEvent(PaymentBase, table=True):
+ __tablename__ = "payment_event"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ event_booking_id: Optional[uuid.UUID] = Field(default=None, foreign_key="event_booking.id")
+ event_booking: Optional["EventBooking"] = Relationship(back_populates="payment", sa_relationship_kwargs={"uselist": False})
+ user: Optional["UserPublic"] = Relationship(back_populates="event_payments")
diff --git a/backend/app/models/pickup_location.py b/backend/app/models/pickup_location.py
new file mode 100644
index 0000000000..ae20d52174
--- /dev/null
+++ b/backend/app/models/pickup_location.py
@@ -0,0 +1,17 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional, List
+
+class PickupLocation(SQLModel, table=True):
+ __tablename__ = "pickup_location"
+
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ nightclub_id: uuid.UUID = Field(foreign_key="nightclub.id", nullable=False)
+ name: str = Field(nullable=False)
+ description: Optional[str] = Field(default=None)
+
+ # Relationships
+ orders: List["NightclubOrder"] = Relationship(back_populates="pickup_location")
+
+ # Optionally, if you have a specific type of venue for PickupLocation
+ nightclub: Optional["Nightclub"] = Relationship(back_populates="pickup_locations")
\ No newline at end of file
diff --git a/backend/app/models/qrcode.py b/backend/app/models/qrcode.py
new file mode 100644
index 0000000000..9e549c41ef
--- /dev/null
+++ b/backend/app/models/qrcode.py
@@ -0,0 +1,39 @@
+import uuid
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional, List
+from pydantic import model_validator, ValidationError
+
+class QRBase(SQLModel):
+ table_number: Optional[str] = Field(default=None, nullable=True)
+
+class QRCode(QRBase, table=True):
+ __tablename__ = "qr_codes"
+ id: Optional[uuid.UUID] = Field(default_factory=uuid.uuid4, primary_key=True)
+
+ # References
+ foodcourt_id: Optional[uuid.UUID] = Field(default=None, foreign_key="foodcourt.id")
+ qsr_id: Optional[uuid.UUID] = Field(default=None, foreign_key="qsr.id")
+ nightclub_id: Optional[uuid.UUID] = Field(default=None, foreign_key="nightclub.id")
+ restaurant_id: Optional[uuid.UUID] = Field(default=None, foreign_key="restaurant.id")
+
+ # Relationships
+ foodcourt: Optional["Foodcourt"] = Relationship(back_populates="qr_codes")
+ qsr: Optional["QSR"] = Relationship(back_populates="qr_codes")
+ nightclub: Optional["Nightclub"] = Relationship(back_populates="qr_codes")
+ restaurant: Optional["Restaurant"] = Relationship(back_populates="qr_codes")
+
+ # Custom model validator to ensure exactly one foreign key is present
+ @model_validator(mode="before")
+ def check_one_foreign_key(cls, values):
+ foodcourt_id = values.get("foodcourt_id")
+ qsr_id = values.get("qsr_id")
+ nightclub_id = values.get("nightclub_id")
+ restaurant_id = values.get("restaurant_id")
+
+ # Count how many of the foreign key fields are set
+ count = sum(v is not None for v in [foodcourt_id, qsr_id, nightclub_id, restaurant_id])
+
+ if count != 1:
+ raise ValueError("Exactly one of the following must be set: foodcourt_id, qsr_id, nightclub_id, restaurant_id.")
+
+ return values
diff --git a/backend/app/models/user.py b/backend/app/models/user.py
new file mode 100644
index 0000000000..38ff0d4674
--- /dev/null
+++ b/backend/app/models/user.py
@@ -0,0 +1,63 @@
+from app.models.group import GroupMembers
+from app.models.venue import FoodcourtUserBusinessLink, NightclubUserBusinessLink, QSRUserBusinessLink, RestaurantUserBusinessLink
+from sqlmodel import SQLModel, Field, Relationship
+from typing import TYPE_CHECKING, Optional, List
+from datetime import datetime
+import uuid
+from pydantic import EmailStr
+
+# Shared properties
+class UserBase(SQLModel):
+ email: EmailStr = Field(unique=True, nullable=True, index=True, max_length=255)
+ phone_number: Optional[str] = Field(unique=True, nullable=False,index=True,default=None)
+ is_active: bool = True
+ is_superuser: bool = False
+ full_name: str | None = Field(default=None, max_length=255)
+ refresh_token: str = Field(nullable=True)
+
+class UserPublic(UserBase, table=True):
+ __tablename__ = "user_public"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ date_of_birth: Optional[datetime] = Field(default=None)
+ gender: Optional[str] = Field(default=None)
+ registration_date: datetime = Field(nullable=False)
+ profile_picture: Optional[str] = Field(default=None)
+ preferences: Optional[str] = Field(default=None)
+
+ # Relationships
+ nightclub_orders: List["NightclubOrder"] = Relationship(back_populates="user")
+ restaurant_orders: List["RestaurantOrder"] = Relationship(back_populates="user")
+ qsr_orders: List["QSROrder"] = Relationship(back_populates="user")
+
+ club_visits: List["ClubVisit"] = Relationship(back_populates="user")
+ event_bookings: List["EventBooking"] = Relationship(back_populates="user")
+ groups: List["Group"] = Relationship(back_populates="members", link_model=GroupMembers)
+ managed_groups: List["Group"] = Relationship(back_populates="admin_user")
+ nightclub_payments: List["PaymentOrderNightclub"] = Relationship(back_populates="user")
+ qsr_payments: List["PaymentOrderQSR"] = Relationship(back_populates="user")
+ restaurant_payments: List["PaymentOrderRestaurant"] = Relationship(back_populates="user")
+ event_payments: List["PaymentEvent"] = Relationship(back_populates="user")
+
+
+class UserBusiness(UserBase, table=True):
+ __tablename__ = "user_business"
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ registration_date: datetime = Field(nullable=False)
+
+ # Relationships
+ managed_foodcourts: List["Foodcourt"] = Relationship(
+ back_populates="managing_users",
+ link_model=FoodcourtUserBusinessLink
+ )
+ managed_qsrs: List["QSR"] = Relationship(
+ back_populates="managing_users",
+ link_model=QSRUserBusinessLink
+ )
+ managed_restaurants: List["Restaurant"] = Relationship(
+ back_populates="managing_users",
+ link_model=RestaurantUserBusinessLink
+ )
+ managed_nightclubs: List["Nightclub"] = Relationship(
+ back_populates="managing_users",
+ link_model=NightclubUserBusinessLink
+ )
diff --git a/backend/app/models/venue.py b/backend/app/models/venue.py
new file mode 100644
index 0000000000..e4c61c1524
--- /dev/null
+++ b/backend/app/models/venue.py
@@ -0,0 +1,111 @@
+import uuid
+from app.models.qrcode import QRCode
+from sqlmodel import SQLModel, Field, Relationship
+from typing import Optional, List, TYPE_CHECKING
+
+class VenueBase(SQLModel):
+ name: str = Field(nullable=False)
+ address: Optional[str] = Field(default=None)
+ latitude: Optional[float] = Field(default=None)
+ longitude: Optional[float] = Field(default=None)
+ capacity: Optional[int] = Field(default=None)
+ description: Optional[str] = Field(default=None)
+ google_rating: Optional[float] = Field(default=None)
+ instagram_handle: Optional[str] = Field(default=None)
+ instagram_token: Optional[str] = Field(default=None)
+ google_map_link: Optional[str] = Field(default=None)
+ mobile_number: Optional[str] = Field(default=None)
+ email: Optional[str] = Field(default=None)
+ opening_time: Optional[str] = Field(default=None)
+ closing_time: Optional[str] = Field(default=None)
+ avg_expense_for_two: Optional[float] = Field(default=None)
+ qr_url: Optional[str] = Field(default=None)
+
+class NightclubUserBusinessLink(SQLModel, table=True):
+ nightclub_id: uuid.UUID = Field(foreign_key="nightclub.id", primary_key=True)
+ user_business_id: uuid.UUID = Field(foreign_key="user_business.id", primary_key=True)
+
+class NightclubBase(VenueBase):
+ pass
+
+class Nightclub(NightclubBase, table=True):
+ __tablename__ = "nightclub"
+
+ id: Optional[uuid.UUID] = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ # Relationships
+ events: List["Event"] = Relationship(back_populates="nightclub")
+ club_visits: List["ClubVisit"] = Relationship(back_populates="nightclub")
+ menu: List["NightclubMenu"] = Relationship(back_populates="nightclub")
+ orders: List["NightclubOrder"] = Relationship(back_populates="nightclub")
+ pickup_locations: List["PickupLocation"] = Relationship(back_populates="nightclub")
+ group : List["Group"] = Relationship(back_populates="nightclubs")
+ managing_users: List["UserBusiness"] = Relationship(
+ back_populates="managed_nightclubs",
+ link_model=NightclubUserBusinessLink
+ )
+ qr_codes: List[QRCode] = Relationship(back_populates="nightclub")
+ carousel_posters: Optional[List["CarouselPoster"]] = Relationship(back_populates="nightclub")
+
+class RestaurantUserBusinessLink(SQLModel, table=True):
+ restaurant_id: uuid.UUID = Field(foreign_key="restaurant.id", primary_key=True)
+ user_business_id: uuid.UUID = Field(foreign_key="user_business.id", primary_key=True)
+
+class RestaurantBase(VenueBase):
+ pass
+
+class Restaurant(RestaurantBase, table=True):
+ __tablename__ = "restaurant"
+
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ # Relationships
+ menu: List["RestaurantMenu"] = Relationship(back_populates="restaurant")
+ orders: List["RestaurantOrder"] = Relationship(back_populates="restaurant")
+ managing_users: List["UserBusiness"] = Relationship(
+ back_populates="managed_restaurants",
+ link_model=RestaurantUserBusinessLink
+ )
+ qr_codes: List[QRCode] = Relationship(back_populates="restaurant")
+ carousel_posters: Optional[List["CarouselPoster"]] = Relationship(back_populates="restaurant")
+
+class QSRUserBusinessLink(SQLModel, table=True):
+ qsr_id: uuid.UUID = Field(foreign_key="qsr.id", primary_key=True)
+ user_business_id: uuid.UUID = Field(foreign_key="user_business.id", primary_key=True)
+
+class QSRBase(VenueBase):
+ pass
+
+class QSR(QSRBase, table=True):
+ __tablename__ = "qsr"
+
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ foodcourt_id: Optional[uuid.UUID] = Field(default=None, foreign_key="foodcourt.id")
+ # Relationships
+ foodcourt: Optional["Foodcourt"] = Relationship(back_populates="qsrs")
+ menu: List["QSRMenu"] = Relationship(back_populates="qsr")
+ orders: List["QSROrder"] = Relationship(back_populates="qsr")
+ managing_users: List["UserBusiness"] = Relationship(
+ back_populates="managed_qsrs",
+ link_model=QSRUserBusinessLink
+ )
+ qr_codes: List[QRCode] = Relationship(back_populates="qsr")
+ carousel_posters: Optional[List["CarouselPoster"]] = Relationship(back_populates="qsr")
+
+class FoodcourtUserBusinessLink(SQLModel, table=True):
+ foodcourt_id: uuid.UUID = Field(foreign_key="foodcourt.id", primary_key=True)
+ user_business_id: uuid.UUID = Field(foreign_key="user_business.id", primary_key=True)
+
+class FoodcourtBase(VenueBase):
+ pass
+
+class Foodcourt(FoodcourtBase, table=True):
+ __tablename__ = "foodcourt"
+
+ id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
+ # Relationships
+ qsrs: List["QSR"] = Relationship(back_populates="foodcourt")
+ managing_users: List["UserBusiness"] = Relationship(
+ back_populates="managed_foodcourts",
+ link_model=FoodcourtUserBusinessLink
+ )
+ qr_codes: List[QRCode] = Relationship(back_populates="foodcourt")
+ carousel_posters: Optional[List["CarouselPoster"]] = Relationship(back_populates="foodcourt")
\ No newline at end of file
diff --git a/backend/app/alembic/versions/.keep b/backend/app/schema/__init__.py
old mode 100755
new mode 100644
similarity index 100%
rename from backend/app/alembic/versions/.keep
rename to backend/app/schema/__init__.py
diff --git a/backend/app/schema/auth.py b/backend/app/schema/auth.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/backend/app/schema/carousel_poster.py b/backend/app/schema/carousel_poster.py
new file mode 100644
index 0000000000..2020fe3fe3
--- /dev/null
+++ b/backend/app/schema/carousel_poster.py
@@ -0,0 +1,14 @@
+from sqlmodel import SQLModel, Field
+from typing import Optional
+import uuid
+from datetime import datetime
+from app.models.carousel_poster import CarouselPosterBase
+
+class CarouselPosterCreate(CarouselPosterBase):
+ class Config:
+ from_attributes = True
+
+class CarouselPosterRead(CarouselPosterBase):
+ id: Optional[uuid.UUID]
+ class Config:
+ from_attributes = True
\ No newline at end of file
diff --git a/backend/app/schema/menu.py b/backend/app/schema/menu.py
new file mode 100644
index 0000000000..56614da53f
--- /dev/null
+++ b/backend/app/schema/menu.py
@@ -0,0 +1,52 @@
+from typing import List, Optional
+import uuid
+from app.models.menu import NightclubMenuBase, QSRMenuBase, RestaurantMenuBase
+from app.models.menu_item import MenuItemBase
+from app.models.menu_category import MenuCategoryBase
+
+class QSRMenuRead(QSRMenuBase):
+ id: Optional[uuid.UUID]
+ class Config:
+ from_attributes = True
+
+class QSRMenuCreate(QSRMenuBase):
+ class Config:
+ from_attributes = True
+
+class RestaurantMenuRead(RestaurantMenuBase):
+ id: Optional[uuid.UUID]
+ class Config:
+ from_attributes = True
+
+class RestaurantMenuCreate(RestaurantMenuBase):
+ class Config:
+ from_attributes = True
+
+class MenuItemRead(MenuItemBase):
+ id: Optional[uuid.UUID]
+ class Config:
+ from_attributes = True
+
+class MenuCategoryRead(MenuCategoryBase):
+ id: Optional[uuid.UUID]
+ menu_items: List[MenuItemRead] = []
+ class Config:
+ from_attributes = True
+
+class NightclubMenuRead(NightclubMenuBase):
+ id: Optional[uuid.UUID]
+ categories: List[MenuCategoryRead] = []
+ class Config:
+ from_attributes = True
+
+class MenuItemCreate(MenuItemBase):
+ class Config:
+ from_attributes = True
+
+class MenuCategoryCreate(MenuCategoryBase):
+ class Config:
+ from_attributes = True
+
+class NightclubMenuCreate(NightclubMenuBase):
+ class Config:
+ from_attributes = True
diff --git a/backend/app/schema/qrcode.py b/backend/app/schema/qrcode.py
new file mode 100644
index 0000000000..eaa725f165
--- /dev/null
+++ b/backend/app/schema/qrcode.py
@@ -0,0 +1,25 @@
+from typing import Optional
+from uuid import UUID
+from pydantic import BaseModel, Field
+
+class QRCodeBase(BaseModel):
+ table_number: Optional[str] = Field(default=None, nullable=True)
+ foodcourt_id: Optional[UUID] = Field(default=None)
+ qsr_id: Optional[UUID] = Field(default=None)
+ nightclub_id: Optional[UUID] = Field(default=None)
+ restaurant_id: Optional[UUID] = Field(default=None)
+
+class QRCodeCreate(QRCodeBase):
+ """
+ Schema for creating a new QR code.
+ Only one of foodcourt_id, qsr_id, nightclub_id, or restaurant_id should be present.
+ """
+
+ class Config:
+ from_attributes = True
+
+class QRCodeRead(QRCodeBase):
+ id: UUID # Automatically added by the model
+
+ class Config:
+ from_attributes = True
\ No newline at end of file
diff --git a/backend/app/schema/venue.py b/backend/app/schema/venue.py
new file mode 100644
index 0000000000..cfefbda373
--- /dev/null
+++ b/backend/app/schema/venue.py
@@ -0,0 +1,40 @@
+from typing import Optional
+import uuid
+from app.models.venue import FoodcourtBase, NightclubBase, QSRBase, RestaurantBase
+
+class RestaurantRead(RestaurantBase):
+ id: Optional[uuid.UUID]
+ class Config:
+ from_attributes = True
+
+class RestaurantCreate(RestaurantBase):
+ class Config:
+ from_attributes = True
+
+class NightclubRead(NightclubBase):
+ id: Optional[uuid.UUID]
+ class Config:
+ from_attributes = True
+
+class NightclubCreate(NightclubBase):
+ class Config:
+ from_attributes = True
+
+class QSRRead(QSRBase):
+ id: Optional[uuid.UUID]
+ class Config:
+ from_attributes = True
+
+class QSRCreate(QSRBase):
+ class Config:
+ from_attributes = True
+
+
+class FoodcourtRead(FoodcourtBase):
+ id: Optional[uuid.UUID]
+ class Config:
+ from_attributes = True
+
+class FoodcourtCreate(FoodcourtBase):
+ class Config:
+ from_attributes = True
\ No newline at end of file
diff --git a/backend/app/static/landing_page.html b/backend/app/static/landing_page.html
new file mode 100644
index 0000000000..2bed0ef319
--- /dev/null
+++ b/backend/app/static/landing_page.html
@@ -0,0 +1,48 @@
+
+
+
+
+
+ Redirecting...
+
+
+
+ Redirecting...
+
+
\ No newline at end of file
diff --git a/backend/app/utils/__init__.py b/backend/app/utils/__init__.py
new file mode 100644
index 0000000000..73b91aab81
--- /dev/null
+++ b/backend/app/utils/__init__.py
@@ -0,0 +1 @@
+from .h3_utils import get_h3_index, is_within_radius
\ No newline at end of file
diff --git a/backend/app/utils/h3_utils.py b/backend/app/utils/h3_utils.py
new file mode 100644
index 0000000000..2cbbd56055
--- /dev/null
+++ b/backend/app/utils/h3_utils.py
@@ -0,0 +1,7 @@
+import h3
+
+def get_h3_index(latitude: float, longitude: float, resolution: int = 9) -> str:
+ return h3.geo_to_h3(latitude, longitude, resolution)
+
+def is_within_radius(user_h3_index: str, poster_h3_index: str, radius: int) -> bool:
+ return h3.h3_distance(user_h3_index, poster_h3_index) <= radius
diff --git a/backend/poetry.lock b/backend/poetry.lock
index f56ce480f0..bcfb89c0df 100644
--- a/backend/poetry.lock
+++ b/backend/poetry.lock
@@ -1,5 +1,45 @@
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
+[[package]]
+name = "aiofiles"
+version = "24.1.0"
+description = "File support for asyncio."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"},
+ {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"},
+]
+
+[[package]]
+name = "aioredis"
+version = "1.3.1"
+description = "asyncio (PEP 3156) Redis support"
+optional = false
+python-versions = "*"
+files = [
+ {file = "aioredis-1.3.1-py3-none-any.whl", hash = "sha256:b61808d7e97b7cd5a92ed574937a079c9387fdadd22bfbfa7ad2fd319ecc26e3"},
+ {file = "aioredis-1.3.1.tar.gz", hash = "sha256:15f8af30b044c771aee6787e5ec24694c048184c7b9e54c3b60c750a4b93273a"},
+]
+
+[package.dependencies]
+async-timeout = "*"
+hiredis = "*"
+
+[[package]]
+name = "aiosqlite"
+version = "0.17.0"
+description = "asyncio bridge to the standard sqlite3 module"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "aiosqlite-0.17.0-py3-none-any.whl", hash = "sha256:6c49dc6d3405929b1d08eeccc72306d3677503cc5e5e43771efc1e00232e8231"},
+ {file = "aiosqlite-0.17.0.tar.gz", hash = "sha256:f0e6acc24bc4864149267ac82fb46dfb3be4455f99fe21df82609cc6e6baee51"},
+]
+
+[package.dependencies]
+typing_extensions = ">=3.7.2"
+
[[package]]
name = "alembic"
version = "1.13.2"
@@ -52,34 +92,179 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
trio = ["trio (>=0.23)"]
+[[package]]
+name = "argon2-cffi"
+version = "23.1.0"
+description = "Argon2 for Python"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"},
+ {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"},
+]
+
+[package.dependencies]
+argon2-cffi-bindings = "*"
+
+[package.extras]
+dev = ["argon2-cffi[tests,typing]", "tox (>4)"]
+docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"]
+tests = ["hypothesis", "pytest"]
+typing = ["mypy"]
+
+[[package]]
+name = "argon2-cffi-bindings"
+version = "21.2.0"
+description = "Low-level CFFI bindings for Argon2"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"},
+ {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"},
+ {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"},
+ {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"},
+ {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"},
+ {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"},
+ {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"},
+ {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"},
+ {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"},
+ {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"},
+ {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"},
+ {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"},
+ {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"},
+]
+
+[package.dependencies]
+cffi = ">=1.0.1"
+
+[package.extras]
+dev = ["cogapp", "pre-commit", "pytest", "wheel"]
+tests = ["pytest"]
+
+[[package]]
+name = "async-timeout"
+version = "4.0.3"
+description = "Timeout context manager for asyncio programs"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
+ {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
+]
+
+[[package]]
+name = "asyncpg"
+version = "0.29.0"
+description = "An asyncio PostgreSQL driver"
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "asyncpg-0.29.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72fd0ef9f00aeed37179c62282a3d14262dbbafb74ec0ba16e1b1864d8a12169"},
+ {file = "asyncpg-0.29.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52e8f8f9ff6e21f9b39ca9f8e3e33a5fcdceaf5667a8c5c32bee158e313be385"},
+ {file = "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e6823a7012be8b68301342ba33b4740e5a166f6bbda0aee32bc01638491a22"},
+ {file = "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:746e80d83ad5d5464cfbf94315eb6744222ab00aa4e522b704322fb182b83610"},
+ {file = "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ff8e8109cd6a46ff852a5e6bab8b0a047d7ea42fcb7ca5ae6eaae97d8eacf397"},
+ {file = "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:97eb024685b1d7e72b1972863de527c11ff87960837919dac6e34754768098eb"},
+ {file = "asyncpg-0.29.0-cp310-cp310-win32.whl", hash = "sha256:5bbb7f2cafd8d1fa3e65431833de2642f4b2124be61a449fa064e1a08d27e449"},
+ {file = "asyncpg-0.29.0-cp310-cp310-win_amd64.whl", hash = "sha256:76c3ac6530904838a4b650b2880f8e7af938ee049e769ec2fba7cd66469d7772"},
+ {file = "asyncpg-0.29.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4900ee08e85af01adb207519bb4e14b1cae8fd21e0ccf80fac6aa60b6da37b4"},
+ {file = "asyncpg-0.29.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a65c1dcd820d5aea7c7d82a3fdcb70e096f8f70d1a8bf93eb458e49bfad036ac"},
+ {file = "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b52e46f165585fd6af4863f268566668407c76b2c72d366bb8b522fa66f1870"},
+ {file = "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc600ee8ef3dd38b8d67421359779f8ccec30b463e7aec7ed481c8346decf99f"},
+ {file = "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:039a261af4f38f949095e1e780bae84a25ffe3e370175193174eb08d3cecab23"},
+ {file = "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6feaf2d8f9138d190e5ec4390c1715c3e87b37715cd69b2c3dfca616134efd2b"},
+ {file = "asyncpg-0.29.0-cp311-cp311-win32.whl", hash = "sha256:1e186427c88225ef730555f5fdda6c1812daa884064bfe6bc462fd3a71c4b675"},
+ {file = "asyncpg-0.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfe73ffae35f518cfd6e4e5f5abb2618ceb5ef02a2365ce64f132601000587d3"},
+ {file = "asyncpg-0.29.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6011b0dc29886ab424dc042bf9eeb507670a3b40aece3439944006aafe023178"},
+ {file = "asyncpg-0.29.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b544ffc66b039d5ec5a7454667f855f7fec08e0dfaf5a5490dfafbb7abbd2cfb"},
+ {file = "asyncpg-0.29.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d84156d5fb530b06c493f9e7635aa18f518fa1d1395ef240d211cb563c4e2364"},
+ {file = "asyncpg-0.29.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54858bc25b49d1114178d65a88e48ad50cb2b6f3e475caa0f0c092d5f527c106"},
+ {file = "asyncpg-0.29.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bde17a1861cf10d5afce80a36fca736a86769ab3579532c03e45f83ba8a09c59"},
+ {file = "asyncpg-0.29.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:37a2ec1b9ff88d8773d3eb6d3784dc7e3fee7756a5317b67f923172a4748a175"},
+ {file = "asyncpg-0.29.0-cp312-cp312-win32.whl", hash = "sha256:bb1292d9fad43112a85e98ecdc2e051602bce97c199920586be83254d9dafc02"},
+ {file = "asyncpg-0.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:2245be8ec5047a605e0b454c894e54bf2ec787ac04b1cb7e0d3c67aa1e32f0fe"},
+ {file = "asyncpg-0.29.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0009a300cae37b8c525e5b449233d59cd9868fd35431abc470a3e364d2b85cb9"},
+ {file = "asyncpg-0.29.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cad1324dbb33f3ca0cd2074d5114354ed3be2b94d48ddfd88af75ebda7c43cc"},
+ {file = "asyncpg-0.29.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:012d01df61e009015944ac7543d6ee30c2dc1eb2f6b10b62a3f598beb6531548"},
+ {file = "asyncpg-0.29.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000c996c53c04770798053e1730d34e30cb645ad95a63265aec82da9093d88e7"},
+ {file = "asyncpg-0.29.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e0bfe9c4d3429706cf70d3249089de14d6a01192d617e9093a8e941fea8ee775"},
+ {file = "asyncpg-0.29.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:642a36eb41b6313ffa328e8a5c5c2b5bea6ee138546c9c3cf1bffaad8ee36dd9"},
+ {file = "asyncpg-0.29.0-cp38-cp38-win32.whl", hash = "sha256:a921372bbd0aa3a5822dd0409da61b4cd50df89ae85150149f8c119f23e8c408"},
+ {file = "asyncpg-0.29.0-cp38-cp38-win_amd64.whl", hash = "sha256:103aad2b92d1506700cbf51cd8bb5441e7e72e87a7b3a2ca4e32c840f051a6a3"},
+ {file = "asyncpg-0.29.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5340dd515d7e52f4c11ada32171d87c05570479dc01dc66d03ee3e150fb695da"},
+ {file = "asyncpg-0.29.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e17b52c6cf83e170d3d865571ba574577ab8e533e7361a2b8ce6157d02c665d3"},
+ {file = "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f100d23f273555f4b19b74a96840aa27b85e99ba4b1f18d4ebff0734e78dc090"},
+ {file = "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48e7c58b516057126b363cec8ca02b804644fd012ef8e6c7e23386b7d5e6ce83"},
+ {file = "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f9ea3f24eb4c49a615573724d88a48bd1b7821c890c2effe04f05382ed9e8810"},
+ {file = "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8d36c7f14a22ec9e928f15f92a48207546ffe68bc412f3be718eedccdf10dc5c"},
+ {file = "asyncpg-0.29.0-cp39-cp39-win32.whl", hash = "sha256:797ab8123ebaed304a1fad4d7576d5376c3a006a4100380fb9d517f0b59c1ab2"},
+ {file = "asyncpg-0.29.0-cp39-cp39-win_amd64.whl", hash = "sha256:cce08a178858b426ae1aa8409b5cc171def45d4293626e7aa6510696d46decd8"},
+ {file = "asyncpg-0.29.0.tar.gz", hash = "sha256:d1c49e1f44fffafd9a55e1a9b101590859d881d639ea2922516f5d9c512d354e"},
+]
+
+[package.dependencies]
+async-timeout = {version = ">=4.0.3", markers = "python_version < \"3.12.0\""}
+
+[package.extras]
+docs = ["Sphinx (>=5.3.0,<5.4.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"]
+test = ["flake8 (>=6.1,<7.0)", "uvloop (>=0.15.3)"]
+
+[[package]]
+name = "babel"
+version = "2.16.0"
+description = "Internationalization utilities"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"},
+ {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"},
+]
+
+[package.extras]
+dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"]
+
[[package]]
name = "bcrypt"
-version = "4.0.1"
+version = "4.1.2"
description = "Modern password hashing for your software and your servers"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
files = [
- {file = "bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f"},
- {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0"},
- {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410"},
- {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344"},
- {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a"},
- {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3"},
- {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2"},
- {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535"},
- {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e"},
- {file = "bcrypt-4.0.1-cp36-abi3-win32.whl", hash = "sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab"},
- {file = "bcrypt-4.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9"},
- {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c"},
- {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b"},
- {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d"},
- {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d"},
- {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215"},
- {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c"},
- {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda"},
- {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665"},
- {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71"},
- {file = "bcrypt-4.0.1.tar.gz", hash = "sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd"},
+ {file = "bcrypt-4.1.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:ac621c093edb28200728a9cca214d7e838529e557027ef0581685909acd28b5e"},
+ {file = "bcrypt-4.1.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea505c97a5c465ab8c3ba75c0805a102ce526695cd6818c6de3b1a38f6f60da1"},
+ {file = "bcrypt-4.1.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57fa9442758da926ed33a91644649d3e340a71e2d0a5a8de064fb621fd5a3326"},
+ {file = "bcrypt-4.1.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb3bd3321517916696233b5e0c67fd7d6281f0ef48e66812db35fc963a422a1c"},
+ {file = "bcrypt-4.1.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6cad43d8c63f34b26aef462b6f5e44fdcf9860b723d2453b5d391258c4c8e966"},
+ {file = "bcrypt-4.1.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:44290ccc827d3a24604f2c8bcd00d0da349e336e6503656cb8192133e27335e2"},
+ {file = "bcrypt-4.1.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:732b3920a08eacf12f93e6b04ea276c489f1c8fb49344f564cca2adb663b3e4c"},
+ {file = "bcrypt-4.1.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1c28973decf4e0e69cee78c68e30a523be441972c826703bb93099868a8ff5b5"},
+ {file = "bcrypt-4.1.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b8df79979c5bae07f1db22dcc49cc5bccf08a0380ca5c6f391cbb5790355c0b0"},
+ {file = "bcrypt-4.1.2-cp37-abi3-win32.whl", hash = "sha256:fbe188b878313d01b7718390f31528be4010fed1faa798c5a1d0469c9c48c369"},
+ {file = "bcrypt-4.1.2-cp37-abi3-win_amd64.whl", hash = "sha256:9800ae5bd5077b13725e2e3934aa3c9c37e49d3ea3d06318010aa40f54c63551"},
+ {file = "bcrypt-4.1.2-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:71b8be82bc46cedd61a9f4ccb6c1a493211d031415a34adde3669ee1b0afbb63"},
+ {file = "bcrypt-4.1.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e3c6642077b0c8092580c819c1684161262b2e30c4f45deb000c38947bf483"},
+ {file = "bcrypt-4.1.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:387e7e1af9a4dd636b9505a465032f2f5cb8e61ba1120e79a0e1cd0b512f3dfc"},
+ {file = "bcrypt-4.1.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f70d9c61f9c4ca7d57f3bfe88a5ccf62546ffbadf3681bb1e268d9d2e41c91a7"},
+ {file = "bcrypt-4.1.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2a298db2a8ab20056120b45e86c00a0a5eb50ec4075b6142db35f593b97cb3fb"},
+ {file = "bcrypt-4.1.2-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:ba55e40de38a24e2d78d34c2d36d6e864f93e0d79d0b6ce915e4335aa81d01b1"},
+ {file = "bcrypt-4.1.2-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3566a88234e8de2ccae31968127b0ecccbb4cddb629da744165db72b58d88ca4"},
+ {file = "bcrypt-4.1.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b90e216dc36864ae7132cb151ffe95155a37a14e0de3a8f64b49655dd959ff9c"},
+ {file = "bcrypt-4.1.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:69057b9fc5093ea1ab00dd24ede891f3e5e65bee040395fb1e66ee196f9c9b4a"},
+ {file = "bcrypt-4.1.2-cp39-abi3-win32.whl", hash = "sha256:02d9ef8915f72dd6daaef40e0baeef8a017ce624369f09754baf32bb32dba25f"},
+ {file = "bcrypt-4.1.2-cp39-abi3-win_amd64.whl", hash = "sha256:be3ab1071662f6065899fe08428e45c16aa36e28bc42921c4901a191fda6ee42"},
+ {file = "bcrypt-4.1.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d75fc8cd0ba23f97bae88a6ec04e9e5351ff3c6ad06f38fe32ba50cbd0d11946"},
+ {file = "bcrypt-4.1.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:a97e07e83e3262599434816f631cc4c7ca2aa8e9c072c1b1a7fec2ae809a1d2d"},
+ {file = "bcrypt-4.1.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e51c42750b7585cee7892c2614be0d14107fad9581d1738d954a262556dd1aab"},
+ {file = "bcrypt-4.1.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ba4e4cc26610581a6329b3937e02d319f5ad4b85b074846bf4fef8a8cf51e7bb"},
+ {file = "bcrypt-4.1.2.tar.gz", hash = "sha256:33313a1200a3ae90b75587ceac502b048b840fc69e7f7a0905b5f87fac7a1258"},
]
[package.extras]
@@ -108,6 +293,85 @@ files = [
{file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"},
]
+[[package]]
+name = "cffi"
+version = "1.17.1"
+description = "Foreign Function Interface for Python calling C code."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
+ {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
+ {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
+ {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
+ {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
+ {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
+ {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
+ {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
+ {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
+ {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
+ {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
+ {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
+ {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
+ {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
+ {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
+ {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
+ {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
+ {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
+ {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
+ {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
+ {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"},
+ {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"},
+ {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"},
+ {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
+ {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
+ {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
+ {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
+ {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
+]
+
+[package.dependencies]
+pycparser = "*"
+
[[package]]
name = "cfgv"
version = "3.4.0"
@@ -318,6 +582,55 @@ files = [
[package.extras]
toml = ["tomli"]
+[[package]]
+name = "cryptography"
+version = "43.0.1"
+description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"},
+ {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"},
+ {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"},
+ {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"},
+ {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"},
+ {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"},
+ {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"},
+ {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"},
+ {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"},
+ {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"},
+ {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"},
+ {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"},
+ {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"},
+ {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"},
+ {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"},
+ {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"},
+ {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"},
+ {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"},
+ {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"},
+ {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"},
+ {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"},
+ {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"},
+ {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"},
+ {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"},
+ {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"},
+ {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"},
+ {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"},
+]
+
+[package.dependencies]
+cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
+
+[package.extras]
+docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
+docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"]
+nox = ["nox"]
+pep8test = ["check-sdist", "click", "mypy", "ruff"]
+sdist = ["build"]
+ssh = ["bcrypt (>=3.1.5)"]
+test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
+test-randomorder = ["pytest-randomly"]
+
[[package]]
name = "cssselect"
version = "1.2.0"
@@ -380,13 +693,13 @@ wmi = ["wmi (>=1.5.1)"]
[[package]]
name = "email-validator"
-version = "2.2.0"
+version = "2.1.2"
description = "A robust email address syntax and deliverability validation library."
optional = false
python-versions = ">=3.8"
files = [
- {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"},
- {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"},
+ {file = "email_validator-2.1.2-py3-none-any.whl", hash = "sha256:d89f6324e13b1e39889eab7f9ca2f91dc9aebb6fa50a6d8bd4329ab50f251115"},
+ {file = "email_validator-2.1.2.tar.gz", hash = "sha256:14c0f3d343c4beda37400421b39fa411bbe33a75df20825df73ad53e06a9f04c"},
]
[package.dependencies]
@@ -445,6 +758,68 @@ typing-extensions = ">=4.8.0"
[package.extras]
all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
+[[package]]
+name = "fastapi-admin"
+version = "1.0.4"
+description = "A fast admin dashboard based on FastAPI and TortoiseORM with tabler ui, inspired by Django admin."
+optional = false
+python-versions = ">=3.7,<4.0"
+files = [
+ {file = "fastapi-admin-1.0.4.tar.gz", hash = "sha256:d45cb23a23fc2bbffb0e8adfb1362350a1fe808f47912253c1f067f7d7745d88"},
+ {file = "fastapi_admin-1.0.4-py3-none-any.whl", hash = "sha256:0b00dd2d72bbb5af50847cd4c49261aab999eeba7d8371786b822dce4b97ef0d"},
+]
+
+[package.dependencies]
+aiofiles = "*"
+aioredis = "*"
+Babel = "*"
+bcrypt = "*"
+fastapi = "*"
+jinja2 = "*"
+pendulum = "*"
+python-multipart = "*"
+tortoise-orm = "*"
+uvicorn = {version = "*", extras = ["standard"]}
+
+[[package]]
+name = "fastapi-cache"
+version = "0.1.0"
+description = "FastAPI simple cache"
+optional = false
+python-versions = "*"
+files = [
+ {file = "fastapi-cache-0.1.0.tar.gz", hash = "sha256:1f57e6e666672c84e3dd5d4141ec808d5339d158e10c87a87eb9ce11ff8b1735"},
+]
+
+[package.dependencies]
+aioredis = "1.3.1"
+
+[[package]]
+name = "fastapi-users"
+version = "13.0.0"
+description = "Ready-to-use and customizable users management for FastAPI"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "fastapi_users-13.0.0-py3-none-any.whl", hash = "sha256:e6246529e3080a5b50e5afeed1e996663b661f1dc791a1ac478925cb5bfc0fa0"},
+ {file = "fastapi_users-13.0.0.tar.gz", hash = "sha256:b397c815b7051c8fd4b560fbeee707acd28e00bd3e8f25c292ad158a1e47e884"},
+]
+
+[package.dependencies]
+email-validator = ">=1.1.0,<2.2"
+fastapi = ">=0.65.2"
+httpx-oauth = {version = ">=0.13", optional = true, markers = "extra == \"oauth\""}
+makefun = ">=1.11.2,<2.0.0"
+pwdlib = {version = "0.2.0", extras = ["argon2", "bcrypt"]}
+pyjwt = {version = "2.8.0", extras = ["crypto"]}
+python-multipart = "0.0.9"
+
+[package.extras]
+beanie = ["fastapi-users-db-beanie (>=3.0.0)"]
+oauth = ["httpx-oauth (>=0.13)"]
+redis = ["redis (>=4.3.3,<6.0.0)"]
+sqlalchemy = ["fastapi-users-db-sqlalchemy (>=6.0.0)"]
+
[[package]]
name = "filelock"
version = "3.15.4"
@@ -564,6 +939,163 @@ files = [
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
]
+[[package]]
+name = "h3"
+version = "3.7.7"
+description = "Hierarchical hexagonal geospatial indexing system"
+optional = false
+python-versions = "*"
+files = [
+ {file = "h3-3.7.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:951ecc9da0bcd5091670b13636928747bc98bc76891da0fa725524ec017cd9de"},
+ {file = "h3-3.7.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:26b9dd605541223ef927cc913deccb236cee024b16032f4a3e4387e2791479f2"},
+ {file = "h3-3.7.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:996ebb32dc26dd607af7493149f94ce316117be6f42971f7b33bbd326ec695d2"},
+ {file = "h3-3.7.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa2a4aa888cd9476788b874b4e11e178293f5b86e8461c36596bf183c242d417"},
+ {file = "h3-3.7.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0256e42687470c6f0044ca78fe375fe32a654be8b5a8313b4a68f52f513389c6"},
+ {file = "h3-3.7.7-cp310-cp310-win_amd64.whl", hash = "sha256:a3e2bc125490f900e0513c30480722f129bab1415f23040b6cd3a3f8d5a39336"},
+ {file = "h3-3.7.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7d59018a50cd3b6d0ff0b18a54fdfcbaf2f79c13c831842f54fd2780c4b561ea"},
+ {file = "h3-3.7.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e74526d941c1656fe162cc63b459b61aa83a15e257e9477b1570f26c544b51a"},
+ {file = "h3-3.7.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c7398dbab685fcf3fe92f7c4c5901ab258bc66f7fa05fd1da8693375a10a549"},
+ {file = "h3-3.7.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d22ea488ab5fe01c94070e9a6b3222916905a4d3f7a9d33cb2298c93fa0ffd3"},
+ {file = "h3-3.7.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c94836155e8169be393980fc059f06481a14dd1913bd9cba609f6f1e8864c171"},
+ {file = "h3-3.7.7-cp311-cp311-win_amd64.whl", hash = "sha256:836e74313ff55324485cd7e07783bc67df3191ec08a318035d7cd8ee0b0badab"},
+ {file = "h3-3.7.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:51c2f63ef5a57e4b18ebc9c0eb56656433e280ec45ab487a514127bb6e7d6a1f"},
+ {file = "h3-3.7.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d6e38dea47c220d9802af8e8bebc806f9f39358aee07b736191ff21e2c9921d"},
+ {file = "h3-3.7.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e408342e94f558802a97bfcbe1baae2af8b1fd926ad9041d970ff9dbd0502099"},
+ {file = "h3-3.7.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:644c3c84585aa4df62e81bc54fd305c4d6686324731de230b0ddbd7036ed172c"},
+ {file = "h3-3.7.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bb4a3d5e82d0c89512dc71b4eac17976a29be29da250ba76bc94bc5b9e824f0e"},
+ {file = "h3-3.7.7-cp312-cp312-win_amd64.whl", hash = "sha256:2ccff5f02589e80202597ed0b9f61ebd114e262e7dd0fe88059298602898192f"},
+ {file = "h3-3.7.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ef2e71b619f984e71c4bd9d128152e2c7e3e788e2d2ec571b32cef1d295ddf38"},
+ {file = "h3-3.7.7-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cb13f0213ed6da80e739355e5b62cfc81b7b1469af997be3384a6cbc3a1a750"},
+ {file = "h3-3.7.7-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:701f72f703d892fb17e66b9fd7b6b2ad125e135b091eb7dd0ec11858b84d84d2"},
+ {file = "h3-3.7.7-cp36-cp36m-win_amd64.whl", hash = "sha256:796622be7cb052690404c0ac03768183e51ae22505ce4a424b4537b2b7609fba"},
+ {file = "h3-3.7.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bcd88a72d6aa97d0f3b3b87b7bfd9725a8909501e6cb9d0057d5b690b6bb37b0"},
+ {file = "h3-3.7.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7358ba3f91193a2551c4a8d7ad7fd348e567b3a3581c9c161630029dfb23e07"},
+ {file = "h3-3.7.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8f34b204edc2e8f7d99a6db4ed1b5d202b7ea3ec6817d373ec432dee14efe04"},
+ {file = "h3-3.7.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aa0f8ce89b5e694815ee7a5172a782d58f2652267329de7008354b110b53955"},
+ {file = "h3-3.7.7-cp37-cp37m-win_amd64.whl", hash = "sha256:4c851baa1c2d4f29b01157ce2a4cdb1f3879fff5c36ff7861dad1526963a17a7"},
+ {file = "h3-3.7.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6f3a9da5472820b0a4add342f96fe52f65fbb8f46984383885738517b38af69e"},
+ {file = "h3-3.7.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1c57da776a3c1a01e2986b1f6a31d497ee0be8fcdbaaf9b23bb90f5a90eb8f0b"},
+ {file = "h3-3.7.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a5c0c0ddd9c57694ecc3b9ba99cbef2842882f8943d6edc676a365e139dbc6d"},
+ {file = "h3-3.7.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c1b5a0a652719b645387231bf6d7d4dd85150e4440a4ce72a804a10e86592ae"},
+ {file = "h3-3.7.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:64f76dc827fef94e9f43f95a1daea2e11f2ad2e8c55deac072f3d59bd62412d4"},
+ {file = "h3-3.7.7-cp38-cp38-win_amd64.whl", hash = "sha256:c993a36120d7f5607f24ba9e39caf715eaf9cd9d44f5d5660fd85e3f4e0c6bf7"},
+ {file = "h3-3.7.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eb154d2af699870b888e10476e327c895078009d2d2a6ef2d053d7dcf0e2c270"},
+ {file = "h3-3.7.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c96ad74e246bb7638d413efa8199dd4c58ee929424a4dcaadb16365195f77f87"},
+ {file = "h3-3.7.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52901f14f8b6e2c82075fd52c0e70176b868f621d47b5dc93f468c510e963722"},
+ {file = "h3-3.7.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9d82a0fcc647e7bab36ab2e7a7392d141edc95d113ccf972e0fb7b0ddf80a0"},
+ {file = "h3-3.7.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9f4417d09acb36f0452346052f576923d6e4334bff3459f217d6278d40397424"},
+ {file = "h3-3.7.7-cp39-cp39-win_amd64.whl", hash = "sha256:7ae774cd43b057f68dc10c99e4522fa40ed6b32ab90b2df0025595ffa15e77a0"},
+ {file = "h3-3.7.7.tar.gz", hash = "sha256:33d141c3cef0725a881771fd8cb80c06a0db84a6e4ca5c647ce095ae07c61e94"},
+]
+
+[package.extras]
+all = ["flake8", "numpy", "pylint", "pytest", "pytest-cov"]
+numpy = ["numpy"]
+test = ["flake8", "pylint", "pytest", "pytest-cov"]
+
+[[package]]
+name = "hiredis"
+version = "3.0.0"
+description = "Python wrapper for hiredis"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "hiredis-3.0.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:4b182791c41c5eb1d9ed736f0ff81694b06937ca14b0d4dadde5dadba7ff6dae"},
+ {file = "hiredis-3.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:13c275b483a052dd645eb2cb60d6380f1f5215e4c22d6207e17b86be6dd87ffa"},
+ {file = "hiredis-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c1018cc7f12824506f165027eabb302735b49e63af73eb4d5450c66c88f47026"},
+ {file = "hiredis-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83a29cc7b21b746cb6a480189e49f49b2072812c445e66a9e38d2004d496b81c"},
+ {file = "hiredis-3.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e241fab6332e8fb5f14af00a4a9c6aefa22f19a336c069b7ddbf28ef8341e8d6"},
+ {file = "hiredis-3.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1fb8de899f0145d6c4d5d4bd0ee88a78eb980a7ffabd51e9889251b8f58f1785"},
+ {file = "hiredis-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b23291951959141173eec10f8573538e9349fa27f47a0c34323d1970bf891ee5"},
+ {file = "hiredis-3.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e421ac9e4b5efc11705a0d5149e641d4defdc07077f748667f359e60dc904420"},
+ {file = "hiredis-3.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:77c8006c12154c37691b24ff293c077300c22944018c3ff70094a33e10c1d795"},
+ {file = "hiredis-3.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:41afc0d3c18b59eb50970479a9c0e5544fb4b95e3a79cf2fbaece6ddefb926fe"},
+ {file = "hiredis-3.0.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:04ccae6dcd9647eae6025425ab64edb4d79fde8b9e6e115ebfabc6830170e3b2"},
+ {file = "hiredis-3.0.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:fe91d62b0594db5ea7d23fc2192182b1a7b6973f628a9b8b2e0a42a2be721ac6"},
+ {file = "hiredis-3.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:99516d99316062824a24d145d694f5b0d030c80da693ea6f8c4ecf71a251d8bb"},
+ {file = "hiredis-3.0.0-cp310-cp310-win32.whl", hash = "sha256:562eaf820de045eb487afaa37e6293fe7eceb5b25e158b5a1974b7e40bf04543"},
+ {file = "hiredis-3.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a1c81c89ed765198da27412aa21478f30d54ef69bf5e4480089d9c3f77b8f882"},
+ {file = "hiredis-3.0.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:4664dedcd5933364756d7251a7ea86d60246ccf73a2e00912872dacbfcef8978"},
+ {file = "hiredis-3.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:47de0bbccf4c8a9f99d82d225f7672b9dd690d8fd872007b933ef51a302c9fa6"},
+ {file = "hiredis-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e43679eca508ba8240d016d8cca9d27342d70184773c15bea78a23c87a1922f1"},
+ {file = "hiredis-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13c345e7278c210317e77e1934b27b61394fee0dec2e8bd47e71570900f75823"},
+ {file = "hiredis-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00018f22f38530768b73ea86c11f47e8d4df65facd4e562bd78773bd1baef35e"},
+ {file = "hiredis-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ea3a86405baa8eb0d3639ced6926ad03e07113de54cb00fd7510cb0db76a89d"},
+ {file = "hiredis-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c073848d2b1d5561f3903879ccf4e1a70c9b1e7566c7bdcc98d082fa3e7f0a1d"},
+ {file = "hiredis-3.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a8dffb5f5b3415a4669d25de48b617fd9d44b0bccfc4c2ab24b06406ecc9ecb"},
+ {file = "hiredis-3.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:22c17c96143c2a62dfd61b13803bc5de2ac526b8768d2141c018b965d0333b66"},
+ {file = "hiredis-3.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c3ece960008dab66c6b8bb3a1350764677ee7c74ccd6270aaf1b1caf9ccebb46"},
+ {file = "hiredis-3.0.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f75999ae00a920f7dce6ecae76fa5e8674a3110e5a75f12c7a2c75ae1af53396"},
+ {file = "hiredis-3.0.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e069967cbd5e1900aafc4b5943888f6d34937fc59bf8918a1a546cb729b4b1e4"},
+ {file = "hiredis-3.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0aacc0a78e1d94d843a6d191f224a35893e6bdfeb77a4a89264155015c65f126"},
+ {file = "hiredis-3.0.0-cp311-cp311-win32.whl", hash = "sha256:719c32147ba29528cb451f037bf837dcdda4ff3ddb6cdb12c4216b0973174718"},
+ {file = "hiredis-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:bdc144d56333c52c853c31b4e2e52cfbdb22d3da4374c00f5f3d67c42158970f"},
+ {file = "hiredis-3.0.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:484025d2eb8f6348f7876fc5a2ee742f568915039fcb31b478fd5c242bb0fe3a"},
+ {file = "hiredis-3.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:fcdb552ffd97151dab8e7bc3ab556dfa1512556b48a367db94b5c20253a35ee1"},
+ {file = "hiredis-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bb6f9fd92f147ba11d338ef5c68af4fd2908739c09e51f186e1d90958c68cc1"},
+ {file = "hiredis-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa86bf9a0ed339ec9e8a9a9d0ae4dccd8671625c83f9f9f2640729b15e07fbfd"},
+ {file = "hiredis-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e194a0d5df9456995d8f510eab9f529213e7326af6b94770abf8f8b7952ddcaa"},
+ {file = "hiredis-3.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a1df39d74ec507d79c7a82c8063eee60bf80537cdeee652f576059b9cdd15c"},
+ {file = "hiredis-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f91456507427ba36fd81b2ca11053a8e112c775325acc74e993201ea912d63e9"},
+ {file = "hiredis-3.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9862db92ef67a8a02e0d5370f07d380e14577ecb281b79720e0d7a89aedb9ee5"},
+ {file = "hiredis-3.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d10fcd9e0eeab835f492832b2a6edb5940e2f1230155f33006a8dfd3bd2c94e4"},
+ {file = "hiredis-3.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:48727d7d405d03977d01885f317328dc21d639096308de126c2c4e9950cbd3c9"},
+ {file = "hiredis-3.0.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e0bb6102ebe2efecf8a3292c6660a0e6fac98176af6de67f020bea1c2343717"},
+ {file = "hiredis-3.0.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:df274e3abb4df40f4c7274dd3e587dfbb25691826c948bc98d5fead019dfb001"},
+ {file = "hiredis-3.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:034925b5fb514f7b11aac38cd55b3fd7e9d3af23bd6497f3f20aa5b8ba58e232"},
+ {file = "hiredis-3.0.0-cp312-cp312-win32.whl", hash = "sha256:120f2dda469b28d12ccff7c2230225162e174657b49cf4cd119db525414ae281"},
+ {file = "hiredis-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:e584fe5f4e6681d8762982be055f1534e0170f6308a7a90f58d737bab12ff6a8"},
+ {file = "hiredis-3.0.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:122171ff47d96ed8dd4bba6c0e41d8afaba3e8194949f7720431a62aa29d8895"},
+ {file = "hiredis-3.0.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:ba9fc605ac558f0de67463fb588722878641e6fa1dabcda979e8e69ff581d0bd"},
+ {file = "hiredis-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a631e2990b8be23178f655cae8ac6c7422af478c420dd54e25f2e26c29e766f1"},
+ {file = "hiredis-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63482db3fadebadc1d01ad33afa6045ebe2ea528eb77ccaabd33ee7d9c2bad48"},
+ {file = "hiredis-3.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f669212c390eebfbe03c4e20181f5970b82c5d0a0ad1df1785f7ffbe7d61150"},
+ {file = "hiredis-3.0.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a49ef161739f8018c69b371528bdb47d7342edfdee9ddc75a4d8caddf45a6e"},
+ {file = "hiredis-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98a152052b8878e5e43a2e3a14075218adafc759547c98668a21e9485882696c"},
+ {file = "hiredis-3.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50a196af0ce657fcde9bf8a0bbe1032e22c64d8fcec2bc926a35e7ff68b3a166"},
+ {file = "hiredis-3.0.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f2f312eef8aafc2255e3585dcf94d5da116c43ef837db91db9ecdc1bc930072d"},
+ {file = "hiredis-3.0.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:6ca41fa40fa019cde42c21add74aadd775e71458051a15a352eabeb12eb4d084"},
+ {file = "hiredis-3.0.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:6eecb343c70629f5af55a8b3e53264e44fa04e155ef7989de13668a0cb102a90"},
+ {file = "hiredis-3.0.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:c3fdad75e7837a475900a1d3a5cc09aa024293c3b0605155da2d42f41bc0e482"},
+ {file = "hiredis-3.0.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8854969e7480e8d61ed7549eb232d95082a743e94138d98d7222ba4e9f7ecacd"},
+ {file = "hiredis-3.0.0-cp38-cp38-win32.whl", hash = "sha256:f114a6c86edbf17554672b050cce72abf489fe58d583c7921904d5f1c9691605"},
+ {file = "hiredis-3.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:7d99b91e42217d7b4b63354b15b41ce960e27d216783e04c4a350224d55842a4"},
+ {file = "hiredis-3.0.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:4c6efcbb5687cf8d2aedcc2c3ed4ac6feae90b8547427d417111194873b66b06"},
+ {file = "hiredis-3.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5b5cff42a522a0d81c2ae7eae5e56d0ee7365e0c4ad50c4de467d8957aff4414"},
+ {file = "hiredis-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:82f794d564f4bc76b80c50b03267fe5d6589e93f08e66b7a2f674faa2fa76ebc"},
+ {file = "hiredis-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7a4c1791d7aa7e192f60fe028ae409f18ccdd540f8b1e6aeb0df7816c77e4a4"},
+ {file = "hiredis-3.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2537b2cd98192323fce4244c8edbf11f3cac548a9d633dbbb12b48702f379f4"},
+ {file = "hiredis-3.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fed69bbaa307040c62195a269f82fc3edf46b510a17abb6b30a15d7dab548df"},
+ {file = "hiredis-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:869f6d5537d243080f44253491bb30aa1ec3c21754003b3bddeadedeb65842b0"},
+ {file = "hiredis-3.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d435ae89073d7cd51e6b6bf78369c412216261c9c01662e7008ff00978153729"},
+ {file = "hiredis-3.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:204b79b30a0e6be0dc2301a4d385bb61472809f09c49f400497f1cdd5a165c66"},
+ {file = "hiredis-3.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3ea635101b739c12effd189cc19b2671c268abb03013fd1f6321ca29df3ca625"},
+ {file = "hiredis-3.0.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:f359175197fd833c8dd7a8c288f1516be45415bb5c939862ab60c2918e1e1943"},
+ {file = "hiredis-3.0.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac6d929cb33dd12ad3424b75725975f0a54b5b12dbff95f2a2d660c510aa106d"},
+ {file = "hiredis-3.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:100431e04d25a522ef2c3b94f294c4219c4de3bfc7d557b6253296145a144c11"},
+ {file = "hiredis-3.0.0-cp39-cp39-win32.whl", hash = "sha256:e1a9c14ae9573d172dc050a6f63a644457df5d01ec4d35a6a0f097f812930f83"},
+ {file = "hiredis-3.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:54a6dd7b478e6eb01ce15b3bb5bf771e108c6c148315bf194eb2ab776a3cac4d"},
+ {file = "hiredis-3.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:50da7a9edf371441dfcc56288d790985ee9840d982750580710a9789b8f4a290"},
+ {file = "hiredis-3.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9b285ef6bf1581310b0d5e8f6ce64f790a1c40e89c660e1320b35f7515433672"},
+ {file = "hiredis-3.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dcfa684966f25b335072115de2f920228a3c2caf79d4bfa2b30f6e4f674a948"},
+ {file = "hiredis-3.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a41be8af1fd78ca97bc948d789a09b730d1e7587d07ca53af05758f31f4b985d"},
+ {file = "hiredis-3.0.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:038756db735e417ab36ee6fd7725ce412385ed2bd0767e8179a4755ea11b804f"},
+ {file = "hiredis-3.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fcecbd39bd42cef905c0b51c9689c39d0cc8b88b1671e7f40d4fb213423aef3a"},
+ {file = "hiredis-3.0.0-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a131377493a59fb0f5eaeb2afd49c6540cafcfba5b0b3752bed707be9e7c4eaf"},
+ {file = "hiredis-3.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:3d22c53f0ec5c18ecb3d92aa9420563b1c5d657d53f01356114978107b00b860"},
+ {file = "hiredis-3.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8a91e9520fbc65a799943e5c970ffbcd67905744d8becf2e75f9f0a5e8414f0"},
+ {file = "hiredis-3.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dc8043959b50141df58ab4f398e8ae84c6f9e673a2c9407be65fc789138f4a6"},
+ {file = "hiredis-3.0.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51b99cfac514173d7b8abdfe10338193e8a0eccdfe1870b646009d2fb7cbe4b5"},
+ {file = "hiredis-3.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:fa1fcad89d8a41d8dc10b1e54951ec1e161deabd84ed5a2c95c3c7213bdb3514"},
+ {file = "hiredis-3.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:898636a06d9bf575d2c594129085ad6b713414038276a4bfc5db7646b8a5be78"},
+ {file = "hiredis-3.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:466f836dbcf86de3f9692097a7a01533dc9926986022c6617dc364a402b265c5"},
+ {file = "hiredis-3.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23142a8af92a13fc1e3f2ca1d940df3dcf2af1d176be41fe8d89e30a837a0b60"},
+ {file = "hiredis-3.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:793c80a3d6b0b0e8196a2d5de37a08330125668c8012922685e17aa9108c33ac"},
+ {file = "hiredis-3.0.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:467d28112c7faa29b7db743f40803d927c8591e9da02b6ce3d5fadc170a542a2"},
+ {file = "hiredis-3.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:dc384874a719c767b50a30750f937af18842ee5e288afba95a5a3ed703b1515a"},
+ {file = "hiredis-3.0.0.tar.gz", hash = "sha256:fed8581ae26345dea1f1e0d1a96e05041a727a45e7d8d459164583e23c6ac441"},
+]
+
[[package]]
name = "httpcore"
version = "1.0.5"
@@ -657,6 +1189,20 @@ cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"]
+[[package]]
+name = "httpx-oauth"
+version = "0.15.1"
+description = "Async OAuth client using HTTPX"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "httpx_oauth-0.15.1-py3-none-any.whl", hash = "sha256:89b45f250e93e42bbe9631adf349cab0e3d3ced958c07e06651735198d1bdf00"},
+ {file = "httpx_oauth-0.15.1.tar.gz", hash = "sha256:4094cf0938fc7252b5f5dfd62cd1ab5aee2fcb6734e621942ee17d1af4806b74"},
+]
+
+[package.dependencies]
+httpx = ">=0.18,<1.0.0"
+
[[package]]
name = "identify"
version = "2.6.0"
@@ -693,6 +1239,28 @@ files = [
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
]
+[[package]]
+name = "iso8601"
+version = "1.1.0"
+description = "Simple module to parse ISO 8601 dates"
+optional = false
+python-versions = ">=3.6.2,<4.0"
+files = [
+ {file = "iso8601-1.1.0-py3-none-any.whl", hash = "sha256:8400e90141bf792bce2634df533dc57e3bee19ea120a87bebcd3da89a58ad73f"},
+ {file = "iso8601-1.1.0.tar.gz", hash = "sha256:32811e7b81deee2063ea6d2e94f8819a86d1f3811e49d23623a41fa832bef03f"},
+]
+
+[[package]]
+name = "itsdangerous"
+version = "2.2.0"
+description = "Safely pass data to untrusted environments and back."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"},
+ {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"},
+]
+
[[package]]
name = "jinja2"
version = "3.1.4"
@@ -868,6 +1436,17 @@ html5 = ["html5lib"]
htmlsoup = ["BeautifulSoup4"]
source = ["Cython (>=3.0.10)"]
+[[package]]
+name = "makefun"
+version = "1.15.4"
+description = "Small library to dynamically create python functions."
+optional = false
+python-versions = "*"
+files = [
+ {file = "makefun-1.15.4-py2.py3-none-any.whl", hash = "sha256:945d078a7e01a903f2cbef738b33e0ebc52b8d35fb7e20c528ed87b5c80db5b7"},
+ {file = "makefun-1.15.4.tar.gz", hash = "sha256:9f9b9904e7c397759374a88f4c57781fbab2a458dec78df4b3ee6272cd9fb010"},
+]
+
[[package]]
name = "mako"
version = "1.3.5"
@@ -1036,6 +1615,23 @@ files = [
{file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
]
+[[package]]
+name = "otplessauthsdk"
+version = "0.3.3"
+description = "otpless-auth-sdk"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "OTPLessAuthSDK-0.3.3-py3-none-any.whl", hash = "sha256:7f698e19a7af3501d69b1b8ca8cf952bcaaa6d3a783a7cfc390c7e0c65dfdd7f"},
+ {file = "OTPLessAuthSDK-0.3.3.tar.gz", hash = "sha256:46126c5f6a5009d44b7f7adaf7e67567930de5be530a2f0edb49d8f764cfae22"},
+]
+
+[package.dependencies]
+cryptography = "*"
+PyJWT = "*"
+requests = "*"
+rsa = "*"
+
[[package]]
name = "packaging"
version = "24.1"
@@ -1067,6 +1663,105 @@ bcrypt = ["bcrypt (>=3.1.0)"]
build-docs = ["cloud-sptheme (>=1.10.1)", "sphinx (>=1.6)", "sphinxcontrib-fulltoc (>=1.2.0)"]
totp = ["cryptography"]
+[[package]]
+name = "pendulum"
+version = "3.0.0"
+description = "Python datetimes made easy"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pendulum-3.0.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2cf9e53ef11668e07f73190c805dbdf07a1939c3298b78d5a9203a86775d1bfd"},
+ {file = "pendulum-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fb551b9b5e6059377889d2d878d940fd0bbb80ae4810543db18e6f77b02c5ef6"},
+ {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c58227ac260d5b01fc1025176d7b31858c9f62595737f350d22124a9a3ad82d"},
+ {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60fb6f415fea93a11c52578eaa10594568a6716602be8430b167eb0d730f3332"},
+ {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b69f6b4dbcb86f2c2fe696ba991e67347bcf87fe601362a1aba6431454b46bde"},
+ {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:138afa9c373ee450ede206db5a5e9004fd3011b3c6bbe1e57015395cd076a09f"},
+ {file = "pendulum-3.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:83d9031f39c6da9677164241fd0d37fbfc9dc8ade7043b5d6d62f56e81af8ad2"},
+ {file = "pendulum-3.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c2308af4033fa534f089595bcd40a95a39988ce4059ccd3dc6acb9ef14ca44a"},
+ {file = "pendulum-3.0.0-cp310-none-win_amd64.whl", hash = "sha256:9a59637cdb8462bdf2dbcb9d389518c0263799189d773ad5c11db6b13064fa79"},
+ {file = "pendulum-3.0.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3725245c0352c95d6ca297193192020d1b0c0f83d5ee6bb09964edc2b5a2d508"},
+ {file = "pendulum-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6c035f03a3e565ed132927e2c1b691de0dbf4eb53b02a5a3c5a97e1a64e17bec"},
+ {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597e66e63cbd68dd6d58ac46cb7a92363d2088d37ccde2dae4332ef23e95cd00"},
+ {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99a0f8172e19f3f0c0e4ace0ad1595134d5243cf75985dc2233e8f9e8de263ca"},
+ {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:77d8839e20f54706aed425bec82a83b4aec74db07f26acd039905d1237a5e1d4"},
+ {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afde30e8146292b059020fbc8b6f8fd4a60ae7c5e6f0afef937bbb24880bdf01"},
+ {file = "pendulum-3.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:660434a6fcf6303c4efd36713ca9212c753140107ee169a3fc6c49c4711c2a05"},
+ {file = "pendulum-3.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dee9e5a48c6999dc1106eb7eea3e3a50e98a50651b72c08a87ee2154e544b33e"},
+ {file = "pendulum-3.0.0-cp311-none-win_amd64.whl", hash = "sha256:d4cdecde90aec2d67cebe4042fd2a87a4441cc02152ed7ed8fb3ebb110b94ec4"},
+ {file = "pendulum-3.0.0-cp311-none-win_arm64.whl", hash = "sha256:773c3bc4ddda2dda9f1b9d51fe06762f9200f3293d75c4660c19b2614b991d83"},
+ {file = "pendulum-3.0.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:409e64e41418c49f973d43a28afe5df1df4f1dd87c41c7c90f1a63f61ae0f1f7"},
+ {file = "pendulum-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a38ad2121c5ec7c4c190c7334e789c3b4624798859156b138fcc4d92295835dc"},
+ {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fde4d0b2024b9785f66b7f30ed59281bd60d63d9213cda0eb0910ead777f6d37"},
+ {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b2c5675769fb6d4c11238132962939b960fcb365436b6d623c5864287faa319"},
+ {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8af95e03e066826f0f4c65811cbee1b3123d4a45a1c3a2b4fc23c4b0dff893b5"},
+ {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2165a8f33cb15e06c67070b8afc87a62b85c5a273e3aaa6bc9d15c93a4920d6f"},
+ {file = "pendulum-3.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ad5e65b874b5e56bd942546ea7ba9dd1d6a25121db1c517700f1c9de91b28518"},
+ {file = "pendulum-3.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17fe4b2c844bbf5f0ece69cfd959fa02957c61317b2161763950d88fed8e13b9"},
+ {file = "pendulum-3.0.0-cp312-none-win_amd64.whl", hash = "sha256:78f8f4e7efe5066aca24a7a57511b9c2119f5c2b5eb81c46ff9222ce11e0a7a5"},
+ {file = "pendulum-3.0.0-cp312-none-win_arm64.whl", hash = "sha256:28f49d8d1e32aae9c284a90b6bb3873eee15ec6e1d9042edd611b22a94ac462f"},
+ {file = "pendulum-3.0.0-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:d4e2512f4e1a4670284a153b214db9719eb5d14ac55ada5b76cbdb8c5c00399d"},
+ {file = "pendulum-3.0.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:3d897eb50883cc58d9b92f6405245f84b9286cd2de6e8694cb9ea5cb15195a32"},
+ {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e169cc2ca419517f397811bbe4589cf3cd13fca6dc38bb352ba15ea90739ebb"},
+ {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17c3084a4524ebefd9255513692f7e7360e23c8853dc6f10c64cc184e1217ab"},
+ {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:826d6e258052715f64d05ae0fc9040c0151e6a87aae7c109ba9a0ed930ce4000"},
+ {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2aae97087872ef152a0c40e06100b3665d8cb86b59bc8471ca7c26132fccd0f"},
+ {file = "pendulum-3.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ac65eeec2250d03106b5e81284ad47f0d417ca299a45e89ccc69e36130ca8bc7"},
+ {file = "pendulum-3.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a5346d08f3f4a6e9e672187faa179c7bf9227897081d7121866358af369f44f9"},
+ {file = "pendulum-3.0.0-cp37-none-win_amd64.whl", hash = "sha256:235d64e87946d8f95c796af34818c76e0f88c94d624c268693c85b723b698aa9"},
+ {file = "pendulum-3.0.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:6a881d9c2a7f85bc9adafcfe671df5207f51f5715ae61f5d838b77a1356e8b7b"},
+ {file = "pendulum-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d7762d2076b9b1cb718a6631ad6c16c23fc3fac76cbb8c454e81e80be98daa34"},
+ {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e8e36a8130819d97a479a0e7bf379b66b3b1b520e5dc46bd7eb14634338df8c"},
+ {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7dc843253ac373358ffc0711960e2dd5b94ab67530a3e204d85c6e8cb2c5fa10"},
+ {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a78ad3635d609ceb1e97d6aedef6a6a6f93433ddb2312888e668365908c7120"},
+ {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b30a137e9e0d1f751e60e67d11fc67781a572db76b2296f7b4d44554761049d6"},
+ {file = "pendulum-3.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c95984037987f4a457bb760455d9ca80467be792236b69d0084f228a8ada0162"},
+ {file = "pendulum-3.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d29c6e578fe0f893766c0d286adbf0b3c726a4e2341eba0917ec79c50274ec16"},
+ {file = "pendulum-3.0.0-cp38-none-win_amd64.whl", hash = "sha256:deaba8e16dbfcb3d7a6b5fabdd5a38b7c982809567479987b9c89572df62e027"},
+ {file = "pendulum-3.0.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b11aceea5b20b4b5382962b321dbc354af0defe35daa84e9ff3aae3c230df694"},
+ {file = "pendulum-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a90d4d504e82ad236afac9adca4d6a19e4865f717034fc69bafb112c320dcc8f"},
+ {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:825799c6b66e3734227756fa746cc34b3549c48693325b8b9f823cb7d21b19ac"},
+ {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad769e98dc07972e24afe0cff8d365cb6f0ebc7e65620aa1976fcfbcadc4c6f3"},
+ {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6fc26907eb5fb8cc6188cc620bc2075a6c534d981a2f045daa5f79dfe50d512"},
+ {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c717eab1b6d898c00a3e0fa7781d615b5c5136bbd40abe82be100bb06df7a56"},
+ {file = "pendulum-3.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3ddd1d66d1a714ce43acfe337190be055cdc221d911fc886d5a3aae28e14b76d"},
+ {file = "pendulum-3.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:822172853d7a9cf6da95d7b66a16c7160cb99ae6df55d44373888181d7a06edc"},
+ {file = "pendulum-3.0.0-cp39-none-win_amd64.whl", hash = "sha256:840de1b49cf1ec54c225a2a6f4f0784d50bd47f68e41dc005b7f67c7d5b5f3ae"},
+ {file = "pendulum-3.0.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3b1f74d1e6ffe5d01d6023870e2ce5c2191486928823196f8575dcc786e107b1"},
+ {file = "pendulum-3.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:729e9f93756a2cdfa77d0fc82068346e9731c7e884097160603872686e570f07"},
+ {file = "pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e586acc0b450cd21cbf0db6bae386237011b75260a3adceddc4be15334689a9a"},
+ {file = "pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22e7944ffc1f0099a79ff468ee9630c73f8c7835cd76fdb57ef7320e6a409df4"},
+ {file = "pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fa30af36bd8e50686846bdace37cf6707bdd044e5cb6e1109acbad3277232e04"},
+ {file = "pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:440215347b11914ae707981b9a57ab9c7b6983ab0babde07063c6ee75c0dc6e7"},
+ {file = "pendulum-3.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:314c4038dc5e6a52991570f50edb2f08c339debdf8cea68ac355b32c4174e820"},
+ {file = "pendulum-3.0.0-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5acb1d386337415f74f4d1955c4ce8d0201978c162927d07df8eb0692b2d8533"},
+ {file = "pendulum-3.0.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a789e12fbdefaffb7b8ac67f9d8f22ba17a3050ceaaa635cd1cc4645773a4b1e"},
+ {file = "pendulum-3.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:860aa9b8a888e5913bd70d819306749e5eb488e6b99cd6c47beb701b22bdecf5"},
+ {file = "pendulum-3.0.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:5ebc65ea033ef0281368217fbf59f5cb05b338ac4dd23d60959c7afcd79a60a0"},
+ {file = "pendulum-3.0.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d9fef18ab0386ef6a9ac7bad7e43ded42c83ff7ad412f950633854f90d59afa8"},
+ {file = "pendulum-3.0.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1c134ba2f0571d0b68b83f6972e2307a55a5a849e7dac8505c715c531d2a8795"},
+ {file = "pendulum-3.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:385680812e7e18af200bb9b4a49777418c32422d05ad5a8eb85144c4a285907b"},
+ {file = "pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eec91cd87c59fb32ec49eb722f375bd58f4be790cae11c1b70fac3ee4f00da0"},
+ {file = "pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4386bffeca23c4b69ad50a36211f75b35a4deb6210bdca112ac3043deb7e494a"},
+ {file = "pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dfbcf1661d7146d7698da4b86e7f04814221081e9fe154183e34f4c5f5fa3bf8"},
+ {file = "pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:04a1094a5aa1daa34a6b57c865b25f691848c61583fb22722a4df5699f6bf74c"},
+ {file = "pendulum-3.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5b0ec85b9045bd49dd3a3493a5e7ddfd31c36a2a60da387c419fa04abcaecb23"},
+ {file = "pendulum-3.0.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0a15b90129765b705eb2039062a6daf4d22c4e28d1a54fa260892e8c3ae6e157"},
+ {file = "pendulum-3.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:bb8f6d7acd67a67d6fedd361ad2958ff0539445ef51cbe8cd288db4306503cd0"},
+ {file = "pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd69b15374bef7e4b4440612915315cc42e8575fcda2a3d7586a0d88192d0c88"},
+ {file = "pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc00f8110db6898360c53c812872662e077eaf9c75515d53ecc65d886eec209a"},
+ {file = "pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:83a44e8b40655d0ba565a5c3d1365d27e3e6778ae2a05b69124db9e471255c4a"},
+ {file = "pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1a3604e9fbc06b788041b2a8b78f75c243021e0f512447806a6d37ee5214905d"},
+ {file = "pendulum-3.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:92c307ae7accebd06cbae4729f0ba9fa724df5f7d91a0964b1b972a22baa482b"},
+ {file = "pendulum-3.0.0.tar.gz", hash = "sha256:5d034998dea404ec31fae27af6b22cff1708f830a1ed7353be4d1019bb9f584e"},
+]
+
+[package.dependencies]
+python-dateutil = ">=2.6"
+tzdata = ">=2020.1"
+
+[package.extras]
+test = ["time-machine (>=2.6.0)"]
+
[[package]]
name = "platformdirs"
version = "4.2.2"
@@ -1224,6 +1919,69 @@ files = [
{file = "psycopg_binary-3.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:921f0c7f39590763d64a619de84d1b142587acc70fd11cbb5ba8fa39786f3073"},
]
+[[package]]
+name = "psycopg2"
+version = "2.9.9"
+description = "psycopg2 - Python-PostgreSQL Database Adapter"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "psycopg2-2.9.9-cp310-cp310-win32.whl", hash = "sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516"},
+ {file = "psycopg2-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"},
+ {file = "psycopg2-2.9.9-cp311-cp311-win32.whl", hash = "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"},
+ {file = "psycopg2-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"},
+ {file = "psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"},
+ {file = "psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"},
+ {file = "psycopg2-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"},
+ {file = "psycopg2-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"},
+ {file = "psycopg2-2.9.9-cp38-cp38-win32.whl", hash = "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"},
+ {file = "psycopg2-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:bac58c024c9922c23550af2a581998624d6e02350f4ae9c5f0bc642c633a2d5e"},
+ {file = "psycopg2-2.9.9-cp39-cp39-win32.whl", hash = "sha256:c92811b2d4c9b6ea0285942b2e7cac98a59e166d59c588fe5cfe1eda58e72d59"},
+ {file = "psycopg2-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913"},
+ {file = "psycopg2-2.9.9.tar.gz", hash = "sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156"},
+]
+
+[[package]]
+name = "pwdlib"
+version = "0.2.0"
+description = "Modern password hashing for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pwdlib-0.2.0-py3-none-any.whl", hash = "sha256:be53812012ab66795a57ac9393a59716ae7c2b60841ed453eb1262017fdec144"},
+ {file = "pwdlib-0.2.0.tar.gz", hash = "sha256:b1bdafc064310eb6d3d07144a210267063ab4f45ac73a97be948e6589f74e861"},
+]
+
+[package.dependencies]
+argon2-cffi = {version = "23.1.0", optional = true, markers = "extra == \"argon2\""}
+bcrypt = {version = "4.1.2", optional = true, markers = "extra == \"bcrypt\""}
+
+[package.extras]
+argon2 = ["argon2-cffi (==23.1.0)"]
+bcrypt = ["bcrypt (==4.1.2)"]
+
+[[package]]
+name = "pyasn1"
+version = "0.6.1"
+description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"},
+ {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"},
+]
+
+[[package]]
+name = "pycparser"
+version = "2.22"
+description = "C parser in Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
+ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
+]
+
[[package]]
name = "pydantic"
version = "2.8.2"
@@ -1378,12 +2136,40 @@ files = [
{file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"},
]
+[package.dependencies]
+cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""}
+
[package.extras]
crypto = ["cryptography (>=3.4.0)"]
dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"]
docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"]
tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
+[[package]]
+name = "pyotp"
+version = "2.9.0"
+description = "Python One Time Password Library"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pyotp-2.9.0-py3-none-any.whl", hash = "sha256:81c2e5865b8ac55e825b0358e496e1d9387c811e85bb40e71a3b29b288963612"},
+ {file = "pyotp-2.9.0.tar.gz", hash = "sha256:346b6642e0dbdde3b4ff5a930b664ca82abfa116356ed48cc42c7d6590d36f63"},
+]
+
+[package.extras]
+test = ["coverage", "mypy", "ruff", "wheel"]
+
+[[package]]
+name = "pypika-tortoise"
+version = "0.1.6"
+description = "Forked from pypika and streamline just for tortoise-orm"
+optional = false
+python-versions = ">=3.7,<4.0"
+files = [
+ {file = "pypika-tortoise-0.1.6.tar.gz", hash = "sha256:d802868f479a708e3263724c7b5719a26ad79399b2a70cea065f4a4cadbebf36"},
+ {file = "pypika_tortoise-0.1.6-py3-none-any.whl", hash = "sha256:2d68bbb7e377673743cff42aa1059f3a80228d411fbcae591e4465e173109fd8"},
+]
+
[[package]]
name = "pytest"
version = "7.4.4"
@@ -1436,17 +2222,28 @@ cli = ["click (>=5.0)"]
[[package]]
name = "python-multipart"
-version = "0.0.7"
+version = "0.0.9"
description = "A streaming multipart parser for Python"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "python_multipart-0.0.7-py3-none-any.whl", hash = "sha256:b1fef9a53b74c795e2347daac8c54b252d9e0df9c619712691c1cc8021bd3c49"},
- {file = "python_multipart-0.0.7.tar.gz", hash = "sha256:288a6c39b06596c1b988bb6794c6fbc80e6c369e35e5062637df256bee0c9af9"},
+ {file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"},
+ {file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"},
]
[package.extras]
-dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatch", "invoke (==2.2.0)", "more-itertools (==4.3.0)", "pbr (==4.3.0)", "pluggy (==1.0.0)", "py (==1.11.0)", "pytest (==7.2.0)", "pytest-cov (==4.0.0)", "pytest-timeout (==2.1.0)", "pyyaml (==5.1)"]
+dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"]
+
+[[package]]
+name = "pytz"
+version = "2024.2"
+description = "World timezone definitions, modern and historical"
+optional = false
+python-versions = "*"
+files = [
+ {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"},
+ {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"},
+]
[[package]]
name = "pyyaml"
@@ -1508,6 +2305,24 @@ files = [
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
]
+[[package]]
+name = "redis"
+version = "5.0.8"
+description = "Python client for Redis database and key-value store"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "redis-5.0.8-py3-none-any.whl", hash = "sha256:56134ee08ea909106090934adc36f65c9bcbbaecea5b21ba704ba6fb561f8eb4"},
+ {file = "redis-5.0.8.tar.gz", hash = "sha256:0c5b10d387568dfe0698c6fad6615750c24170e548ca2deac10c649d463e9870"},
+]
+
+[package.dependencies]
+async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""}
+
+[package.extras]
+hiredis = ["hiredis (>1.0.0)"]
+ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"]
+
[[package]]
name = "requests"
version = "2.32.3"
@@ -1529,6 +2344,20 @@ urllib3 = ">=1.21.1,<3"
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+[[package]]
+name = "rsa"
+version = "4.9"
+description = "Pure-Python RSA implementation"
+optional = false
+python-versions = ">=3.6,<4"
+files = [
+ {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"},
+ {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"},
+]
+
+[package.dependencies]
+pyasn1 = ">=0.1.3"
+
[[package]]
name = "ruff"
version = "0.2.2"
@@ -1625,6 +2454,28 @@ files = [
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
]
+[[package]]
+name = "sqladmin"
+version = "0.19.0"
+description = "SQLAlchemy admin for FastAPI and Starlette"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "sqladmin-0.19.0-py3-none-any.whl", hash = "sha256:7549df159c1a9e65d2a9bf66ddca321e4c2aafef824faa23b881fa0aa08b88bf"},
+ {file = "sqladmin-0.19.0.tar.gz", hash = "sha256:edd7d1a16e61fc4edb428dc92a99e9f5b41252127a9d93637ce1d9b3eaa20877"},
+]
+
+[package.dependencies]
+itsdangerous = {version = "*", optional = true, markers = "extra == \"full\""}
+jinja2 = "*"
+python-multipart = "*"
+sqlalchemy = ">=1.4"
+starlette = "*"
+wtforms = ">=3.1,<3.2"
+
+[package.extras]
+full = ["itsdangerous"]
+
[[package]]
name = "sqlalchemy"
version = "2.0.31"
@@ -1770,6 +2621,32 @@ files = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
+[[package]]
+name = "tortoise-orm"
+version = "0.21.6"
+description = "Easy async ORM for python, built with relations in mind"
+optional = false
+python-versions = "<4.0,>=3.8"
+files = [
+ {file = "tortoise_orm-0.21.6-py3-none-any.whl", hash = "sha256:98fcf07dce3396075eac36b0d2b14d2267ff875d32455e03ee15e38de2f138df"},
+ {file = "tortoise_orm-0.21.6.tar.gz", hash = "sha256:0fbc718001647bf282c01eaaa360f94f1432c9281701244180703d48d58a88ec"},
+]
+
+[package.dependencies]
+aiosqlite = ">=0.16.0,<0.18.0"
+iso8601 = ">=1.0.2,<2.0.0"
+pydantic = ">=2.0,<2.7.0 || >2.7.0,<3.0"
+pypika-tortoise = ">=0.1.6,<0.2.0"
+pytz = "*"
+
+[package.extras]
+accel = ["ciso8601", "orjson", "uvloop"]
+aiomysql = ["aiomysql"]
+asyncmy = ["asyncmy (>=0.2.8,<0.3.0)"]
+asyncodbc = ["asyncodbc (>=0.1.1,<0.2.0)"]
+asyncpg = ["asyncpg"]
+psycopg = ["psycopg[binary,pool] (>=3.0.12,<4.0.0)"]
+
[[package]]
name = "types-passlib"
version = "1.7.7.20240327"
@@ -2078,7 +2955,24 @@ files = [
{file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"},
]
+[[package]]
+name = "wtforms"
+version = "3.1.2"
+description = "Form validation and rendering for Python web development."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "wtforms-3.1.2-py3-none-any.whl", hash = "sha256:bf831c042829c8cdbad74c27575098d541d039b1faa74c771545ecac916f2c07"},
+ {file = "wtforms-3.1.2.tar.gz", hash = "sha256:f8d76180d7239c94c6322f7990ae1216dae3659b7aa1cee94b6318bdffb474b9"},
+]
+
+[package.dependencies]
+markupsafe = "*"
+
+[package.extras]
+email = ["email-validator"]
+
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
-content-hash = "7ec220bee66b5bc207f9a8b2f4ca9100da0213bb9d0a407b51cac3dc8201e97c"
+content-hash = "be3f5a23911a1d2d631f15293704a2edb6c52602e70bf491d42e9e5b24be46a5"
diff --git a/backend/pyproject.toml b/backend/pyproject.toml
index 671a864645..45856e304b 100644
--- a/backend/pyproject.toml
+++ b/backend/pyproject.toml
@@ -8,12 +8,14 @@ authors = ["Admin "]
python = "^3.10"
uvicorn = {extras = ["standard"], version = "^0.24.0.post1"}
fastapi = "^0.109.1"
-python-multipart = "^0.0.7"
+python-multipart = "0.0.9"
email-validator = "^2.1.0.post1"
passlib = {extras = ["bcrypt"], version = "^1.7.4"}
tenacity = "^8.2.3"
pydantic = ">2.0"
emails = "^0.6"
+psycopg2 = "^2.9.6"
+h3 = "^3.7.7"
gunicorn = "^22.0.0"
jinja2 = "^3.1.4"
@@ -22,10 +24,18 @@ httpx = "^0.25.1"
psycopg = {extras = ["binary"], version = "^3.1.13"}
sqlmodel = "^0.0.21"
# Pin bcrypt until passlib supports the latest
-bcrypt = "4.0.1"
+bcrypt = "4.1.2"
pydantic-settings = "^2.2.1"
sentry-sdk = {extras = ["fastapi"], version = "^1.40.6"}
pyjwt = "^2.8.0"
+fastapi-cache = {extras = ["redis"], version = "^0.1.0"}
+pyotp = "^2.9.0"
+redis = "^5.0.8"
+fastapi-users = {extras = ["oauth"], version = "^13.0.0"}
+asyncpg = "^0.29.0"
+otplessauthsdk = "^0.3.3"
+fastapi-admin = "^1.0.4"
+sqladmin = {extras = ["full"], version = "^0.19.0"}
[tool.poetry.group.dev.dependencies]
pytest = "^7.4.3"
diff --git a/copier.yml b/copier.yml
index 5db3891c8d..f53c66bb2f 100644
--- a/copier.yml
+++ b/copier.yml
@@ -74,7 +74,6 @@ _exclude:
- poetry.lock
- .cache
- .venv
- # Frontend
# Logs
- logs
- "*.log"
diff --git a/deployment.md b/deployment.md
index 6bcbe40259..a0b8b0db17 100644
--- a/deployment.md
+++ b/deployment.md
@@ -284,8 +284,6 @@ Traefik UI: `https://traefik.fastapi-project.example.com`
### Production
-Frontend: `https://fastapi-project.example.com`
-
Backend API docs: `https://fastapi-project.example.com/docs`
Backend API base URL: `https://fastapi-project.example.com/api/`
@@ -294,8 +292,6 @@ Adminer: `https://adminer.fastapi-project.example.com`
### Staging
-Frontend: `https://staging.fastapi-project.example.com`
-
Backend API docs: `https://staging.fastapi-project.example.com/docs`
Backend API base URL: `https://staging.fastapi-project.example.com/api/`
diff --git a/development.md b/development.md
index 857a4e0a38..b4753b3902 100644
--- a/development.md
+++ b/development.md
@@ -146,13 +146,9 @@ The production or staging URLs would use these same paths, but with your own dom
Development URLs, for local development.
-Frontend: http://localhost
-
-Backend: http://localhost/api/
-
Automatic Interactive Docs (Swagger UI): http://localhost/docs
-Automatic Alternative Docs (ReDoc): http://localhost/redoc
+Automatic Alternative Docs (ReDoc): http://localhost/redoc
Adminer: http://localhost:8080
@@ -162,8 +158,6 @@ Traefik UI: http://localhost:8090
Development URLs, for local development.
-Frontend: http://localhost.tiangolo.com
-
Backend: http://localhost.tiangolo.com/api/
Automatic Interactive Docs (Swagger UI): http://localhost.tiangolo.com/docs
diff --git a/docker-compose.override.yml b/docker-compose.override.yml
index 418b535ab6..15f669bb68 100644
--- a/docker-compose.override.yml
+++ b/docker-compose.override.yml
@@ -74,14 +74,6 @@ services:
- "1080:1080"
- "1025:1025"
- frontend:
- restart: "no"
- build:
- context: ./frontend
- args:
- - VITE_API_URL=http://${DOMAIN?Variable not set}
- - NODE_ENV=development
-
networks:
traefik-public:
# For local dev, don't expect an external Traefik network
diff --git a/docker-compose.yml b/docker-compose.yml
index d614942cbd..42a4754b23 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -56,7 +56,7 @@ services:
- SMTP_USER=${SMTP_USER}
- SMTP_PASSWORD=${SMTP_PASSWORD}
- EMAILS_FROM_EMAIL=${EMAILS_FROM_EMAIL}
- - POSTGRES_SERVER=db
+ - POSTGRES_SERVER=${POSTGRES_SERVER}
- POSTGRES_PORT=${POSTGRES_PORT}
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER?Variable not set}
@@ -72,59 +72,21 @@ services:
- traefik.enable=true
- traefik.docker.network=traefik-public
- traefik.constraint-label=traefik-public
-
- traefik.http.services.${STACK_NAME?Variable not set}-backend.loadbalancer.server.port=80
-
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=(Host(`${DOMAIN?Variable not set}`) || Host(`www.${DOMAIN?Variable not set}`)) && (PathPrefix(`/api`) || PathPrefix(`/docs`) || PathPrefix(`/redoc`))
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.entrypoints=http
-
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.rule=(Host(`${DOMAIN?Variable not set}`) || Host(`www.${DOMAIN?Variable not set}`)) && (PathPrefix(`/api`) || PathPrefix(`/docs`) || PathPrefix(`/redoc`))
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.entrypoints=https
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls=true
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls.certresolver=le
-
- # Define Traefik Middleware to handle domain with and without "www" to redirect to only one
- traefik.http.middlewares.${STACK_NAME?Variable not set}-www-redirect.redirectregex.regex=^http(s)?://www.(${DOMAIN?Variable not set})/(.*)
- # Redirect a domain with www to non-www
- traefik.http.middlewares.${STACK_NAME?Variable not set}-www-redirect.redirectregex.replacement=http$${1}://${DOMAIN?Variable not set}/$${3}
-
- # Enable www redirection for HTTP and HTTPS
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.middlewares=https-redirect,${STACK_NAME?Variable not set}-www-redirect
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.middlewares=${STACK_NAME?Variable not set}-www-redirect
- frontend:
- image: '${DOCKER_IMAGE_FRONTEND?Variable not set}:${TAG-latest}'
- restart: always
- networks:
- - traefik-public
- - default
- build:
- context: ./frontend
- args:
- - VITE_API_URL=https://${DOMAIN?Variable not set}
- - NODE_ENV=production
- labels:
- - traefik.enable=true
- - traefik.docker.network=traefik-public
- - traefik.constraint-label=traefik-public
-
- - traefik.http.services.${STACK_NAME?Variable not set}-frontend.loadbalancer.server.port=80
-
- - traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.rule=Host(`${DOMAIN?Variable not set}`) || Host(`www.${DOMAIN?Variable not set}`)
- - traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.entrypoints=http
-
- - traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.rule=Host(`${DOMAIN?Variable not set}`) || Host(`www.${DOMAIN?Variable not set}`)
- - traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.entrypoints=https
- - traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.tls=true
- - traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.tls.certresolver=le
-
- # Enable www redirection for HTTP and HTTPS
- - traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.middlewares=${STACK_NAME?Variable not set}-www-redirect
- - traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.middlewares=https-redirect,${STACK_NAME?Variable not set}-www-redirect
volumes:
app-db-data:
networks:
traefik-public:
- # Allow setting it to false for testing
- external: true
+ external: true
\ No newline at end of file
diff --git a/frontend/.dockerignore b/frontend/.dockerignore
deleted file mode 100644
index f06235c460..0000000000
--- a/frontend/.dockerignore
+++ /dev/null
@@ -1,2 +0,0 @@
-node_modules
-dist
diff --git a/frontend/.env b/frontend/.env
deleted file mode 100644
index f829bd1979..0000000000
--- a/frontend/.env
+++ /dev/null
@@ -1 +0,0 @@
-VITE_API_URL=http://localhost
diff --git a/frontend/.gitignore b/frontend/.gitignore
deleted file mode 100644
index dfc4015cce..0000000000
--- a/frontend/.gitignore
+++ /dev/null
@@ -1,29 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-openapi.json
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
-/test-results/
-/playwright-report/
-/blob-report/
-/playwright/.cache/
diff --git a/frontend/.nvmrc b/frontend/.nvmrc
deleted file mode 100644
index 209e3ef4b6..0000000000
--- a/frontend/.nvmrc
+++ /dev/null
@@ -1 +0,0 @@
-20
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
deleted file mode 100644
index 8728c7b029..0000000000
--- a/frontend/Dockerfile
+++ /dev/null
@@ -1,23 +0,0 @@
-# Stage 0, "build-stage", based on Node.js, to build and compile the frontend
-FROM node:20 AS build-stage
-
-WORKDIR /app
-
-COPY package*.json /app/
-
-RUN npm install
-
-COPY ./ /app/
-
-ARG VITE_API_URL=${VITE_API_URL}
-
-RUN npm run build
-
-
-# Stage 1, based on Nginx, to have only the compiled app, ready for production with Nginx
-FROM nginx:1
-
-COPY --from=build-stage /app/dist/ /usr/share/nginx/html
-
-COPY ./nginx.conf /etc/nginx/conf.d/default.conf
-COPY ./nginx-backend-not-found.conf /etc/nginx/extra-conf.d/backend-not-found.conf
diff --git a/frontend/README.md b/frontend/README.md
deleted file mode 100644
index 9a01970fda..0000000000
--- a/frontend/README.md
+++ /dev/null
@@ -1,160 +0,0 @@
-# FastAPI Project - Frontend
-
-The frontend is built with [Vite](https://vitejs.dev/), [React](https://reactjs.org/), [TypeScript](https://www.typescriptlang.org/), [TanStack Query](https://tanstack.com/query), [TanStack Router](https://tanstack.com/router) and [Chakra UI](https://chakra-ui.com/).
-
-## Frontend development
-
-Before you begin, ensure that you have either the Node Version Manager (nvm) or Fast Node Manager (fnm) installed on your system.
-
-* To install fnm follow the [official fnm guide](https://github.com/Schniz/fnm#installation). If you prefer nvm, you can install it using the [official nvm guide](https://github.com/nvm-sh/nvm#installing-and-updating).
-
-* After installing either nvm or fnm, proceed to the `frontend` directory:
-
-```bash
-cd frontend
-```
-* If the Node.js version specified in the `.nvmrc` file isn't installed on your system, you can install it using the appropriate command:
-
-```bash
-# If using fnm
-fnm install
-
-# If using nvm
-nvm install
-```
-
-* Once the installation is complete, switch to the installed version:
-
-```bash
-# If using fnm
-fnm use
-
-# If using nvm
-nvm use
-```
-
-* Within the `frontend` directory, install the necessary NPM packages:
-
-```bash
-npm install
-```
-
-* And start the live server with the following `npm` script:
-
-```bash
-npm run dev
-```
-
-* Then open your browser at http://localhost:5173/.
-
-Notice that this live server is not running inside Docker, it's for local development, and that is the recommended workflow. Once you are happy with your frontend, you can build the frontend Docker image and start it, to test it in a production-like environment. But building the image at every change will not be as productive as running the local development server with live reload.
-
-Check the file `package.json` to see other available options.
-
-### Removing the frontend
-
-If you are developing an API-only app and want to remove the frontend, you can do it easily:
-
-* Remove the `./frontend` directory.
-
-* In the `docker-compose.yml` file, remove the whole service / section `frontend`.
-
-* In the `docker-compose.override.yml` file, remove the whole service / section `frontend`.
-
-Done, you have a frontend-less (api-only) app. 🤓
-
----
-
-If you want, you can also remove the `FRONTEND` environment variables from:
-
-* `.env`
-* `./scripts/*.sh`
-
-But it would be only to clean them up, leaving them won't really have any effect either way.
-
-## Generate Client
-
-### Automatically
-
-* Activate the backend virtual environment.
-* From the top level project directory, run the script:
-
-```bash
-./scripts/generate-frontend-client.sh
-```
-
-* Commit the changes.
-
-### Manually
-
-* Start the Docker Compose stack.
-
-* Download the OpenAPI JSON file from `http://localhost/api/v1/openapi.json` and copy it to a new file `openapi.json` at the root of the `frontend` directory.
-
-* To simplify the names in the generated frontend client code, modify the `openapi.json` file by running the following script:
-
-```bash
-node modify-openapi-operationids.js
-```
-
-* To generate the frontend client, run:
-
-```bash
-npm run generate-client
-```
-
-* Commit the changes.
-
-Notice that everytime the backend changes (changing the OpenAPI schema), you should follow these steps again to update the frontend client.
-
-## Using a Remote API
-
-If you want to use a remote API, you can set the environment variable `VITE_API_URL` to the URL of the remote API. For example, you can set it in the `frontend/.env` file:
-
-```env
-VITE_API_URL=https://my-remote-api.example.com
-```
-
-Then, when you run the frontend, it will use that URL as the base URL for the API.
-
-## Code Structure
-
-The frontend code is structured as follows:
-
-* `frontend/src` - The main frontend code.
-* `frontend/src/assets` - Static assets.
-* `frontend/src/client` - The generated OpenAPI client.
-* `frontend/src/components` - The different components of the frontend.
-* `frontend/src/hooks` - Custom hooks.
-* `frontend/src/routes` - The different routes of the frontend which include the pages.
-* `theme.tsx` - The Chakra UI custom theme.
-
-## End-to-End Testing with Playwright
-
-The frontend includes initial end-to-end tests using Playwright. To run the tests, you need to have the Docker Compose stack running. Start the stack with the following command:
-
-```bash
-docker compose up -d
-```
-
-Then, you can run the tests with the following command:
-
-```bash
-npx playwright test
-```
-
-You can also run your tests in UI mode to see the browser and interact with it running:
-
-```bash
-npx playwright test --ui
-```
-
-To stop and remove the Docker Compose stack and clean the data created in tests, use the following command:
-
-```bash
-docker compose down -v
-```
-
-To update the tests, navigate to the tests directory and modify the existing test files or add new ones as needed.
-
-For more information on writing and running Playwright tests, refer to the official [Playwright documentation](https://playwright.dev/docs/intro).
\ No newline at end of file
diff --git a/frontend/biome.json b/frontend/biome.json
deleted file mode 100644
index a06315dc2a..0000000000
--- a/frontend/biome.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "$schema": "https://biomejs.dev/schemas/1.6.1/schema.json",
- "organizeImports": {
- "enabled": true
- },
- "files": {
- "ignore": [
- "node_modules",
- "src/routeTree.gen.ts",
- "playwright.config.ts",
- "playwright-report"
- ]
- },
- "linter": {
- "enabled": true,
- "rules": {
- "recommended": true,
- "suspicious": {
- "noExplicitAny": "off",
- "noArrayIndexKey": "off"
- },
- "style": {
- "noNonNullAssertion": "off"
- }
- }
- },
- "formatter": {
- "indentStyle": "space"
- },
- "javascript": {
- "formatter": {
- "quoteStyle": "double",
- "semicolons": "asNeeded"
- }
- }
-}
diff --git a/frontend/index.html b/frontend/index.html
deleted file mode 100644
index 57621a268b..0000000000
--- a/frontend/index.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
- Full Stack FastAPI Project
-
-
-
-
-
-
-
diff --git a/frontend/modify-openapi-operationids.js b/frontend/modify-openapi-operationids.js
deleted file mode 100644
index b22fd17f9e..0000000000
--- a/frontend/modify-openapi-operationids.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import * as fs from "node:fs"
-
-async function modifyOpenAPIFile(filePath) {
- try {
- const data = await fs.promises.readFile(filePath)
- const openapiContent = JSON.parse(data)
-
- const paths = openapiContent.paths
- for (const pathKey of Object.keys(paths)) {
- const pathData = paths[pathKey]
- for (const method of Object.keys(pathData)) {
- const operation = pathData[method]
- if (operation.tags && operation.tags.length > 0) {
- const tag = operation.tags[0]
- const operationId = operation.operationId
- const toRemove = `${tag}-`
- if (operationId.startsWith(toRemove)) {
- const newOperationId = operationId.substring(toRemove.length)
- operation.operationId = newOperationId
- }
- }
- }
- }
-
- await fs.promises.writeFile(
- filePath,
- JSON.stringify(openapiContent, null, 2),
- )
- console.log("File successfully modified")
- } catch (err) {
- console.error("Error:", err)
- }
-}
-
-const filePath = "./openapi.json"
-modifyOpenAPIFile(filePath)
diff --git a/frontend/nginx-backend-not-found.conf b/frontend/nginx-backend-not-found.conf
deleted file mode 100644
index f6fea66358..0000000000
--- a/frontend/nginx-backend-not-found.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-location /api {
- return 404;
-}
-location /docs {
- return 404;
-}
-location /redoc {
- return 404;
-}
diff --git a/frontend/nginx.conf b/frontend/nginx.conf
deleted file mode 100644
index ba4d9aad6c..0000000000
--- a/frontend/nginx.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-server {
- listen 80;
-
- location / {
- root /usr/share/nginx/html;
- index index.html index.htm;
- try_files $uri /index.html =404;
- }
-
- include /etc/nginx/extra-conf.d/*.conf;
-}
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
deleted file mode 100644
index 9560ff9f69..0000000000
--- a/frontend/package-lock.json
+++ /dev/null
@@ -1,6478 +0,0 @@
-{
- "name": "frontend",
- "version": "0.0.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "frontend",
- "version": "0.0.0",
- "dependencies": {
- "@chakra-ui/icons": "2.1.1",
- "@chakra-ui/react": "2.8.2",
- "@emotion/react": "11.11.3",
- "@emotion/styled": "11.11.0",
- "@tanstack/react-query": "^5.28.14",
- "@tanstack/react-query-devtools": "^5.28.14",
- "@tanstack/react-router": "1.19.1",
- "axios": "1.7.4",
- "form-data": "4.0.0",
- "framer-motion": "10.16.16",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-error-boundary": "^4.0.13",
- "react-hook-form": "7.49.3",
- "react-icons": "5.0.1"
- },
- "devDependencies": {
- "@biomejs/biome": "1.6.1",
- "@hey-api/openapi-ts": "^0.34.1",
- "@playwright/test": "^1.45.2",
- "@tanstack/router-devtools": "1.19.1",
- "@tanstack/router-vite-plugin": "1.19.0",
- "@types/node": "^20.10.5",
- "@types/react": "^18.2.37",
- "@types/react-dom": "^18.2.15",
- "@vitejs/plugin-react-swc": "^3.5.0",
- "dotenv": "^16.4.5",
- "typescript": "^5.2.2",
- "vite": "^5.0.13"
- }
- },
- "node_modules/@babel/code-frame": {
- "version": "7.23.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
- "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
- "dependencies": {
- "@babel/highlight": "^7.23.4",
- "chalk": "^2.4.2"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/code-frame/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/code-frame/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/code-frame/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/@babel/code-frame/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/@babel/code-frame/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/code-frame/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/helper-module-imports": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
- "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
- "dependencies": {
- "@babel/types": "^7.22.15"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-string-parser": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
- "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/highlight": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
- "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.22.20",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/highlight/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/highlight/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/highlight/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/@babel/highlight/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/@babel/highlight/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/highlight/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/runtime": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
- "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
- "dependencies": {
- "regenerator-runtime": "^0.14.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/types": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz",
- "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==",
- "dependencies": {
- "@babel/helper-string-parser": "^7.23.4",
- "@babel/helper-validator-identifier": "^7.22.20",
- "to-fast-properties": "^2.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@biomejs/biome": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.6.1.tgz",
- "integrity": "sha512-SILQvA2S0XeaOuu1bivv6fQmMo7zMfr2xqDEN+Sz78pGbAKZnGmg0emsXjQWoBY/RVm9kPCgX+aGEpZZTYaM7w==",
- "dev": true,
- "hasInstallScript": true,
- "bin": {
- "biome": "bin/biome"
- },
- "engines": {
- "node": ">=14.*"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/biome"
- },
- "optionalDependencies": {
- "@biomejs/cli-darwin-arm64": "1.6.1",
- "@biomejs/cli-darwin-x64": "1.6.1",
- "@biomejs/cli-linux-arm64": "1.6.1",
- "@biomejs/cli-linux-arm64-musl": "1.6.1",
- "@biomejs/cli-linux-x64": "1.6.1",
- "@biomejs/cli-linux-x64-musl": "1.6.1",
- "@biomejs/cli-win32-arm64": "1.6.1",
- "@biomejs/cli-win32-x64": "1.6.1"
- }
- },
- "node_modules/@biomejs/cli-darwin-arm64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.6.1.tgz",
- "integrity": "sha512-KlvY00iB9T/vFi4m/GXxEyYkYnYy6aw06uapzUIIdiMMj7I/pmZu7CsZlzWdekVD0j+SsQbxdZMsb0wPhnRSsg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=14.*"
- }
- },
- "node_modules/@biomejs/cli-darwin-x64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.6.1.tgz",
- "integrity": "sha512-jP4E8TXaQX5e3nvRJSzB+qicZrdIDCrjR0sSb1DaDTx4JPZH5WXq/BlTqAyWi3IijM+IYMjWqAAK4kOHsSCzxw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=14.*"
- }
- },
- "node_modules/@biomejs/cli-linux-arm64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.6.1.tgz",
- "integrity": "sha512-nxD1UyX3bWSl/RSKlib/JsOmt+652/9yieogdSC/UTLgVCZYOF7u8L/LK7kAa0Y4nA8zSPavAQTgko7mHC2ObA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=14.*"
- }
- },
- "node_modules/@biomejs/cli-linux-arm64-musl": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.1.tgz",
- "integrity": "sha512-YdkDgFecdHJg7PJxAMaZIixVWGB6St4yH08BHagO0fEhNNiY8cAKEVo2mcXlsnEiTMpeSEAY9VxLUrVT3IVxpw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=14.*"
- }
- },
- "node_modules/@biomejs/cli-linux-x64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.6.1.tgz",
- "integrity": "sha512-BYAzenlMF3QdngjNFw9QVBXKGNzeecqwF3pwDgUGEvU7OJpn1/lyVkJVxYPtVGRNdjQ9e6l/s8NjKuBpW/ZR4Q==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=14.*"
- }
- },
- "node_modules/@biomejs/cli-linux-x64-musl": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.1.tgz",
- "integrity": "sha512-aSISIDmxq04NNy7tm4x9rBk2vH0ub2VDIE4outEmdC2LBtEJoINiphlZagx/FvjbsqUfygent9QUSn0oREnAXg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=14.*"
- }
- },
- "node_modules/@biomejs/cli-win32-arm64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.6.1.tgz",
- "integrity": "sha512-/eCHQKZ1kEawUpkSuXq4urtxMsD1P1678OPG3zNKt3ru16AqqspLdO3jzBe3k74xCPYnQ36e9Yqc97Mo0qgPtg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=14.*"
- }
- },
- "node_modules/@biomejs/cli-win32-x64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.6.1.tgz",
- "integrity": "sha512-5TUZbzBwnDLFxLVGEPsorNi6eC2Gt+z4Oei9Qvq0M/4c4/mjZ96ABgwao/tMxf4ZBr/qyy2YdvF+gX9Rc+xC0A==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=14.*"
- }
- },
- "node_modules/@chakra-ui/accordion": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/accordion/-/accordion-2.3.1.tgz",
- "integrity": "sha512-FSXRm8iClFyU+gVaXisOSEw0/4Q+qZbFRiuhIAkVU6Boj0FxAMrlo9a8AV5TuF77rgaHytCdHk0Ng+cyUijrag==",
- "dependencies": {
- "@chakra-ui/descendant": "3.1.0",
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/transition": "2.1.0"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "framer-motion": ">=4.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/alert": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/alert/-/alert-2.2.2.tgz",
- "integrity": "sha512-jHg4LYMRNOJH830ViLuicjb3F+v6iriE/2G5T+Sd0Hna04nukNJ1MxUmBPE+vI22me2dIflfelu2v9wdB6Pojw==",
- "dependencies": {
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/spinner": "2.1.0"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/anatomy": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/anatomy/-/anatomy-2.2.2.tgz",
- "integrity": "sha512-MV6D4VLRIHr4PkW4zMyqfrNS1mPlCTiCXwvYGtDFQYr+xHFfonhAuf9WjsSc0nyp2m0OdkSLnzmVKkZFLo25Tg=="
- },
- "node_modules/@chakra-ui/avatar": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/avatar/-/avatar-2.3.0.tgz",
- "integrity": "sha512-8gKSyLfygnaotbJbDMHDiJoF38OHXUYVme4gGxZ1fLnQEdPVEaIWfH+NndIjOM0z8S+YEFnT9KyGMUtvPrBk3g==",
- "dependencies": {
- "@chakra-ui/image": "2.1.0",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/breadcrumb": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/breadcrumb/-/breadcrumb-2.2.0.tgz",
- "integrity": "sha512-4cWCG24flYBxjruRi4RJREWTGF74L/KzI2CognAW/d/zWR0CjiScuJhf37Am3LFbCySP6WSoyBOtTIoTA4yLEA==",
- "dependencies": {
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/breakpoint-utils": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/@chakra-ui/breakpoint-utils/-/breakpoint-utils-2.0.8.tgz",
- "integrity": "sha512-Pq32MlEX9fwb5j5xx8s18zJMARNHlQZH2VH1RZgfgRDpp7DcEgtRW5AInfN5CfqdHLO1dGxA7I3MqEuL5JnIsA==",
- "dependencies": {
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "node_modules/@chakra-ui/button": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/button/-/button-2.1.0.tgz",
- "integrity": "sha512-95CplwlRKmmUXkdEp/21VkEWgnwcx2TOBG6NfYlsuLBDHSLlo5FKIiE2oSi4zXc4TLcopGcWPNcm/NDaSC5pvA==",
- "dependencies": {
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/spinner": "2.1.0"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/card": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/card/-/card-2.2.0.tgz",
- "integrity": "sha512-xUB/k5MURj4CtPAhdSoXZidUbm8j3hci9vnc+eZJVDqhDOShNlD6QeniQNRPRys4lWAQLCbFcrwL29C8naDi6g==",
- "dependencies": {
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/checkbox": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/checkbox/-/checkbox-2.3.2.tgz",
- "integrity": "sha512-85g38JIXMEv6M+AcyIGLh7igNtfpAN6KGQFYxY9tBj0eWvWk4NKQxvqqyVta0bSAyIl1rixNIIezNpNWk2iO4g==",
- "dependencies": {
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-callback-ref": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/visually-hidden": "2.2.0",
- "@zag-js/focus-visible": "0.16.0"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/clickable": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/clickable/-/clickable-2.1.0.tgz",
- "integrity": "sha512-flRA/ClPUGPYabu+/GLREZVZr9j2uyyazCAUHAdrTUEdDYCr31SVGhgh7dgKdtq23bOvAQJpIJjw/0Bs0WvbXw==",
- "dependencies": {
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/close-button": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/close-button/-/close-button-2.1.1.tgz",
- "integrity": "sha512-gnpENKOanKexswSVpVz7ojZEALl2x5qjLYNqSQGbxz+aP9sOXPfUS56ebyBrre7T7exuWGiFeRwnM0oVeGPaiw==",
- "dependencies": {
- "@chakra-ui/icon": "3.2.0"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/color-mode": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/color-mode/-/color-mode-2.2.0.tgz",
- "integrity": "sha512-niTEA8PALtMWRI9wJ4LL0CSBDo8NBfLNp4GD6/0hstcm3IlbBHTVKxN6HwSaoNYfphDQLxCjT4yG+0BJA5tFpg==",
- "dependencies": {
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/control-box": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/control-box/-/control-box-2.1.0.tgz",
- "integrity": "sha512-gVrRDyXFdMd8E7rulL0SKeoljkLQiPITFnsyMO8EFHNZ+AHt5wK4LIguYVEq88APqAGZGfHFWXr79RYrNiE3Mg==",
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/counter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/counter/-/counter-2.1.0.tgz",
- "integrity": "sha512-s6hZAEcWT5zzjNz2JIWUBzRubo9la/oof1W7EKZVVfPYHERnl5e16FmBC79Yfq8p09LQ+aqFKm/etYoJMMgghw==",
- "dependencies": {
- "@chakra-ui/number-utils": "2.0.7",
- "@chakra-ui/react-use-callback-ref": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/css-reset": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-2.3.0.tgz",
- "integrity": "sha512-cQwwBy5O0jzvl0K7PLTLgp8ijqLPKyuEMiDXwYzl95seD3AoeuoCLyzZcJtVqaUZ573PiBdAbY/IlZcwDOItWg==",
- "peerDependencies": {
- "@emotion/react": ">=10.0.35",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/descendant": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/descendant/-/descendant-3.1.0.tgz",
- "integrity": "sha512-VxCIAir08g5w27klLyi7PVo8BxhW4tgU/lxQyujkmi4zx7hT9ZdrcQLAted/dAa+aSIZ14S1oV0Q9lGjsAdxUQ==",
- "dependencies": {
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/dom-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/dom-utils/-/dom-utils-2.1.0.tgz",
- "integrity": "sha512-ZmF2qRa1QZ0CMLU8M1zCfmw29DmPNtfjR9iTo74U5FPr3i1aoAh7fbJ4qAlZ197Xw9eAW28tvzQuoVWeL5C7fQ=="
- },
- "node_modules/@chakra-ui/editable": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/editable/-/editable-3.1.0.tgz",
- "integrity": "sha512-j2JLrUL9wgg4YA6jLlbU88370eCRyor7DZQD9lzpY95tSOXpTljeg3uF9eOmDnCs6fxp3zDWIfkgMm/ExhcGTg==",
- "dependencies": {
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-callback-ref": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-focus-on-pointer-down": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/event-utils": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/@chakra-ui/event-utils/-/event-utils-2.0.8.tgz",
- "integrity": "sha512-IGM/yGUHS+8TOQrZGpAKOJl/xGBrmRYJrmbHfUE7zrG3PpQyXvbLDP1M+RggkCFVgHlJi2wpYIf0QtQlU0XZfw=="
- },
- "node_modules/@chakra-ui/focus-lock": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/focus-lock/-/focus-lock-2.1.0.tgz",
- "integrity": "sha512-EmGx4PhWGjm4dpjRqM4Aa+rCWBxP+Rq8Uc/nAVnD4YVqkEhBkrPTpui2lnjsuxqNaZ24fIAZ10cF1hlpemte/w==",
- "dependencies": {
- "@chakra-ui/dom-utils": "2.1.0",
- "react-focus-lock": "^2.9.4"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/form-control": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/form-control/-/form-control-2.2.0.tgz",
- "integrity": "sha512-wehLC1t4fafCVJ2RvJQT2jyqsAwX7KymmiGqBu7nQoQz8ApTkGABWpo/QwDh3F/dBLrouHDoOvGmYTqft3Mirw==",
- "dependencies": {
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/hooks": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/hooks/-/hooks-2.2.1.tgz",
- "integrity": "sha512-RQbTnzl6b1tBjbDPf9zGRo9rf/pQMholsOudTxjy4i9GfTfz6kgp5ValGjQm2z7ng6Z31N1cnjZ1AlSzQ//ZfQ==",
- "dependencies": {
- "@chakra-ui/react-utils": "2.0.12",
- "@chakra-ui/utils": "2.0.15",
- "compute-scroll-into-view": "3.0.3",
- "copy-to-clipboard": "3.3.3"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/icon": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/icon/-/icon-3.2.0.tgz",
- "integrity": "sha512-xxjGLvlX2Ys4H0iHrI16t74rG9EBcpFvJ3Y3B7KMQTrnW34Kf7Da/UC8J67Gtx85mTHW020ml85SVPKORWNNKQ==",
- "dependencies": {
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/icons": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/icons/-/icons-2.1.1.tgz",
- "integrity": "sha512-3p30hdo4LlRZTT5CwoAJq3G9fHI0wDc0pBaMHj4SUn0yomO+RcDRlzhdXqdr5cVnzax44sqXJVnf3oQG0eI+4g==",
- "dependencies": {
- "@chakra-ui/icon": "3.2.0"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/image": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/image/-/image-2.1.0.tgz",
- "integrity": "sha512-bskumBYKLiLMySIWDGcz0+D9Th0jPvmX6xnRMs4o92tT3Od/bW26lahmV2a2Op2ItXeCmRMY+XxJH5Gy1i46VA==",
- "dependencies": {
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/input": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/input/-/input-2.1.2.tgz",
- "integrity": "sha512-GiBbb3EqAA8Ph43yGa6Mc+kUPjh4Spmxp1Pkelr8qtudpc3p2PJOOebLpd90mcqw8UePPa+l6YhhPtp6o0irhw==",
- "dependencies": {
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/object-utils": "2.1.0",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/layout": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/layout/-/layout-2.3.1.tgz",
- "integrity": "sha512-nXuZ6WRbq0WdgnRgLw+QuxWAHuhDtVX8ElWqcTK+cSMFg/52eVP47czYBE5F35YhnoW2XBwfNoNgZ7+e8Z01Rg==",
- "dependencies": {
- "@chakra-ui/breakpoint-utils": "2.0.8",
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/object-utils": "2.1.0",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/lazy-utils": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@chakra-ui/lazy-utils/-/lazy-utils-2.0.5.tgz",
- "integrity": "sha512-UULqw7FBvcckQk2n3iPO56TMJvDsNv0FKZI6PlUNJVaGsPbsYxK/8IQ60vZgaTVPtVcjY6BE+y6zg8u9HOqpyg=="
- },
- "node_modules/@chakra-ui/live-region": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/live-region/-/live-region-2.1.0.tgz",
- "integrity": "sha512-ZOxFXwtaLIsXjqnszYYrVuswBhnIHHP+XIgK1vC6DePKtyK590Wg+0J0slDwThUAd4MSSIUa/nNX84x1GMphWw==",
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/media-query": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/media-query/-/media-query-3.3.0.tgz",
- "integrity": "sha512-IsTGgFLoICVoPRp9ykOgqmdMotJG0CnPsKvGQeSFOB/dZfIujdVb14TYxDU4+MURXry1MhJ7LzZhv+Ml7cr8/g==",
- "dependencies": {
- "@chakra-ui/breakpoint-utils": "2.0.8",
- "@chakra-ui/react-env": "3.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/menu": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/menu/-/menu-2.2.1.tgz",
- "integrity": "sha512-lJS7XEObzJxsOwWQh7yfG4H8FzFPRP5hVPN/CL+JzytEINCSBvsCDHrYPQGp7jzpCi8vnTqQQGQe0f8dwnXd2g==",
- "dependencies": {
- "@chakra-ui/clickable": "2.1.0",
- "@chakra-ui/descendant": "3.1.0",
- "@chakra-ui/lazy-utils": "2.0.5",
- "@chakra-ui/popper": "3.1.0",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-animation-state": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-disclosure": "2.1.0",
- "@chakra-ui/react-use-focus-effect": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-outside-click": "2.2.0",
- "@chakra-ui/react-use-update-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/transition": "2.1.0"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "framer-motion": ">=4.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/modal": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/modal/-/modal-2.3.1.tgz",
- "integrity": "sha512-TQv1ZaiJMZN+rR9DK0snx/OPwmtaGH1HbZtlYt4W4s6CzyK541fxLRTjIXfEzIGpvNW+b6VFuFjbcR78p4DEoQ==",
- "dependencies": {
- "@chakra-ui/close-button": "2.1.1",
- "@chakra-ui/focus-lock": "2.1.0",
- "@chakra-ui/portal": "2.1.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/transition": "2.1.0",
- "aria-hidden": "^1.2.3",
- "react-remove-scroll": "^2.5.6"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "framer-motion": ">=4.0.0",
- "react": ">=18",
- "react-dom": ">=18"
- }
- },
- "node_modules/@chakra-ui/number-input": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/number-input/-/number-input-2.1.2.tgz",
- "integrity": "sha512-pfOdX02sqUN0qC2ysuvgVDiws7xZ20XDIlcNhva55Jgm095xjm8eVdIBfNm3SFbSUNxyXvLTW/YQanX74tKmuA==",
- "dependencies": {
- "@chakra-ui/counter": "2.1.0",
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-callback-ref": "2.1.0",
- "@chakra-ui/react-use-event-listener": "2.1.0",
- "@chakra-ui/react-use-interval": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/number-utils": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/@chakra-ui/number-utils/-/number-utils-2.0.7.tgz",
- "integrity": "sha512-yOGxBjXNvLTBvQyhMDqGU0Oj26s91mbAlqKHiuw737AXHt0aPllOthVUqQMeaYLwLCjGMg0jtI7JReRzyi94Dg=="
- },
- "node_modules/@chakra-ui/object-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/object-utils/-/object-utils-2.1.0.tgz",
- "integrity": "sha512-tgIZOgLHaoti5PYGPTwK3t/cqtcycW0owaiOXoZOcpwwX/vlVb+H1jFsQyWiiwQVPt9RkoSLtxzXamx+aHH+bQ=="
- },
- "node_modules/@chakra-ui/pin-input": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/pin-input/-/pin-input-2.1.0.tgz",
- "integrity": "sha512-x4vBqLStDxJFMt+jdAHHS8jbh294O53CPQJoL4g228P513rHylV/uPscYUHrVJXRxsHfRztQO9k45jjTYaPRMw==",
- "dependencies": {
- "@chakra-ui/descendant": "3.1.0",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/popover": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/popover/-/popover-2.2.1.tgz",
- "integrity": "sha512-K+2ai2dD0ljvJnlrzesCDT9mNzLifE3noGKZ3QwLqd/K34Ym1W/0aL1ERSynrcG78NKoXS54SdEzkhCZ4Gn/Zg==",
- "dependencies": {
- "@chakra-ui/close-button": "2.1.1",
- "@chakra-ui/lazy-utils": "2.0.5",
- "@chakra-ui/popper": "3.1.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-animation-state": "2.1.0",
- "@chakra-ui/react-use-disclosure": "2.1.0",
- "@chakra-ui/react-use-focus-effect": "2.1.0",
- "@chakra-ui/react-use-focus-on-pointer-down": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "framer-motion": ">=4.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/popper": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/popper/-/popper-3.1.0.tgz",
- "integrity": "sha512-ciDdpdYbeFG7og6/6J8lkTFxsSvwTdMLFkpVylAF6VNC22jssiWfquj2eyD4rJnzkRFPvIWJq8hvbfhsm+AjSg==",
- "dependencies": {
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@popperjs/core": "^2.9.3"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/portal": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/portal/-/portal-2.1.0.tgz",
- "integrity": "sha512-9q9KWf6SArEcIq1gGofNcFPSWEyl+MfJjEUg/un1SMlQjaROOh3zYr+6JAwvcORiX7tyHosnmWC3d3wI2aPSQg==",
- "dependencies": {
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18",
- "react-dom": ">=18"
- }
- },
- "node_modules/@chakra-ui/progress": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/progress/-/progress-2.2.0.tgz",
- "integrity": "sha512-qUXuKbuhN60EzDD9mHR7B67D7p/ZqNS2Aze4Pbl1qGGZfulPW0PY8Rof32qDtttDQBkzQIzFGE8d9QpAemToIQ==",
- "dependencies": {
- "@chakra-ui/react-context": "2.1.0"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/provider": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/provider/-/provider-2.4.2.tgz",
- "integrity": "sha512-w0Tef5ZCJK1mlJorcSjItCSbyvVuqpvyWdxZiVQmE6fvSJR83wZof42ux0+sfWD+I7rHSfj+f9nzhNaEWClysw==",
- "dependencies": {
- "@chakra-ui/css-reset": "2.3.0",
- "@chakra-ui/portal": "2.1.0",
- "@chakra-ui/react-env": "3.1.0",
- "@chakra-ui/system": "2.6.2",
- "@chakra-ui/utils": "2.0.15"
- },
- "peerDependencies": {
- "@emotion/react": "^11.0.0",
- "@emotion/styled": "^11.0.0",
- "react": ">=18",
- "react-dom": ">=18"
- }
- },
- "node_modules/@chakra-ui/radio": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/radio/-/radio-2.1.2.tgz",
- "integrity": "sha512-n10M46wJrMGbonaghvSRnZ9ToTv/q76Szz284gv4QUWvyljQACcGrXIONUnQ3BIwbOfkRqSk7Xl/JgZtVfll+w==",
- "dependencies": {
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@zag-js/focus-visible": "0.16.0"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react": {
- "version": "2.8.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react/-/react-2.8.2.tgz",
- "integrity": "sha512-Hn0moyxxyCDKuR9ywYpqgX8dvjqwu9ArwpIb9wHNYjnODETjLwazgNIliCVBRcJvysGRiV51U2/JtJVrpeCjUQ==",
- "dependencies": {
- "@chakra-ui/accordion": "2.3.1",
- "@chakra-ui/alert": "2.2.2",
- "@chakra-ui/avatar": "2.3.0",
- "@chakra-ui/breadcrumb": "2.2.0",
- "@chakra-ui/button": "2.1.0",
- "@chakra-ui/card": "2.2.0",
- "@chakra-ui/checkbox": "2.3.2",
- "@chakra-ui/close-button": "2.1.1",
- "@chakra-ui/control-box": "2.1.0",
- "@chakra-ui/counter": "2.1.0",
- "@chakra-ui/css-reset": "2.3.0",
- "@chakra-ui/editable": "3.1.0",
- "@chakra-ui/focus-lock": "2.1.0",
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/hooks": "2.2.1",
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/image": "2.1.0",
- "@chakra-ui/input": "2.1.2",
- "@chakra-ui/layout": "2.3.1",
- "@chakra-ui/live-region": "2.1.0",
- "@chakra-ui/media-query": "3.3.0",
- "@chakra-ui/menu": "2.2.1",
- "@chakra-ui/modal": "2.3.1",
- "@chakra-ui/number-input": "2.1.2",
- "@chakra-ui/pin-input": "2.1.0",
- "@chakra-ui/popover": "2.2.1",
- "@chakra-ui/popper": "3.1.0",
- "@chakra-ui/portal": "2.1.0",
- "@chakra-ui/progress": "2.2.0",
- "@chakra-ui/provider": "2.4.2",
- "@chakra-ui/radio": "2.1.2",
- "@chakra-ui/react-env": "3.1.0",
- "@chakra-ui/select": "2.1.2",
- "@chakra-ui/skeleton": "2.1.0",
- "@chakra-ui/skip-nav": "2.1.0",
- "@chakra-ui/slider": "2.1.0",
- "@chakra-ui/spinner": "2.1.0",
- "@chakra-ui/stat": "2.1.1",
- "@chakra-ui/stepper": "2.3.1",
- "@chakra-ui/styled-system": "2.9.2",
- "@chakra-ui/switch": "2.1.2",
- "@chakra-ui/system": "2.6.2",
- "@chakra-ui/table": "2.1.0",
- "@chakra-ui/tabs": "3.0.0",
- "@chakra-ui/tag": "3.1.1",
- "@chakra-ui/textarea": "2.1.2",
- "@chakra-ui/theme": "3.3.1",
- "@chakra-ui/theme-utils": "2.0.21",
- "@chakra-ui/toast": "7.0.2",
- "@chakra-ui/tooltip": "2.3.1",
- "@chakra-ui/transition": "2.1.0",
- "@chakra-ui/utils": "2.0.15",
- "@chakra-ui/visually-hidden": "2.2.0"
- },
- "peerDependencies": {
- "@emotion/react": "^11.0.0",
- "@emotion/styled": "^11.0.0",
- "framer-motion": ">=4.0.0",
- "react": ">=18",
- "react-dom": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-children-utils": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-children-utils/-/react-children-utils-2.0.6.tgz",
- "integrity": "sha512-QVR2RC7QsOsbWwEnq9YduhpqSFnZGvjjGREV8ygKi8ADhXh93C8azLECCUVgRJF2Wc+So1fgxmjLcbZfY2VmBA==",
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-context": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-context/-/react-context-2.1.0.tgz",
- "integrity": "sha512-iahyStvzQ4AOwKwdPReLGfDesGG+vWJfEsn0X/NoGph/SkN+HXtv2sCfYFFR9k7bb+Kvc6YfpLlSuLvKMHi2+w==",
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-env": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-env/-/react-env-3.1.0.tgz",
- "integrity": "sha512-Vr96GV2LNBth3+IKzr/rq1IcnkXv+MLmwjQH6C8BRtn3sNskgDFD5vLkVXcEhagzZMCh8FR3V/bzZPojBOyNhw==",
- "dependencies": {
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-types": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-types/-/react-types-2.0.7.tgz",
- "integrity": "sha512-12zv2qIZ8EHwiytggtGvo4iLT0APris7T0qaAWqzpUGS0cdUtR8W+V1BJ5Ocq+7tA6dzQ/7+w5hmXih61TuhWQ==",
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-animation-state": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-animation-state/-/react-use-animation-state-2.1.0.tgz",
- "integrity": "sha512-CFZkQU3gmDBwhqy0vC1ryf90BVHxVN8cTLpSyCpdmExUEtSEInSCGMydj2fvn7QXsz/za8JNdO2xxgJwxpLMtg==",
- "dependencies": {
- "@chakra-ui/dom-utils": "2.1.0",
- "@chakra-ui/react-use-event-listener": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-callback-ref": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-callback-ref/-/react-use-callback-ref-2.1.0.tgz",
- "integrity": "sha512-efnJrBtGDa4YaxDzDE90EnKD3Vkh5a1t3w7PhnRQmsphLy3g2UieasoKTlT2Hn118TwDjIv5ZjHJW6HbzXA9wQ==",
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-controllable-state": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-controllable-state/-/react-use-controllable-state-2.1.0.tgz",
- "integrity": "sha512-QR/8fKNokxZUs4PfxjXuwl0fj/d71WPrmLJvEpCTkHjnzu7LnYvzoe2wB867IdooQJL0G1zBxl0Dq+6W1P3jpg==",
- "dependencies": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-disclosure": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-disclosure/-/react-use-disclosure-2.1.0.tgz",
- "integrity": "sha512-Ax4pmxA9LBGMyEZJhhUZobg9C0t3qFE4jVF1tGBsrLDcdBeLR9fwOogIPY9Hf0/wqSlAryAimICbr5hkpa5GSw==",
- "dependencies": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-event-listener": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-event-listener/-/react-use-event-listener-2.1.0.tgz",
- "integrity": "sha512-U5greryDLS8ISP69DKDsYcsXRtAdnTQT+jjIlRYZ49K/XhUR/AqVZCK5BkR1spTDmO9H8SPhgeNKI70ODuDU/Q==",
- "dependencies": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-focus-effect": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-focus-effect/-/react-use-focus-effect-2.1.0.tgz",
- "integrity": "sha512-xzVboNy7J64xveLcxTIJ3jv+lUJKDwRM7Szwn9tNzUIPD94O3qwjV7DDCUzN2490nSYDF4OBMt/wuDBtaR3kUQ==",
- "dependencies": {
- "@chakra-ui/dom-utils": "2.1.0",
- "@chakra-ui/react-use-event-listener": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-focus-on-pointer-down": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-focus-on-pointer-down/-/react-use-focus-on-pointer-down-2.1.0.tgz",
- "integrity": "sha512-2jzrUZ+aiCG/cfanrolsnSMDykCAbv9EK/4iUyZno6BYb3vziucmvgKuoXbMPAzWNtwUwtuMhkby8rc61Ue+Lg==",
- "dependencies": {
- "@chakra-ui/react-use-event-listener": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-interval": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-interval/-/react-use-interval-2.1.0.tgz",
- "integrity": "sha512-8iWj+I/+A0J08pgEXP1J1flcvhLBHkk0ln7ZvGIyXiEyM6XagOTJpwNhiu+Bmk59t3HoV/VyvyJTa+44sEApuw==",
- "dependencies": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-latest-ref": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-latest-ref/-/react-use-latest-ref-2.1.0.tgz",
- "integrity": "sha512-m0kxuIYqoYB0va9Z2aW4xP/5b7BzlDeWwyXCH6QpT2PpW3/281L3hLCm1G0eOUcdVlayqrQqOeD6Mglq+5/xoQ==",
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-merge-refs": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-merge-refs/-/react-use-merge-refs-2.1.0.tgz",
- "integrity": "sha512-lERa6AWF1cjEtWSGjxWTaSMvneccnAVH4V4ozh8SYiN9fSPZLlSG3kNxfNzdFvMEhM7dnP60vynF7WjGdTgQbQ==",
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-outside-click": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-outside-click/-/react-use-outside-click-2.2.0.tgz",
- "integrity": "sha512-PNX+s/JEaMneijbgAM4iFL+f3m1ga9+6QK0E5Yh4s8KZJQ/bLwZzdhMz8J/+mL+XEXQ5J0N8ivZN28B82N1kNw==",
- "dependencies": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-pan-event": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-pan-event/-/react-use-pan-event-2.1.0.tgz",
- "integrity": "sha512-xmL2qOHiXqfcj0q7ZK5s9UjTh4Gz0/gL9jcWPA6GVf+A0Od5imEDa/Vz+533yQKWiNSm1QGrIj0eJAokc7O4fg==",
- "dependencies": {
- "@chakra-ui/event-utils": "2.0.8",
- "@chakra-ui/react-use-latest-ref": "2.1.0",
- "framesync": "6.1.2"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-previous": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-previous/-/react-use-previous-2.1.0.tgz",
- "integrity": "sha512-pjxGwue1hX8AFcmjZ2XfrQtIJgqbTF3Qs1Dy3d1krC77dEsiCUbQ9GzOBfDc8pfd60DrB5N2tg5JyHbypqh0Sg==",
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-safe-layout-effect": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-safe-layout-effect/-/react-use-safe-layout-effect-2.1.0.tgz",
- "integrity": "sha512-Knbrrx/bcPwVS1TorFdzrK/zWA8yuU/eaXDkNj24IrKoRlQrSBFarcgAEzlCHtzuhufP3OULPkELTzz91b0tCw==",
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-size": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-size/-/react-use-size-2.1.0.tgz",
- "integrity": "sha512-tbLqrQhbnqOjzTaMlYytp7wY8BW1JpL78iG7Ru1DlV4EWGiAmXFGvtnEt9HftU0NJ0aJyjgymkxfVGI55/1Z4A==",
- "dependencies": {
- "@zag-js/element-size": "0.10.5"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-timeout": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-timeout/-/react-use-timeout-2.1.0.tgz",
- "integrity": "sha512-cFN0sobKMM9hXUhyCofx3/Mjlzah6ADaEl/AXl5Y+GawB5rgedgAcu2ErAgarEkwvsKdP6c68CKjQ9dmTQlJxQ==",
- "dependencies": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-use-update-effect": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-update-effect/-/react-use-update-effect-2.1.0.tgz",
- "integrity": "sha512-ND4Q23tETaR2Qd3zwCKYOOS1dfssojPLJMLvUtUbW5M9uW1ejYWgGUobeAiOVfSplownG8QYMmHTP86p/v0lbA==",
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/react-utils": {
- "version": "2.0.12",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-utils/-/react-utils-2.0.12.tgz",
- "integrity": "sha512-GbSfVb283+YA3kA8w8xWmzbjNWk14uhNpntnipHCftBibl0lxtQ9YqMFQLwuFOO0U2gYVocszqqDWX+XNKq9hw==",
- "dependencies": {
- "@chakra-ui/utils": "2.0.15"
- },
- "peerDependencies": {
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/select": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/select/-/select-2.1.2.tgz",
- "integrity": "sha512-ZwCb7LqKCVLJhru3DXvKXpZ7Pbu1TDZ7N0PdQ0Zj1oyVLJyrpef1u9HR5u0amOpqcH++Ugt0f5JSmirjNlctjA==",
- "dependencies": {
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/shared-utils": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@chakra-ui/shared-utils/-/shared-utils-2.0.5.tgz",
- "integrity": "sha512-4/Wur0FqDov7Y0nCXl7HbHzCg4aq86h+SXdoUeuCMD3dSj7dpsVnStLYhng1vxvlbUnLpdF4oz5Myt3i/a7N3Q=="
- },
- "node_modules/@chakra-ui/skeleton": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/skeleton/-/skeleton-2.1.0.tgz",
- "integrity": "sha512-JNRuMPpdZGd6zFVKjVQ0iusu3tXAdI29n4ZENYwAJEMf/fN0l12sVeirOxkJ7oEL0yOx2AgEYFSKdbcAgfUsAQ==",
- "dependencies": {
- "@chakra-ui/media-query": "3.3.0",
- "@chakra-ui/react-use-previous": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/skip-nav": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/skip-nav/-/skip-nav-2.1.0.tgz",
- "integrity": "sha512-Hk+FG+vadBSH0/7hwp9LJnLjkO0RPGnx7gBJWI4/SpoJf3e4tZlWYtwGj0toYY4aGKl93jVghuwGbDBEMoHDug==",
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/slider": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/slider/-/slider-2.1.0.tgz",
- "integrity": "sha512-lUOBcLMCnFZiA/s2NONXhELJh6sY5WtbRykPtclGfynqqOo47lwWJx+VP7xaeuhDOPcWSSecWc9Y1BfPOCz9cQ==",
- "dependencies": {
- "@chakra-ui/number-utils": "2.0.7",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-callback-ref": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-latest-ref": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-pan-event": "2.1.0",
- "@chakra-ui/react-use-size": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/spinner": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/spinner/-/spinner-2.1.0.tgz",
- "integrity": "sha512-hczbnoXt+MMv/d3gE+hjQhmkzLiKuoTo42YhUG7Bs9OSv2lg1fZHW1fGNRFP3wTi6OIbD044U1P9HK+AOgFH3g==",
- "dependencies": {
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/stat": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/stat/-/stat-2.1.1.tgz",
- "integrity": "sha512-LDn0d/LXQNbAn2KaR3F1zivsZCewY4Jsy1qShmfBMKwn6rI8yVlbvu6SiA3OpHS0FhxbsZxQI6HefEoIgtqY6Q==",
- "dependencies": {
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/stepper": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/stepper/-/stepper-2.3.1.tgz",
- "integrity": "sha512-ky77lZbW60zYkSXhYz7kbItUpAQfEdycT0Q4bkHLxfqbuiGMf8OmgZOQkOB9uM4v0zPwy2HXhe0vq4Dd0xa55Q==",
- "dependencies": {
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/styled-system": {
- "version": "2.9.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/styled-system/-/styled-system-2.9.2.tgz",
- "integrity": "sha512-To/Z92oHpIE+4nk11uVMWqo2GGRS86coeMmjxtpnErmWRdLcp1WVCVRAvn+ZwpLiNR+reWFr2FFqJRsREuZdAg==",
- "dependencies": {
- "@chakra-ui/shared-utils": "2.0.5",
- "csstype": "^3.1.2",
- "lodash.mergewith": "4.6.2"
- }
- },
- "node_modules/@chakra-ui/switch": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/switch/-/switch-2.1.2.tgz",
- "integrity": "sha512-pgmi/CC+E1v31FcnQhsSGjJnOE2OcND4cKPyTE+0F+bmGm48Q/b5UmKD9Y+CmZsrt/7V3h8KNczowupfuBfIHA==",
- "dependencies": {
- "@chakra-ui/checkbox": "2.3.2",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "framer-motion": ">=4.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/system": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/system/-/system-2.6.2.tgz",
- "integrity": "sha512-EGtpoEjLrUu4W1fHD+a62XR+hzC5YfsWm+6lO0Kybcga3yYEij9beegO0jZgug27V+Rf7vns95VPVP6mFd/DEQ==",
- "dependencies": {
- "@chakra-ui/color-mode": "2.2.0",
- "@chakra-ui/object-utils": "2.1.0",
- "@chakra-ui/react-utils": "2.0.12",
- "@chakra-ui/styled-system": "2.9.2",
- "@chakra-ui/theme-utils": "2.0.21",
- "@chakra-ui/utils": "2.0.15",
- "react-fast-compare": "3.2.2"
- },
- "peerDependencies": {
- "@emotion/react": "^11.0.0",
- "@emotion/styled": "^11.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/table": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/table/-/table-2.1.0.tgz",
- "integrity": "sha512-o5OrjoHCh5uCLdiUb0Oc0vq9rIAeHSIRScc2ExTC9Qg/uVZl2ygLrjToCaKfaaKl1oQexIeAcZDKvPG8tVkHyQ==",
- "dependencies": {
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/tabs": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/tabs/-/tabs-3.0.0.tgz",
- "integrity": "sha512-6Mlclp8L9lqXmsGWF5q5gmemZXOiOYuh0SGT/7PgJVNPz3LXREXlXg2an4MBUD8W5oTkduCX+3KTMCwRrVrDYw==",
- "dependencies": {
- "@chakra-ui/clickable": "2.1.0",
- "@chakra-ui/descendant": "3.1.0",
- "@chakra-ui/lazy-utils": "2.0.5",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/tag": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/tag/-/tag-3.1.1.tgz",
- "integrity": "sha512-Bdel79Dv86Hnge2PKOU+t8H28nm/7Y3cKd4Kfk9k3lOpUh4+nkSGe58dhRzht59lEqa4N9waCgQiBdkydjvBXQ==",
- "dependencies": {
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/textarea": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/textarea/-/textarea-2.1.2.tgz",
- "integrity": "sha512-ip7tvklVCZUb2fOHDb23qPy/Fr2mzDOGdkrpbNi50hDCiV4hFX02jdQJdi3ydHZUyVgZVBKPOJ+lT9i7sKA2wA==",
- "dependencies": {
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/theme": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/theme/-/theme-3.3.1.tgz",
- "integrity": "sha512-Hft/VaT8GYnItGCBbgWd75ICrIrIFrR7lVOhV/dQnqtfGqsVDlrztbSErvMkoPKt0UgAkd9/o44jmZ6X4U2nZQ==",
- "dependencies": {
- "@chakra-ui/anatomy": "2.2.2",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/theme-tools": "2.1.2"
- },
- "peerDependencies": {
- "@chakra-ui/styled-system": ">=2.8.0"
- }
- },
- "node_modules/@chakra-ui/theme-tools": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/theme-tools/-/theme-tools-2.1.2.tgz",
- "integrity": "sha512-Qdj8ajF9kxY4gLrq7gA+Azp8CtFHGO9tWMN2wfF9aQNgG9AuMhPrUzMq9AMQ0MXiYcgNq/FD3eegB43nHVmXVA==",
- "dependencies": {
- "@chakra-ui/anatomy": "2.2.2",
- "@chakra-ui/shared-utils": "2.0.5",
- "color2k": "^2.0.2"
- },
- "peerDependencies": {
- "@chakra-ui/styled-system": ">=2.0.0"
- }
- },
- "node_modules/@chakra-ui/theme-utils": {
- "version": "2.0.21",
- "resolved": "https://registry.npmjs.org/@chakra-ui/theme-utils/-/theme-utils-2.0.21.tgz",
- "integrity": "sha512-FjH5LJbT794r0+VSCXB3lT4aubI24bLLRWB+CuRKHijRvsOg717bRdUN/N1fEmEpFnRVrbewttWh/OQs0EWpWw==",
- "dependencies": {
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/styled-system": "2.9.2",
- "@chakra-ui/theme": "3.3.1",
- "lodash.mergewith": "4.6.2"
- }
- },
- "node_modules/@chakra-ui/toast": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/toast/-/toast-7.0.2.tgz",
- "integrity": "sha512-yvRP8jFKRs/YnkuE41BVTq9nB2v/KDRmje9u6dgDmE5+1bFt3bwjdf9gVbif4u5Ve7F7BGk5E093ARRVtvLvXA==",
- "dependencies": {
- "@chakra-ui/alert": "2.2.2",
- "@chakra-ui/close-button": "2.1.1",
- "@chakra-ui/portal": "2.1.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-timeout": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/styled-system": "2.9.2",
- "@chakra-ui/theme": "3.3.1"
- },
- "peerDependencies": {
- "@chakra-ui/system": "2.6.2",
- "framer-motion": ">=4.0.0",
- "react": ">=18",
- "react-dom": ">=18"
- }
- },
- "node_modules/@chakra-ui/tooltip": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/tooltip/-/tooltip-2.3.1.tgz",
- "integrity": "sha512-Rh39GBn/bL4kZpuEMPPRwYNnccRCL+w9OqamWHIB3Qboxs6h8cOyXfIdGxjo72lvhu1QI/a4KFqkM3St+WfC0A==",
- "dependencies": {
- "@chakra-ui/dom-utils": "2.1.0",
- "@chakra-ui/popper": "3.1.0",
- "@chakra-ui/portal": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-disclosure": "2.1.0",
- "@chakra-ui/react-use-event-listener": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "framer-motion": ">=4.0.0",
- "react": ">=18",
- "react-dom": ">=18"
- }
- },
- "node_modules/@chakra-ui/transition": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/transition/-/transition-2.1.0.tgz",
- "integrity": "sha512-orkT6T/Dt+/+kVwJNy7zwJ+U2xAZ3EU7M3XCs45RBvUnZDr/u9vdmaM/3D/rOpmQJWgQBwKPJleUXrYWUagEDQ==",
- "dependencies": {
- "@chakra-ui/shared-utils": "2.0.5"
- },
- "peerDependencies": {
- "framer-motion": ">=4.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@chakra-ui/utils": {
- "version": "2.0.15",
- "resolved": "https://registry.npmjs.org/@chakra-ui/utils/-/utils-2.0.15.tgz",
- "integrity": "sha512-El4+jL0WSaYYs+rJbuYFDbjmfCcfGDmRY95GO4xwzit6YAPZBLcR65rOEwLps+XWluZTy1xdMrusg/hW0c1aAA==",
- "dependencies": {
- "@types/lodash.mergewith": "4.6.7",
- "css-box-model": "1.2.1",
- "framesync": "6.1.2",
- "lodash.mergewith": "4.6.2"
- }
- },
- "node_modules/@chakra-ui/visually-hidden": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/visually-hidden/-/visually-hidden-2.2.0.tgz",
- "integrity": "sha512-KmKDg01SrQ7VbTD3+cPWf/UfpF5MSwm3v7MWi0n5t8HnnadT13MF0MJCDSXbBWnzLv1ZKJ6zlyAOeARWX+DpjQ==",
- "peerDependencies": {
- "@chakra-ui/system": ">=2.0.0",
- "react": ">=18"
- }
- },
- "node_modules/@emotion/babel-plugin": {
- "version": "11.11.0",
- "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz",
- "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==",
- "dependencies": {
- "@babel/helper-module-imports": "^7.16.7",
- "@babel/runtime": "^7.18.3",
- "@emotion/hash": "^0.9.1",
- "@emotion/memoize": "^0.8.1",
- "@emotion/serialize": "^1.1.2",
- "babel-plugin-macros": "^3.1.0",
- "convert-source-map": "^1.5.0",
- "escape-string-regexp": "^4.0.0",
- "find-root": "^1.1.0",
- "source-map": "^0.5.7",
- "stylis": "4.2.0"
- }
- },
- "node_modules/@emotion/babel-plugin/node_modules/source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/@emotion/cache": {
- "version": "11.11.0",
- "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz",
- "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==",
- "dependencies": {
- "@emotion/memoize": "^0.8.1",
- "@emotion/sheet": "^1.2.2",
- "@emotion/utils": "^1.2.1",
- "@emotion/weak-memoize": "^0.3.1",
- "stylis": "4.2.0"
- }
- },
- "node_modules/@emotion/hash": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz",
- "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ=="
- },
- "node_modules/@emotion/is-prop-valid": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz",
- "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==",
- "dependencies": {
- "@emotion/memoize": "^0.8.1"
- }
- },
- "node_modules/@emotion/memoize": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
- "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
- },
- "node_modules/@emotion/react": {
- "version": "11.11.3",
- "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz",
- "integrity": "sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==",
- "dependencies": {
- "@babel/runtime": "^7.18.3",
- "@emotion/babel-plugin": "^11.11.0",
- "@emotion/cache": "^11.11.0",
- "@emotion/serialize": "^1.1.3",
- "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1",
- "@emotion/utils": "^1.2.1",
- "@emotion/weak-memoize": "^0.3.1",
- "hoist-non-react-statics": "^3.3.1"
- },
- "peerDependencies": {
- "react": ">=16.8.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/@emotion/serialize": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz",
- "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==",
- "dependencies": {
- "@emotion/hash": "^0.9.1",
- "@emotion/memoize": "^0.8.1",
- "@emotion/unitless": "^0.8.1",
- "@emotion/utils": "^1.2.1",
- "csstype": "^3.0.2"
- }
- },
- "node_modules/@emotion/sheet": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz",
- "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA=="
- },
- "node_modules/@emotion/styled": {
- "version": "11.11.0",
- "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz",
- "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==",
- "dependencies": {
- "@babel/runtime": "^7.18.3",
- "@emotion/babel-plugin": "^11.11.0",
- "@emotion/is-prop-valid": "^1.2.1",
- "@emotion/serialize": "^1.1.2",
- "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1",
- "@emotion/utils": "^1.2.1"
- },
- "peerDependencies": {
- "@emotion/react": "^11.0.0-rc.0",
- "react": ">=16.8.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/@emotion/unitless": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz",
- "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ=="
- },
- "node_modules/@emotion/use-insertion-effect-with-fallbacks": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz",
- "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==",
- "peerDependencies": {
- "react": ">=16.8.0"
- }
- },
- "node_modules/@emotion/utils": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz",
- "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg=="
- },
- "node_modules/@emotion/weak-memoize": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz",
- "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww=="
- },
- "node_modules/@esbuild/android-arm": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.8.tgz",
- "integrity": "sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-arm64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz",
- "integrity": "sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.8.tgz",
- "integrity": "sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-arm64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz",
- "integrity": "sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz",
- "integrity": "sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-arm64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz",
- "integrity": "sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz",
- "integrity": "sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz",
- "integrity": "sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz",
- "integrity": "sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ia32": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz",
- "integrity": "sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-loong64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz",
- "integrity": "sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-mips64el": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz",
- "integrity": "sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ppc64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz",
- "integrity": "sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-riscv64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz",
- "integrity": "sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-s390x": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz",
- "integrity": "sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz",
- "integrity": "sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/netbsd-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz",
- "integrity": "sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/openbsd-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz",
- "integrity": "sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/sunos-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz",
- "integrity": "sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-arm64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz",
- "integrity": "sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-ia32": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz",
- "integrity": "sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz",
- "integrity": "sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@hey-api/openapi-ts": {
- "version": "0.34.1",
- "resolved": "https://registry.npmjs.org/@hey-api/openapi-ts/-/openapi-ts-0.34.1.tgz",
- "integrity": "sha512-7Ak+0nvf4Nhzk04tXGg6h4eM7lnWRgfjCPmMl2MyXrhS5urxd3Bg/PhtpB84u18wnwcM4rIeCUlTwDDQ/OB3NQ==",
- "dev": true,
- "dependencies": {
- "@apidevtools/json-schema-ref-parser": "11.5.4",
- "camelcase": "8.0.0",
- "commander": "12.0.0",
- "handlebars": "4.7.8"
- },
- "bin": {
- "openapi-ts": "bin/index.js"
- },
- "engines": {
- "node": "^18.0.0 || >=20.0.0"
- }
- },
- "node_modules/@hey-api/openapi-ts/node_modules/@apidevtools/json-schema-ref-parser": {
- "version": "11.5.4",
- "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.5.4.tgz",
- "integrity": "sha512-o2fsypTGU0WxRxbax8zQoHiIB4dyrkwYfcm8TxZ+bx9pCzcWZbQtiMqpgBvWA/nJ2TrGjK5adCLfTH8wUeU/Wg==",
- "dev": true,
- "dependencies": {
- "@jsdevtools/ono": "^7.1.3",
- "@types/json-schema": "^7.0.15",
- "js-yaml": "^4.1.0"
- },
- "engines": {
- "node": ">= 16"
- },
- "funding": {
- "url": "https://github.com/sponsors/philsturgeon"
- }
- },
- "node_modules/@hey-api/openapi-ts/node_modules/camelcase": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz",
- "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==",
- "dev": true,
- "engines": {
- "node": ">=16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@hey-api/openapi-ts/node_modules/commander": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz",
- "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==",
- "dev": true,
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@jsdevtools/ono": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
- "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
- "dev": true
- },
- "node_modules/@playwright/test": {
- "version": "1.45.2",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.2.tgz",
- "integrity": "sha512-JxG9eq92ET75EbVi3s+4sYbcG7q72ECeZNbdBlaMkGcNbiDQ4cAi8U2QP5oKkOx+1gpaiL1LDStmzCaEM1Z6fQ==",
- "dev": true,
- "dependencies": {
- "playwright": "1.45.2"
- },
- "bin": {
- "playwright": "cli.js"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@popperjs/core": {
- "version": "2.11.8",
- "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
- "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/popperjs"
- }
- },
- "node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.6.1.tgz",
- "integrity": "sha512-0WQ0ouLejaUCRsL93GD4uft3rOmB8qoQMU05Kb8CmMtMBe7XUDLAltxVZI1q6byNqEtU7N1ZX1Vw5lIpgulLQA==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ]
- },
- "node_modules/@rollup/rollup-android-arm64": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.6.1.tgz",
- "integrity": "sha512-1TKm25Rn20vr5aTGGZqo6E4mzPicCUD79k17EgTLAsXc1zysyi4xXKACfUbwyANEPAEIxkzwue6JZ+stYzWUTA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ]
- },
- "node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.6.1.tgz",
- "integrity": "sha512-cEXJQY/ZqMACb+nxzDeX9IPLAg7S94xouJJCNVE5BJM8JUEP4HeTF+ti3cmxWeSJo+5D+o8Tc0UAWUkfENdeyw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.6.1.tgz",
- "integrity": "sha512-LoSU9Xu56isrkV2jLldcKspJ7sSXmZWkAxg7sW/RfF7GS4F5/v4EiqKSMCFbZtDu2Nc1gxxFdQdKwkKS4rwxNg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.6.1.tgz",
- "integrity": "sha512-EfI3hzYAy5vFNDqpXsNxXcgRDcFHUWSx5nnRSCKwXuQlI5J9dD84g2Usw81n3FLBNsGCegKGwwTVsSKK9cooSQ==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.6.1.tgz",
- "integrity": "sha512-9lhc4UZstsegbNLhH0Zu6TqvDfmhGzuCWtcTFXY10VjLLUe4Mr0Ye2L3rrtHaDd/J5+tFMEuo5LTCSCMXWfUKw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.6.1.tgz",
- "integrity": "sha512-FfoOK1yP5ksX3wwZ4Zk1NgyGHZyuRhf99j64I5oEmirV8EFT7+OhUZEnP+x17lcP/QHJNWGsoJwrz4PJ9fBEXw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.6.1.tgz",
- "integrity": "sha512-DNGZvZDO5YF7jN5fX8ZqmGLjZEXIJRdJEdTFMhiyXqyXubBa0WVLDWSNlQ5JR2PNgDbEV1VQowhVRUh+74D+RA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.6.1.tgz",
- "integrity": "sha512-RkJVNVRM+piYy87HrKmhbexCHg3A6Z6MU0W9GHnJwBQNBeyhCJG9KDce4SAMdicQnpURggSvtbGo9xAWOfSvIQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.6.1.tgz",
- "integrity": "sha512-v2FVT6xfnnmTe3W9bJXl6r5KwJglMK/iRlkKiIFfO6ysKs0rDgz7Cwwf3tjldxQUrHL9INT/1r4VA0n9L/F1vQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.6.1.tgz",
- "integrity": "sha512-YEeOjxRyEjqcWphH9dyLbzgkF8wZSKAKUkldRY6dgNR5oKs2LZazqGB41cWJ4Iqqcy9/zqYgmzBkRoVz3Q9MLw==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.6.1.tgz",
- "integrity": "sha512-0zfTlFAIhgz8V2G8STq8toAjsYYA6eci1hnXuyOTUFnymrtJwnS6uGKiv3v5UrPZkBlamLvrLV2iiaeqCKzb0A==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@swc/core": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.100.tgz",
- "integrity": "sha512-7dKgTyxJjlrMwFZYb1auj3Xq0D8ZBe+5oeIgfMlRU05doXZypYJe0LAk0yjj3WdbwYzpF+T1PLxwTWizI0pckw==",
- "dev": true,
- "hasInstallScript": true,
- "dependencies": {
- "@swc/counter": "^0.1.1",
- "@swc/types": "^0.1.5"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/swc"
- },
- "optionalDependencies": {
- "@swc/core-darwin-arm64": "1.3.100",
- "@swc/core-darwin-x64": "1.3.100",
- "@swc/core-linux-arm64-gnu": "1.3.100",
- "@swc/core-linux-arm64-musl": "1.3.100",
- "@swc/core-linux-x64-gnu": "1.3.100",
- "@swc/core-linux-x64-musl": "1.3.100",
- "@swc/core-win32-arm64-msvc": "1.3.100",
- "@swc/core-win32-ia32-msvc": "1.3.100",
- "@swc/core-win32-x64-msvc": "1.3.100"
- },
- "peerDependencies": {
- "@swc/helpers": "^0.5.0"
- },
- "peerDependenciesMeta": {
- "@swc/helpers": {
- "optional": true
- }
- }
- },
- "node_modules/@swc/core-darwin-arm64": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.100.tgz",
- "integrity": "sha512-XVWFsKe6ei+SsDbwmsuRkYck1SXRpO60Hioa4hoLwR8fxbA9eVp6enZtMxzVVMBi8ej5seZ4HZQeAWepbukiBw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-darwin-x64": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.100.tgz",
- "integrity": "sha512-KF/MXrnH1nakm1wbt4XV8FS7kvqD9TGmVxeJ0U4bbvxXMvzeYUurzg3AJUTXYmXDhH/VXOYJE5N5RkwZZPs5iA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-linux-arm64-gnu": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.100.tgz",
- "integrity": "sha512-p8hikNnAEJrw5vHCtKiFT4hdlQxk1V7vqPmvUDgL/qe2menQDK/i12tbz7/3BEQ4UqUPnvwpmVn2d19RdEMNxw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-linux-arm64-musl": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.100.tgz",
- "integrity": "sha512-BWx/0EeY89WC4q3AaIaBSGfQxkYxIlS3mX19dwy2FWJs/O+fMvF9oLk/CyJPOZzbp+1DjGeeoGFuDYpiNO91JA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-linux-x64-gnu": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.100.tgz",
- "integrity": "sha512-XUdGu3dxAkjsahLYnm8WijPfKebo+jHgHphDxaW0ovI6sTdmEGFDew7QzKZRlbYL2jRkUuuKuDGvD6lO5frmhA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-linux-x64-musl": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.100.tgz",
- "integrity": "sha512-PhoXKf+f0OaNW/GCuXjJ0/KfK9EJX7z2gko+7nVnEA0p3aaPtbP6cq1Ubbl6CMoPL+Ci3gZ7nYumDqXNc3CtLQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-win32-arm64-msvc": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.100.tgz",
- "integrity": "sha512-PwLADZN6F9cXn4Jw52FeP/MCLVHm8vwouZZSOoOScDtihjY495SSjdPnlosMaRSR4wJQssGwiD/4MbpgQPqbAw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-win32-ia32-msvc": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.100.tgz",
- "integrity": "sha512-0f6nicKSLlDKlyPRl2JEmkpBV4aeDfRQg6n8mPqgL7bliZIcDahG0ej+HxgNjZfS3e0yjDxsNRa6sAqWU2Z60A==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-win32-x64-msvc": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.100.tgz",
- "integrity": "sha512-b7J0rPoMkRTa3XyUGt8PwCaIBuYWsL2DqbirrQKRESzgCvif5iNpqaM6kjIjI/5y5q1Ycv564CB51YDpiS8EtQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/counter": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz",
- "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==",
- "dev": true
- },
- "node_modules/@swc/types": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz",
- "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==",
- "dev": true
- },
- "node_modules/@tanstack/history": {
- "version": "1.15.13",
- "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.15.13.tgz",
- "integrity": "sha512-ToaeMtK5S4YaxCywAlYexc7KPFN0esjyTZ4vXzJhXEWAkro9iHgh7m/4ozPJb7oTo65WkHWX0W9GjcZbInSD8w==",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/query-core": {
- "version": "5.28.13",
- "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.28.13.tgz",
- "integrity": "sha512-C3+CCOcza+mrZ7LglQbjeYEOTEC3LV0VN0eYaIN6GvqAZ8Foegdgch7n6QYPtT4FuLae5ALy+m+ZMEKpD6tMCQ==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/query-devtools": {
- "version": "5.28.10",
- "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.28.10.tgz",
- "integrity": "sha512-5UN629fKa5/1K/2Pd26gaU7epxRrYiT1gy+V+pW5K6hnf1DeUKK3pANSb2eHKlecjIKIhTwyF7k9XdyE2gREvQ==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/react-query": {
- "version": "5.28.14",
- "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.28.14.tgz",
- "integrity": "sha512-cZqt03Igb3I9tM72qNX5TAAmeYl75Z+k4Mv92VkXIXc2hCrv0fIywd7GN3JV1BBJl4mr7Cc+OOKKOPy8sNVOkA==",
- "dependencies": {
- "@tanstack/query-core": "5.28.13"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "react": "^18.0.0"
- }
- },
- "node_modules/@tanstack/react-query-devtools": {
- "version": "5.28.14",
- "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.28.14.tgz",
- "integrity": "sha512-4CrFBI1O5wibV1ZdGAnBMmTuc7SiShhxWubxRMyIloeEioxs3DQkFbouGBea5nexuwIxAkvhUB8khpPnNjhxMw==",
- "dependencies": {
- "@tanstack/query-devtools": "5.28.10"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "@tanstack/react-query": "^5.28.14",
- "react": "^18.0.0"
- }
- },
- "node_modules/@tanstack/react-router": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.19.1.tgz",
- "integrity": "sha512-a4Xf074qo2fQLmSi8PTncEFn8XakaH3+DT7Dted4OPClzQFS+c6yU3HONVNAsuYWZ7lDK1HMKoHPDFbnHPEWvA==",
- "dependencies": {
- "@tanstack/history": "1.15.13",
- "@tanstack/react-store": "^0.2.1",
- "tiny-invariant": "^1.3.1",
- "tiny-warning": "^1.0.3"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "react": ">=16",
- "react-dom": ">=16"
- }
- },
- "node_modules/@tanstack/react-store": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.2.1.tgz",
- "integrity": "sha512-tEbMCQjbeVw9KOP/202LfqZMSNAVi6zYkkp1kBom8nFuMx/965Hzes3+6G6b/comCwVxoJU8Gg9IrcF8yRPthw==",
- "dependencies": {
- "@tanstack/store": "0.1.3",
- "use-sync-external-store": "^1.2.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "react": ">=16",
- "react-dom": ">=16"
- }
- },
- "node_modules/@tanstack/router-devtools": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/@tanstack/router-devtools/-/router-devtools-1.19.1.tgz",
- "integrity": "sha512-l560JHnffcDccSTo/sOtB+gKvtgaWYpOKOu9MyvswN9XB2pt752UFFIN1Yt/Gsp2Iooq/FcYlYnEPHb4GFzalg==",
- "dev": true,
- "dependencies": {
- "@tanstack/react-router": "1.19.1",
- "clsx": "^2.1.0",
- "date-fns": "^2.29.1",
- "goober": "^2.1.14"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "react": ">=16",
- "react-dom": ">=16"
- }
- },
- "node_modules/@tanstack/router-generator": {
- "version": "1.19.0",
- "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.19.0.tgz",
- "integrity": "sha512-vFF8Q7SdyygiYC7lfJ83GRif0vcxjak9SAcgtX/w7TLR0O+qdxRXFPvhKTQQXH6vVezy5Au9bSaSI2EgDD1ubA==",
- "dev": true,
- "dependencies": {
- "prettier": "^3.1.1",
- "zod": "^3.22.4"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/router-vite-plugin": {
- "version": "1.19.0",
- "resolved": "https://registry.npmjs.org/@tanstack/router-vite-plugin/-/router-vite-plugin-1.19.0.tgz",
- "integrity": "sha512-yvvQnJ7JvqsnxAFqwiHhNTV2n1jKkidjc+XbgS2aNnEHC0aHnYH2ygPlmmfiVD7PMO7x64PdI5e12TzY/aKoFA==",
- "dev": true,
- "dependencies": {
- "@tanstack/router-generator": "1.19.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@tanstack/store": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.1.3.tgz",
- "integrity": "sha512-GnolmC8Fr4mvsHE1fGQmR3Nm0eBO3KnZjDU0a+P3TeQNM/dDscFGxtA7p31NplQNW3KwBw4t1RVFmz0VeKLxcw==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
- "node_modules/@types/json-schema": {
- "version": "7.0.15",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
- "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
- "dev": true
- },
- "node_modules/@types/lodash": {
- "version": "4.14.202",
- "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
- "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ=="
- },
- "node_modules/@types/lodash.mergewith": {
- "version": "4.6.7",
- "resolved": "https://registry.npmjs.org/@types/lodash.mergewith/-/lodash.mergewith-4.6.7.tgz",
- "integrity": "sha512-3m+lkO5CLRRYU0fhGRp7zbsGi6+BZj0uTVSwvcKU+nSlhjA9/QRNfuSGnD2mX6hQA7ZbmcCkzk5h4ZYGOtk14A==",
- "dependencies": {
- "@types/lodash": "*"
- }
- },
- "node_modules/@types/node": {
- "version": "20.10.5",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz",
- "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==",
- "dev": true,
- "dependencies": {
- "undici-types": "~5.26.4"
- }
- },
- "node_modules/@types/parse-json": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
- "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="
- },
- "node_modules/@types/prop-types": {
- "version": "15.7.11",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz",
- "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==",
- "devOptional": true
- },
- "node_modules/@types/react": {
- "version": "18.2.39",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.39.tgz",
- "integrity": "sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==",
- "devOptional": true,
- "dependencies": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- }
- },
- "node_modules/@types/react-dom": {
- "version": "18.2.17",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.17.tgz",
- "integrity": "sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==",
- "dev": true,
- "dependencies": {
- "@types/react": "*"
- }
- },
- "node_modules/@types/scheduler": {
- "version": "0.16.8",
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
- "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==",
- "devOptional": true
- },
- "node_modules/@vitejs/plugin-react-swc": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.5.0.tgz",
- "integrity": "sha512-1PrOvAaDpqlCV+Up8RkAh9qaiUjoDUcjtttyhXDKw53XA6Ve16SOp6cCOpRs8Dj8DqUQs6eTW5YkLcLJjrXAig==",
- "dev": true,
- "dependencies": {
- "@swc/core": "^1.3.96"
- },
- "peerDependencies": {
- "vite": "^4 || ^5"
- }
- },
- "node_modules/@zag-js/dom-query": {
- "version": "0.16.0",
- "resolved": "https://registry.npmjs.org/@zag-js/dom-query/-/dom-query-0.16.0.tgz",
- "integrity": "sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ=="
- },
- "node_modules/@zag-js/element-size": {
- "version": "0.10.5",
- "resolved": "https://registry.npmjs.org/@zag-js/element-size/-/element-size-0.10.5.tgz",
- "integrity": "sha512-uQre5IidULANvVkNOBQ1tfgwTQcGl4hliPSe69Fct1VfYb2Fd0jdAcGzqQgPhfrXFpR62MxLPB7erxJ/ngtL8w=="
- },
- "node_modules/@zag-js/focus-visible": {
- "version": "0.16.0",
- "resolved": "https://registry.npmjs.org/@zag-js/focus-visible/-/focus-visible-0.16.0.tgz",
- "integrity": "sha512-a7U/HSopvQbrDU4GLerpqiMcHKEkQkNPeDZJWz38cw/6Upunh41GjHetq5TB84hxyCaDzJ6q2nEdNoBQfC0FKA==",
- "dependencies": {
- "@zag-js/dom-query": "0.16.0"
- }
- },
- "node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "node_modules/aria-hidden": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz",
- "integrity": "sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==",
- "dependencies": {
- "tslib": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
- },
- "node_modules/axios": {
- "version": "1.7.4",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz",
- "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==",
- "dependencies": {
- "follow-redirects": "^1.15.6",
- "form-data": "^4.0.0",
- "proxy-from-env": "^1.1.0"
- }
- },
- "node_modules/babel-plugin-macros": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
- "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "cosmiconfig": "^7.0.0",
- "resolve": "^1.19.0"
- },
- "engines": {
- "node": ">=10",
- "npm": ">=6"
- }
- },
- "node_modules/callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/clsx": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
- "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/color2k": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/color2k/-/color2k-2.0.3.tgz",
- "integrity": "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog=="
- },
- "node_modules/combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/compute-scroll-into-view": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.0.3.tgz",
- "integrity": "sha512-nadqwNxghAGTamwIqQSG433W6OADZx2vCo3UXHNrzTRHK/htu+7+L0zhjEoaeaQVNAi3YgqWDv8+tzf0hRfR+A=="
- },
- "node_modules/convert-source-map": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
- "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
- },
- "node_modules/copy-to-clipboard": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
- "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
- "dependencies": {
- "toggle-selection": "^1.0.6"
- }
- },
- "node_modules/cosmiconfig": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
- "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
- "dependencies": {
- "@types/parse-json": "^4.0.0",
- "import-fresh": "^3.2.1",
- "parse-json": "^5.0.0",
- "path-type": "^4.0.0",
- "yaml": "^1.10.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/css-box-model": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
- "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==",
- "dependencies": {
- "tiny-invariant": "^1.0.6"
- }
- },
- "node_modules/csstype": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
- "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
- },
- "node_modules/date-fns": {
- "version": "2.30.0",
- "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
- "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
- "dev": true,
- "dependencies": {
- "@babel/runtime": "^7.21.0"
- },
- "engines": {
- "node": ">=0.11"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/date-fns"
- }
- },
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/detect-node-es": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
- "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
- },
- "node_modules/dotenv": {
- "version": "16.4.5",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
- "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://dotenvx.com"
- }
- },
- "node_modules/error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
- "dependencies": {
- "is-arrayish": "^0.2.1"
- }
- },
- "node_modules/esbuild": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.8.tgz",
- "integrity": "sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==",
- "dev": true,
- "hasInstallScript": true,
- "bin": {
- "esbuild": "bin/esbuild"
- },
- "engines": {
- "node": ">=12"
- },
- "optionalDependencies": {
- "@esbuild/android-arm": "0.19.8",
- "@esbuild/android-arm64": "0.19.8",
- "@esbuild/android-x64": "0.19.8",
- "@esbuild/darwin-arm64": "0.19.8",
- "@esbuild/darwin-x64": "0.19.8",
- "@esbuild/freebsd-arm64": "0.19.8",
- "@esbuild/freebsd-x64": "0.19.8",
- "@esbuild/linux-arm": "0.19.8",
- "@esbuild/linux-arm64": "0.19.8",
- "@esbuild/linux-ia32": "0.19.8",
- "@esbuild/linux-loong64": "0.19.8",
- "@esbuild/linux-mips64el": "0.19.8",
- "@esbuild/linux-ppc64": "0.19.8",
- "@esbuild/linux-riscv64": "0.19.8",
- "@esbuild/linux-s390x": "0.19.8",
- "@esbuild/linux-x64": "0.19.8",
- "@esbuild/netbsd-x64": "0.19.8",
- "@esbuild/openbsd-x64": "0.19.8",
- "@esbuild/sunos-x64": "0.19.8",
- "@esbuild/win32-arm64": "0.19.8",
- "@esbuild/win32-ia32": "0.19.8",
- "@esbuild/win32-x64": "0.19.8"
- }
- },
- "node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/find-root": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
- "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
- },
- "node_modules/focus-lock": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-1.3.3.tgz",
- "integrity": "sha512-hfXkZha7Xt4RQtrL1HBfspAuIj89Y0fb6GX0dfJilb8S2G/lvL4akPAcHq6xoD2NuZnDMCnZL/zQesMyeu6Psg==",
- "dependencies": {
- "tslib": "^2.0.3"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/follow-redirects": {
- "version": "1.15.6",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
- "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/RubenVerborgh"
- }
- ],
- "engines": {
- "node": ">=4.0"
- },
- "peerDependenciesMeta": {
- "debug": {
- "optional": true
- }
- }
- },
- "node_modules/form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/framer-motion": {
- "version": "10.16.16",
- "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.16.16.tgz",
- "integrity": "sha512-je6j91rd7NmUX7L1XHouwJ4v3R+SO4umso2LUcgOct3rHZ0PajZ80ETYZTajzEXEl9DlKyzjyt4AvGQ+lrebOw==",
- "dependencies": {
- "tslib": "^2.4.0"
- },
- "optionalDependencies": {
- "@emotion/is-prop-valid": "^0.8.2"
- },
- "peerDependencies": {
- "react": "^18.0.0",
- "react-dom": "^18.0.0"
- },
- "peerDependenciesMeta": {
- "react": {
- "optional": true
- },
- "react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/framer-motion/node_modules/@emotion/is-prop-valid": {
- "version": "0.8.8",
- "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
- "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
- "optional": true,
- "dependencies": {
- "@emotion/memoize": "0.7.4"
- }
- },
- "node_modules/framer-motion/node_modules/@emotion/memoize": {
- "version": "0.7.4",
- "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
- "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
- "optional": true
- },
- "node_modules/framesync": {
- "version": "6.1.2",
- "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.1.2.tgz",
- "integrity": "sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==",
- "dependencies": {
- "tslib": "2.4.0"
- }
- },
- "node_modules/framesync/node_modules/tslib": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
- "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
- },
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-nonce": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
- "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/goober": {
- "version": "2.1.14",
- "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.14.tgz",
- "integrity": "sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==",
- "dev": true,
- "peerDependencies": {
- "csstype": "^3.0.10"
- }
- },
- "node_modules/handlebars": {
- "version": "4.7.8",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
- "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
- "dev": true,
- "dependencies": {
- "minimist": "^1.2.5",
- "neo-async": "^2.6.2",
- "source-map": "^0.6.1",
- "wordwrap": "^1.0.0"
- },
- "bin": {
- "handlebars": "bin/handlebars"
- },
- "engines": {
- "node": ">=0.4.7"
- },
- "optionalDependencies": {
- "uglify-js": "^3.1.4"
- }
- },
- "node_modules/hasown": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
- "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/hoist-non-react-statics": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
- "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
- "dependencies": {
- "react-is": "^16.7.0"
- }
- },
- "node_modules/import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/invariant": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
- "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
- "dependencies": {
- "loose-envify": "^1.0.0"
- }
- },
- "node_modules/is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
- },
- "node_modules/is-core-module": {
- "version": "2.13.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
- "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
- "dependencies": {
- "hasown": "^2.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
- },
- "node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/json-parse-even-better-errors": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
- "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
- },
- "node_modules/lines-and-columns": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
- "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
- },
- "node_modules/lodash.mergewith": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
- "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="
- },
- "node_modules/loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/minimist": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
- "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/nanoid": {
- "version": "3.3.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
- "node_modules/neo-async": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
- "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
- "dev": true
- },
- "node_modules/object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dependencies": {
- "callsites": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "dependencies": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
- },
- "node_modules/path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
- },
- "node_modules/playwright": {
- "version": "1.45.2",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.2.tgz",
- "integrity": "sha512-ReywF2t/0teRvNBpfIgh5e4wnrI/8Su8ssdo5XsQKpjxJj+jspm00jSoz9BTg91TT0c9HRjXO7LBNVrgYj9X0g==",
- "dev": true,
- "dependencies": {
- "playwright-core": "1.45.2"
- },
- "bin": {
- "playwright": "cli.js"
- },
- "engines": {
- "node": ">=18"
- },
- "optionalDependencies": {
- "fsevents": "2.3.2"
- }
- },
- "node_modules/playwright-core": {
- "version": "1.45.2",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.2.tgz",
- "integrity": "sha512-ha175tAWb0dTK0X4orvBIqi3jGEt701SMxMhyujxNrgd8K0Uy5wMSwwcQHtyB4om7INUkfndx02XnQ2p6dvLDw==",
- "dev": true,
- "bin": {
- "playwright-core": "cli.js"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/playwright/node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/postcss": {
- "version": "8.4.35",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
- "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/postcss"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "nanoid": "^3.3.7",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- }
- },
- "node_modules/prettier": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
- "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
- "dev": true,
- "bin": {
- "prettier": "bin/prettier.cjs"
- },
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/prop-types": {
- "version": "15.8.1",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dependencies": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
- }
- },
- "node_modules/proxy-from-env": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
- "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
- },
- "node_modules/react": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
- "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/react-clientside-effect": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz",
- "integrity": "sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==",
- "dependencies": {
- "@babel/runtime": "^7.12.13"
- },
- "peerDependencies": {
- "react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
- }
- },
- "node_modules/react-dom": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
- "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.0"
- },
- "peerDependencies": {
- "react": "^18.2.0"
- }
- },
- "node_modules/react-error-boundary": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz",
- "integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==",
- "dependencies": {
- "@babel/runtime": "^7.12.5"
- },
- "peerDependencies": {
- "react": ">=16.13.1"
- }
- },
- "node_modules/react-fast-compare": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
- "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
- },
- "node_modules/react-focus-lock": {
- "version": "2.11.1",
- "resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.11.1.tgz",
- "integrity": "sha512-IXLwnTBrLTlKTpASZXqqXJ8oymWrgAlOfuuDYN4XCuN1YJ72dwX198UCaF1QqGUk5C3QOnlMik//n3ufcfe8Ig==",
- "dependencies": {
- "@babel/runtime": "^7.0.0",
- "focus-lock": "^1.3.2",
- "prop-types": "^15.6.2",
- "react-clientside-effect": "^1.2.6",
- "use-callback-ref": "^1.3.0",
- "use-sidecar": "^1.1.2"
- },
- "peerDependencies": {
- "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/react-hook-form": {
- "version": "7.49.3",
- "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.49.3.tgz",
- "integrity": "sha512-foD6r3juidAT1cOZzpmD/gOKt7fRsDhXXZ0y28+Al1CHgX+AY1qIN9VSIIItXRq1dN68QrRwl1ORFlwjBaAqeQ==",
- "engines": {
- "node": ">=18",
- "pnpm": "8"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/react-hook-form"
- },
- "peerDependencies": {
- "react": "^16.8.0 || ^17 || ^18"
- }
- },
- "node_modules/react-icons": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz",
- "integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==",
- "peerDependencies": {
- "react": "*"
- }
- },
- "node_modules/react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
- },
- "node_modules/react-remove-scroll": {
- "version": "2.5.7",
- "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz",
- "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==",
- "dependencies": {
- "react-remove-scroll-bar": "^2.3.4",
- "react-style-singleton": "^2.2.1",
- "tslib": "^2.1.0",
- "use-callback-ref": "^1.3.0",
- "use-sidecar": "^1.1.2"
- },
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/react-remove-scroll-bar": {
- "version": "2.3.5",
- "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.5.tgz",
- "integrity": "sha512-3cqjOqg6s0XbOjWvmasmqHch+RLxIEk2r/70rzGXuz3iIGQsQheEQyqYCBb5EECoD01Vo2SIbDqW4paLeLTASw==",
- "dependencies": {
- "react-style-singleton": "^2.2.1",
- "tslib": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/react-style-singleton": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
- "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
- "dependencies": {
- "get-nonce": "^1.0.0",
- "invariant": "^2.2.4",
- "tslib": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/regenerator-runtime": {
- "version": "0.14.1",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
- "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
- },
- "node_modules/resolve": {
- "version": "1.22.8",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
- "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
- "dependencies": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/rollup": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.6.1.tgz",
- "integrity": "sha512-jZHaZotEHQaHLgKr8JnQiDT1rmatjgKlMekyksz+yk9jt/8z9quNjnKNRoaM0wd9DC2QKXjmWWuDYtM3jfF8pQ==",
- "dev": true,
- "bin": {
- "rollup": "dist/bin/rollup"
- },
- "engines": {
- "node": ">=18.0.0",
- "npm": ">=8.0.0"
- },
- "optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.6.1",
- "@rollup/rollup-android-arm64": "4.6.1",
- "@rollup/rollup-darwin-arm64": "4.6.1",
- "@rollup/rollup-darwin-x64": "4.6.1",
- "@rollup/rollup-linux-arm-gnueabihf": "4.6.1",
- "@rollup/rollup-linux-arm64-gnu": "4.6.1",
- "@rollup/rollup-linux-arm64-musl": "4.6.1",
- "@rollup/rollup-linux-x64-gnu": "4.6.1",
- "@rollup/rollup-linux-x64-musl": "4.6.1",
- "@rollup/rollup-win32-arm64-msvc": "4.6.1",
- "@rollup/rollup-win32-ia32-msvc": "4.6.1",
- "@rollup/rollup-win32-x64-msvc": "4.6.1",
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/scheduler": {
- "version": "0.23.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
- "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- }
- },
- "node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/stylis": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
- "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
- },
- "node_modules/supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/tiny-invariant": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
- "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
- },
- "node_modules/tiny-warning": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
- "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
- },
- "node_modules/to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/toggle-selection": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
- "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
- },
- "node_modules/tslib": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
- },
- "node_modules/typescript": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz",
- "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==",
- "dev": true,
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
- "node_modules/uglify-js": {
- "version": "3.17.4",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
- "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
- "dev": true,
- "optional": true,
- "bin": {
- "uglifyjs": "bin/uglifyjs"
- },
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/undici-types": {
- "version": "5.26.5",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
- "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
- "dev": true
- },
- "node_modules/use-callback-ref": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.1.tgz",
- "integrity": "sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==",
- "dependencies": {
- "tslib": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/use-sidecar": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
- "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==",
- "dependencies": {
- "detect-node-es": "^1.1.0",
- "tslib": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0",
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/use-sync-external-store": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
- "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
- "peerDependencies": {
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- }
- },
- "node_modules/vite": {
- "version": "5.0.13",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.13.tgz",
- "integrity": "sha512-/9ovhv2M2dGTuA+dY93B9trfyWMDRQw2jdVBhHNP6wr0oF34wG2i/N55801iZIpgUpnHDm4F/FabGQLyc+eOgg==",
- "dev": true,
- "dependencies": {
- "esbuild": "^0.19.3",
- "postcss": "^8.4.32",
- "rollup": "^4.2.0"
- },
- "bin": {
- "vite": "bin/vite.js"
- },
- "engines": {
- "node": "^18.0.0 || >=20.0.0"
- },
- "funding": {
- "url": "https://github.com/vitejs/vite?sponsor=1"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.3"
- },
- "peerDependencies": {
- "@types/node": "^18.0.0 || >=20.0.0",
- "less": "*",
- "lightningcss": "^1.21.0",
- "sass": "*",
- "stylus": "*",
- "sugarss": "*",
- "terser": "^5.4.0"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- },
- "less": {
- "optional": true
- },
- "lightningcss": {
- "optional": true
- },
- "sass": {
- "optional": true
- },
- "stylus": {
- "optional": true
- },
- "sugarss": {
- "optional": true
- },
- "terser": {
- "optional": true
- }
- }
- },
- "node_modules/wordwrap": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
- "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
- "dev": true
- },
- "node_modules/yaml": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
- "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/zod": {
- "version": "3.22.4",
- "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
- "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/colinhacks"
- }
- }
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.23.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
- "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
- "requires": {
- "@babel/highlight": "^7.23.4",
- "chalk": "^2.4.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
- "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
- "requires": {
- "@babel/types": "^7.22.15"
- }
- },
- "@babel/helper-string-parser": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
- "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ=="
- },
- "@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="
- },
- "@babel/highlight": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
- "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
- "requires": {
- "@babel/helper-validator-identifier": "^7.22.20",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "@babel/runtime": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
- "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
- "requires": {
- "regenerator-runtime": "^0.14.0"
- }
- },
- "@babel/types": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz",
- "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==",
- "requires": {
- "@babel/helper-string-parser": "^7.23.4",
- "@babel/helper-validator-identifier": "^7.22.20",
- "to-fast-properties": "^2.0.0"
- }
- },
- "@biomejs/biome": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.6.1.tgz",
- "integrity": "sha512-SILQvA2S0XeaOuu1bivv6fQmMo7zMfr2xqDEN+Sz78pGbAKZnGmg0emsXjQWoBY/RVm9kPCgX+aGEpZZTYaM7w==",
- "dev": true,
- "requires": {
- "@biomejs/cli-darwin-arm64": "1.6.1",
- "@biomejs/cli-darwin-x64": "1.6.1",
- "@biomejs/cli-linux-arm64": "1.6.1",
- "@biomejs/cli-linux-arm64-musl": "1.6.1",
- "@biomejs/cli-linux-x64": "1.6.1",
- "@biomejs/cli-linux-x64-musl": "1.6.1",
- "@biomejs/cli-win32-arm64": "1.6.1",
- "@biomejs/cli-win32-x64": "1.6.1"
- }
- },
- "@biomejs/cli-darwin-arm64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.6.1.tgz",
- "integrity": "sha512-KlvY00iB9T/vFi4m/GXxEyYkYnYy6aw06uapzUIIdiMMj7I/pmZu7CsZlzWdekVD0j+SsQbxdZMsb0wPhnRSsg==",
- "dev": true,
- "optional": true
- },
- "@biomejs/cli-darwin-x64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.6.1.tgz",
- "integrity": "sha512-jP4E8TXaQX5e3nvRJSzB+qicZrdIDCrjR0sSb1DaDTx4JPZH5WXq/BlTqAyWi3IijM+IYMjWqAAK4kOHsSCzxw==",
- "dev": true,
- "optional": true
- },
- "@biomejs/cli-linux-arm64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.6.1.tgz",
- "integrity": "sha512-nxD1UyX3bWSl/RSKlib/JsOmt+652/9yieogdSC/UTLgVCZYOF7u8L/LK7kAa0Y4nA8zSPavAQTgko7mHC2ObA==",
- "dev": true,
- "optional": true
- },
- "@biomejs/cli-linux-arm64-musl": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.1.tgz",
- "integrity": "sha512-YdkDgFecdHJg7PJxAMaZIixVWGB6St4yH08BHagO0fEhNNiY8cAKEVo2mcXlsnEiTMpeSEAY9VxLUrVT3IVxpw==",
- "dev": true,
- "optional": true
- },
- "@biomejs/cli-linux-x64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.6.1.tgz",
- "integrity": "sha512-BYAzenlMF3QdngjNFw9QVBXKGNzeecqwF3pwDgUGEvU7OJpn1/lyVkJVxYPtVGRNdjQ9e6l/s8NjKuBpW/ZR4Q==",
- "dev": true,
- "optional": true
- },
- "@biomejs/cli-linux-x64-musl": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.1.tgz",
- "integrity": "sha512-aSISIDmxq04NNy7tm4x9rBk2vH0ub2VDIE4outEmdC2LBtEJoINiphlZagx/FvjbsqUfygent9QUSn0oREnAXg==",
- "dev": true,
- "optional": true
- },
- "@biomejs/cli-win32-arm64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.6.1.tgz",
- "integrity": "sha512-/eCHQKZ1kEawUpkSuXq4urtxMsD1P1678OPG3zNKt3ru16AqqspLdO3jzBe3k74xCPYnQ36e9Yqc97Mo0qgPtg==",
- "dev": true,
- "optional": true
- },
- "@biomejs/cli-win32-x64": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.6.1.tgz",
- "integrity": "sha512-5TUZbzBwnDLFxLVGEPsorNi6eC2Gt+z4Oei9Qvq0M/4c4/mjZ96ABgwao/tMxf4ZBr/qyy2YdvF+gX9Rc+xC0A==",
- "dev": true,
- "optional": true
- },
- "@chakra-ui/accordion": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/accordion/-/accordion-2.3.1.tgz",
- "integrity": "sha512-FSXRm8iClFyU+gVaXisOSEw0/4Q+qZbFRiuhIAkVU6Boj0FxAMrlo9a8AV5TuF77rgaHytCdHk0Ng+cyUijrag==",
- "requires": {
- "@chakra-ui/descendant": "3.1.0",
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/transition": "2.1.0"
- }
- },
- "@chakra-ui/alert": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/alert/-/alert-2.2.2.tgz",
- "integrity": "sha512-jHg4LYMRNOJH830ViLuicjb3F+v6iriE/2G5T+Sd0Hna04nukNJ1MxUmBPE+vI22me2dIflfelu2v9wdB6Pojw==",
- "requires": {
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/spinner": "2.1.0"
- }
- },
- "@chakra-ui/anatomy": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/anatomy/-/anatomy-2.2.2.tgz",
- "integrity": "sha512-MV6D4VLRIHr4PkW4zMyqfrNS1mPlCTiCXwvYGtDFQYr+xHFfonhAuf9WjsSc0nyp2m0OdkSLnzmVKkZFLo25Tg=="
- },
- "@chakra-ui/avatar": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/avatar/-/avatar-2.3.0.tgz",
- "integrity": "sha512-8gKSyLfygnaotbJbDMHDiJoF38OHXUYVme4gGxZ1fLnQEdPVEaIWfH+NndIjOM0z8S+YEFnT9KyGMUtvPrBk3g==",
- "requires": {
- "@chakra-ui/image": "2.1.0",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/breadcrumb": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/breadcrumb/-/breadcrumb-2.2.0.tgz",
- "integrity": "sha512-4cWCG24flYBxjruRi4RJREWTGF74L/KzI2CognAW/d/zWR0CjiScuJhf37Am3LFbCySP6WSoyBOtTIoTA4yLEA==",
- "requires": {
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/breakpoint-utils": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/@chakra-ui/breakpoint-utils/-/breakpoint-utils-2.0.8.tgz",
- "integrity": "sha512-Pq32MlEX9fwb5j5xx8s18zJMARNHlQZH2VH1RZgfgRDpp7DcEgtRW5AInfN5CfqdHLO1dGxA7I3MqEuL5JnIsA==",
- "requires": {
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/button": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/button/-/button-2.1.0.tgz",
- "integrity": "sha512-95CplwlRKmmUXkdEp/21VkEWgnwcx2TOBG6NfYlsuLBDHSLlo5FKIiE2oSi4zXc4TLcopGcWPNcm/NDaSC5pvA==",
- "requires": {
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/spinner": "2.1.0"
- }
- },
- "@chakra-ui/card": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/card/-/card-2.2.0.tgz",
- "integrity": "sha512-xUB/k5MURj4CtPAhdSoXZidUbm8j3hci9vnc+eZJVDqhDOShNlD6QeniQNRPRys4lWAQLCbFcrwL29C8naDi6g==",
- "requires": {
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/checkbox": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/checkbox/-/checkbox-2.3.2.tgz",
- "integrity": "sha512-85g38JIXMEv6M+AcyIGLh7igNtfpAN6KGQFYxY9tBj0eWvWk4NKQxvqqyVta0bSAyIl1rixNIIezNpNWk2iO4g==",
- "requires": {
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-callback-ref": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/visually-hidden": "2.2.0",
- "@zag-js/focus-visible": "0.16.0"
- }
- },
- "@chakra-ui/clickable": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/clickable/-/clickable-2.1.0.tgz",
- "integrity": "sha512-flRA/ClPUGPYabu+/GLREZVZr9j2uyyazCAUHAdrTUEdDYCr31SVGhgh7dgKdtq23bOvAQJpIJjw/0Bs0WvbXw==",
- "requires": {
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/close-button": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/close-button/-/close-button-2.1.1.tgz",
- "integrity": "sha512-gnpENKOanKexswSVpVz7ojZEALl2x5qjLYNqSQGbxz+aP9sOXPfUS56ebyBrre7T7exuWGiFeRwnM0oVeGPaiw==",
- "requires": {
- "@chakra-ui/icon": "3.2.0"
- }
- },
- "@chakra-ui/color-mode": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/color-mode/-/color-mode-2.2.0.tgz",
- "integrity": "sha512-niTEA8PALtMWRI9wJ4LL0CSBDo8NBfLNp4GD6/0hstcm3IlbBHTVKxN6HwSaoNYfphDQLxCjT4yG+0BJA5tFpg==",
- "requires": {
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0"
- }
- },
- "@chakra-ui/control-box": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/control-box/-/control-box-2.1.0.tgz",
- "integrity": "sha512-gVrRDyXFdMd8E7rulL0SKeoljkLQiPITFnsyMO8EFHNZ+AHt5wK4LIguYVEq88APqAGZGfHFWXr79RYrNiE3Mg==",
- "requires": {}
- },
- "@chakra-ui/counter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/counter/-/counter-2.1.0.tgz",
- "integrity": "sha512-s6hZAEcWT5zzjNz2JIWUBzRubo9la/oof1W7EKZVVfPYHERnl5e16FmBC79Yfq8p09LQ+aqFKm/etYoJMMgghw==",
- "requires": {
- "@chakra-ui/number-utils": "2.0.7",
- "@chakra-ui/react-use-callback-ref": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/css-reset": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-2.3.0.tgz",
- "integrity": "sha512-cQwwBy5O0jzvl0K7PLTLgp8ijqLPKyuEMiDXwYzl95seD3AoeuoCLyzZcJtVqaUZ573PiBdAbY/IlZcwDOItWg==",
- "requires": {}
- },
- "@chakra-ui/descendant": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/descendant/-/descendant-3.1.0.tgz",
- "integrity": "sha512-VxCIAir08g5w27klLyi7PVo8BxhW4tgU/lxQyujkmi4zx7hT9ZdrcQLAted/dAa+aSIZ14S1oV0Q9lGjsAdxUQ==",
- "requires": {
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0"
- }
- },
- "@chakra-ui/dom-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/dom-utils/-/dom-utils-2.1.0.tgz",
- "integrity": "sha512-ZmF2qRa1QZ0CMLU8M1zCfmw29DmPNtfjR9iTo74U5FPr3i1aoAh7fbJ4qAlZ197Xw9eAW28tvzQuoVWeL5C7fQ=="
- },
- "@chakra-ui/editable": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/editable/-/editable-3.1.0.tgz",
- "integrity": "sha512-j2JLrUL9wgg4YA6jLlbU88370eCRyor7DZQD9lzpY95tSOXpTljeg3uF9eOmDnCs6fxp3zDWIfkgMm/ExhcGTg==",
- "requires": {
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-callback-ref": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-focus-on-pointer-down": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/event-utils": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/@chakra-ui/event-utils/-/event-utils-2.0.8.tgz",
- "integrity": "sha512-IGM/yGUHS+8TOQrZGpAKOJl/xGBrmRYJrmbHfUE7zrG3PpQyXvbLDP1M+RggkCFVgHlJi2wpYIf0QtQlU0XZfw=="
- },
- "@chakra-ui/focus-lock": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/focus-lock/-/focus-lock-2.1.0.tgz",
- "integrity": "sha512-EmGx4PhWGjm4dpjRqM4Aa+rCWBxP+Rq8Uc/nAVnD4YVqkEhBkrPTpui2lnjsuxqNaZ24fIAZ10cF1hlpemte/w==",
- "requires": {
- "@chakra-ui/dom-utils": "2.1.0",
- "react-focus-lock": "^2.9.4"
- }
- },
- "@chakra-ui/form-control": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/form-control/-/form-control-2.2.0.tgz",
- "integrity": "sha512-wehLC1t4fafCVJ2RvJQT2jyqsAwX7KymmiGqBu7nQoQz8ApTkGABWpo/QwDh3F/dBLrouHDoOvGmYTqft3Mirw==",
- "requires": {
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/hooks": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/hooks/-/hooks-2.2.1.tgz",
- "integrity": "sha512-RQbTnzl6b1tBjbDPf9zGRo9rf/pQMholsOudTxjy4i9GfTfz6kgp5ValGjQm2z7ng6Z31N1cnjZ1AlSzQ//ZfQ==",
- "requires": {
- "@chakra-ui/react-utils": "2.0.12",
- "@chakra-ui/utils": "2.0.15",
- "compute-scroll-into-view": "3.0.3",
- "copy-to-clipboard": "3.3.3"
- }
- },
- "@chakra-ui/icon": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/icon/-/icon-3.2.0.tgz",
- "integrity": "sha512-xxjGLvlX2Ys4H0iHrI16t74rG9EBcpFvJ3Y3B7KMQTrnW34Kf7Da/UC8J67Gtx85mTHW020ml85SVPKORWNNKQ==",
- "requires": {
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/icons": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/icons/-/icons-2.1.1.tgz",
- "integrity": "sha512-3p30hdo4LlRZTT5CwoAJq3G9fHI0wDc0pBaMHj4SUn0yomO+RcDRlzhdXqdr5cVnzax44sqXJVnf3oQG0eI+4g==",
- "requires": {
- "@chakra-ui/icon": "3.2.0"
- }
- },
- "@chakra-ui/image": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/image/-/image-2.1.0.tgz",
- "integrity": "sha512-bskumBYKLiLMySIWDGcz0+D9Th0jPvmX6xnRMs4o92tT3Od/bW26lahmV2a2Op2ItXeCmRMY+XxJH5Gy1i46VA==",
- "requires": {
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/input": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/input/-/input-2.1.2.tgz",
- "integrity": "sha512-GiBbb3EqAA8Ph43yGa6Mc+kUPjh4Spmxp1Pkelr8qtudpc3p2PJOOebLpd90mcqw8UePPa+l6YhhPtp6o0irhw==",
- "requires": {
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/object-utils": "2.1.0",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/layout": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/layout/-/layout-2.3.1.tgz",
- "integrity": "sha512-nXuZ6WRbq0WdgnRgLw+QuxWAHuhDtVX8ElWqcTK+cSMFg/52eVP47czYBE5F35YhnoW2XBwfNoNgZ7+e8Z01Rg==",
- "requires": {
- "@chakra-ui/breakpoint-utils": "2.0.8",
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/object-utils": "2.1.0",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/lazy-utils": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@chakra-ui/lazy-utils/-/lazy-utils-2.0.5.tgz",
- "integrity": "sha512-UULqw7FBvcckQk2n3iPO56TMJvDsNv0FKZI6PlUNJVaGsPbsYxK/8IQ60vZgaTVPtVcjY6BE+y6zg8u9HOqpyg=="
- },
- "@chakra-ui/live-region": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/live-region/-/live-region-2.1.0.tgz",
- "integrity": "sha512-ZOxFXwtaLIsXjqnszYYrVuswBhnIHHP+XIgK1vC6DePKtyK590Wg+0J0slDwThUAd4MSSIUa/nNX84x1GMphWw==",
- "requires": {}
- },
- "@chakra-ui/media-query": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/media-query/-/media-query-3.3.0.tgz",
- "integrity": "sha512-IsTGgFLoICVoPRp9ykOgqmdMotJG0CnPsKvGQeSFOB/dZfIujdVb14TYxDU4+MURXry1MhJ7LzZhv+Ml7cr8/g==",
- "requires": {
- "@chakra-ui/breakpoint-utils": "2.0.8",
- "@chakra-ui/react-env": "3.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/menu": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/menu/-/menu-2.2.1.tgz",
- "integrity": "sha512-lJS7XEObzJxsOwWQh7yfG4H8FzFPRP5hVPN/CL+JzytEINCSBvsCDHrYPQGp7jzpCi8vnTqQQGQe0f8dwnXd2g==",
- "requires": {
- "@chakra-ui/clickable": "2.1.0",
- "@chakra-ui/descendant": "3.1.0",
- "@chakra-ui/lazy-utils": "2.0.5",
- "@chakra-ui/popper": "3.1.0",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-animation-state": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-disclosure": "2.1.0",
- "@chakra-ui/react-use-focus-effect": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-outside-click": "2.2.0",
- "@chakra-ui/react-use-update-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/transition": "2.1.0"
- }
- },
- "@chakra-ui/modal": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/modal/-/modal-2.3.1.tgz",
- "integrity": "sha512-TQv1ZaiJMZN+rR9DK0snx/OPwmtaGH1HbZtlYt4W4s6CzyK541fxLRTjIXfEzIGpvNW+b6VFuFjbcR78p4DEoQ==",
- "requires": {
- "@chakra-ui/close-button": "2.1.1",
- "@chakra-ui/focus-lock": "2.1.0",
- "@chakra-ui/portal": "2.1.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/transition": "2.1.0",
- "aria-hidden": "^1.2.3",
- "react-remove-scroll": "^2.5.6"
- }
- },
- "@chakra-ui/number-input": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/number-input/-/number-input-2.1.2.tgz",
- "integrity": "sha512-pfOdX02sqUN0qC2ysuvgVDiws7xZ20XDIlcNhva55Jgm095xjm8eVdIBfNm3SFbSUNxyXvLTW/YQanX74tKmuA==",
- "requires": {
- "@chakra-ui/counter": "2.1.0",
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-callback-ref": "2.1.0",
- "@chakra-ui/react-use-event-listener": "2.1.0",
- "@chakra-ui/react-use-interval": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/number-utils": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/@chakra-ui/number-utils/-/number-utils-2.0.7.tgz",
- "integrity": "sha512-yOGxBjXNvLTBvQyhMDqGU0Oj26s91mbAlqKHiuw737AXHt0aPllOthVUqQMeaYLwLCjGMg0jtI7JReRzyi94Dg=="
- },
- "@chakra-ui/object-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/object-utils/-/object-utils-2.1.0.tgz",
- "integrity": "sha512-tgIZOgLHaoti5PYGPTwK3t/cqtcycW0owaiOXoZOcpwwX/vlVb+H1jFsQyWiiwQVPt9RkoSLtxzXamx+aHH+bQ=="
- },
- "@chakra-ui/pin-input": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/pin-input/-/pin-input-2.1.0.tgz",
- "integrity": "sha512-x4vBqLStDxJFMt+jdAHHS8jbh294O53CPQJoL4g228P513rHylV/uPscYUHrVJXRxsHfRztQO9k45jjTYaPRMw==",
- "requires": {
- "@chakra-ui/descendant": "3.1.0",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/popover": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/popover/-/popover-2.2.1.tgz",
- "integrity": "sha512-K+2ai2dD0ljvJnlrzesCDT9mNzLifE3noGKZ3QwLqd/K34Ym1W/0aL1ERSynrcG78NKoXS54SdEzkhCZ4Gn/Zg==",
- "requires": {
- "@chakra-ui/close-button": "2.1.1",
- "@chakra-ui/lazy-utils": "2.0.5",
- "@chakra-ui/popper": "3.1.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-animation-state": "2.1.0",
- "@chakra-ui/react-use-disclosure": "2.1.0",
- "@chakra-ui/react-use-focus-effect": "2.1.0",
- "@chakra-ui/react-use-focus-on-pointer-down": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/popper": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/popper/-/popper-3.1.0.tgz",
- "integrity": "sha512-ciDdpdYbeFG7og6/6J8lkTFxsSvwTdMLFkpVylAF6VNC22jssiWfquj2eyD4rJnzkRFPvIWJq8hvbfhsm+AjSg==",
- "requires": {
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@popperjs/core": "^2.9.3"
- }
- },
- "@chakra-ui/portal": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/portal/-/portal-2.1.0.tgz",
- "integrity": "sha512-9q9KWf6SArEcIq1gGofNcFPSWEyl+MfJjEUg/un1SMlQjaROOh3zYr+6JAwvcORiX7tyHosnmWC3d3wI2aPSQg==",
- "requires": {
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0"
- }
- },
- "@chakra-ui/progress": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/progress/-/progress-2.2.0.tgz",
- "integrity": "sha512-qUXuKbuhN60EzDD9mHR7B67D7p/ZqNS2Aze4Pbl1qGGZfulPW0PY8Rof32qDtttDQBkzQIzFGE8d9QpAemToIQ==",
- "requires": {
- "@chakra-ui/react-context": "2.1.0"
- }
- },
- "@chakra-ui/provider": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/provider/-/provider-2.4.2.tgz",
- "integrity": "sha512-w0Tef5ZCJK1mlJorcSjItCSbyvVuqpvyWdxZiVQmE6fvSJR83wZof42ux0+sfWD+I7rHSfj+f9nzhNaEWClysw==",
- "requires": {
- "@chakra-ui/css-reset": "2.3.0",
- "@chakra-ui/portal": "2.1.0",
- "@chakra-ui/react-env": "3.1.0",
- "@chakra-ui/system": "2.6.2",
- "@chakra-ui/utils": "2.0.15"
- }
- },
- "@chakra-ui/radio": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/radio/-/radio-2.1.2.tgz",
- "integrity": "sha512-n10M46wJrMGbonaghvSRnZ9ToTv/q76Szz284gv4QUWvyljQACcGrXIONUnQ3BIwbOfkRqSk7Xl/JgZtVfll+w==",
- "requires": {
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@zag-js/focus-visible": "0.16.0"
- }
- },
- "@chakra-ui/react": {
- "version": "2.8.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react/-/react-2.8.2.tgz",
- "integrity": "sha512-Hn0moyxxyCDKuR9ywYpqgX8dvjqwu9ArwpIb9wHNYjnODETjLwazgNIliCVBRcJvysGRiV51U2/JtJVrpeCjUQ==",
- "requires": {
- "@chakra-ui/accordion": "2.3.1",
- "@chakra-ui/alert": "2.2.2",
- "@chakra-ui/avatar": "2.3.0",
- "@chakra-ui/breadcrumb": "2.2.0",
- "@chakra-ui/button": "2.1.0",
- "@chakra-ui/card": "2.2.0",
- "@chakra-ui/checkbox": "2.3.2",
- "@chakra-ui/close-button": "2.1.1",
- "@chakra-ui/control-box": "2.1.0",
- "@chakra-ui/counter": "2.1.0",
- "@chakra-ui/css-reset": "2.3.0",
- "@chakra-ui/editable": "3.1.0",
- "@chakra-ui/focus-lock": "2.1.0",
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/hooks": "2.2.1",
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/image": "2.1.0",
- "@chakra-ui/input": "2.1.2",
- "@chakra-ui/layout": "2.3.1",
- "@chakra-ui/live-region": "2.1.0",
- "@chakra-ui/media-query": "3.3.0",
- "@chakra-ui/menu": "2.2.1",
- "@chakra-ui/modal": "2.3.1",
- "@chakra-ui/number-input": "2.1.2",
- "@chakra-ui/pin-input": "2.1.0",
- "@chakra-ui/popover": "2.2.1",
- "@chakra-ui/popper": "3.1.0",
- "@chakra-ui/portal": "2.1.0",
- "@chakra-ui/progress": "2.2.0",
- "@chakra-ui/provider": "2.4.2",
- "@chakra-ui/radio": "2.1.2",
- "@chakra-ui/react-env": "3.1.0",
- "@chakra-ui/select": "2.1.2",
- "@chakra-ui/skeleton": "2.1.0",
- "@chakra-ui/skip-nav": "2.1.0",
- "@chakra-ui/slider": "2.1.0",
- "@chakra-ui/spinner": "2.1.0",
- "@chakra-ui/stat": "2.1.1",
- "@chakra-ui/stepper": "2.3.1",
- "@chakra-ui/styled-system": "2.9.2",
- "@chakra-ui/switch": "2.1.2",
- "@chakra-ui/system": "2.6.2",
- "@chakra-ui/table": "2.1.0",
- "@chakra-ui/tabs": "3.0.0",
- "@chakra-ui/tag": "3.1.1",
- "@chakra-ui/textarea": "2.1.2",
- "@chakra-ui/theme": "3.3.1",
- "@chakra-ui/theme-utils": "2.0.21",
- "@chakra-ui/toast": "7.0.2",
- "@chakra-ui/tooltip": "2.3.1",
- "@chakra-ui/transition": "2.1.0",
- "@chakra-ui/utils": "2.0.15",
- "@chakra-ui/visually-hidden": "2.2.0"
- }
- },
- "@chakra-ui/react-children-utils": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-children-utils/-/react-children-utils-2.0.6.tgz",
- "integrity": "sha512-QVR2RC7QsOsbWwEnq9YduhpqSFnZGvjjGREV8ygKi8ADhXh93C8azLECCUVgRJF2Wc+So1fgxmjLcbZfY2VmBA==",
- "requires": {}
- },
- "@chakra-ui/react-context": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-context/-/react-context-2.1.0.tgz",
- "integrity": "sha512-iahyStvzQ4AOwKwdPReLGfDesGG+vWJfEsn0X/NoGph/SkN+HXtv2sCfYFFR9k7bb+Kvc6YfpLlSuLvKMHi2+w==",
- "requires": {}
- },
- "@chakra-ui/react-env": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-env/-/react-env-3.1.0.tgz",
- "integrity": "sha512-Vr96GV2LNBth3+IKzr/rq1IcnkXv+MLmwjQH6C8BRtn3sNskgDFD5vLkVXcEhagzZMCh8FR3V/bzZPojBOyNhw==",
- "requires": {
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0"
- }
- },
- "@chakra-ui/react-types": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-types/-/react-types-2.0.7.tgz",
- "integrity": "sha512-12zv2qIZ8EHwiytggtGvo4iLT0APris7T0qaAWqzpUGS0cdUtR8W+V1BJ5Ocq+7tA6dzQ/7+w5hmXih61TuhWQ==",
- "requires": {}
- },
- "@chakra-ui/react-use-animation-state": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-animation-state/-/react-use-animation-state-2.1.0.tgz",
- "integrity": "sha512-CFZkQU3gmDBwhqy0vC1ryf90BVHxVN8cTLpSyCpdmExUEtSEInSCGMydj2fvn7QXsz/za8JNdO2xxgJwxpLMtg==",
- "requires": {
- "@chakra-ui/dom-utils": "2.1.0",
- "@chakra-ui/react-use-event-listener": "2.1.0"
- }
- },
- "@chakra-ui/react-use-callback-ref": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-callback-ref/-/react-use-callback-ref-2.1.0.tgz",
- "integrity": "sha512-efnJrBtGDa4YaxDzDE90EnKD3Vkh5a1t3w7PhnRQmsphLy3g2UieasoKTlT2Hn118TwDjIv5ZjHJW6HbzXA9wQ==",
- "requires": {}
- },
- "@chakra-ui/react-use-controllable-state": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-controllable-state/-/react-use-controllable-state-2.1.0.tgz",
- "integrity": "sha512-QR/8fKNokxZUs4PfxjXuwl0fj/d71WPrmLJvEpCTkHjnzu7LnYvzoe2wB867IdooQJL0G1zBxl0Dq+6W1P3jpg==",
- "requires": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- }
- },
- "@chakra-ui/react-use-disclosure": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-disclosure/-/react-use-disclosure-2.1.0.tgz",
- "integrity": "sha512-Ax4pmxA9LBGMyEZJhhUZobg9C0t3qFE4jVF1tGBsrLDcdBeLR9fwOogIPY9Hf0/wqSlAryAimICbr5hkpa5GSw==",
- "requires": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- }
- },
- "@chakra-ui/react-use-event-listener": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-event-listener/-/react-use-event-listener-2.1.0.tgz",
- "integrity": "sha512-U5greryDLS8ISP69DKDsYcsXRtAdnTQT+jjIlRYZ49K/XhUR/AqVZCK5BkR1spTDmO9H8SPhgeNKI70ODuDU/Q==",
- "requires": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- }
- },
- "@chakra-ui/react-use-focus-effect": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-focus-effect/-/react-use-focus-effect-2.1.0.tgz",
- "integrity": "sha512-xzVboNy7J64xveLcxTIJ3jv+lUJKDwRM7Szwn9tNzUIPD94O3qwjV7DDCUzN2490nSYDF4OBMt/wuDBtaR3kUQ==",
- "requires": {
- "@chakra-ui/dom-utils": "2.1.0",
- "@chakra-ui/react-use-event-listener": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0"
- }
- },
- "@chakra-ui/react-use-focus-on-pointer-down": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-focus-on-pointer-down/-/react-use-focus-on-pointer-down-2.1.0.tgz",
- "integrity": "sha512-2jzrUZ+aiCG/cfanrolsnSMDykCAbv9EK/4iUyZno6BYb3vziucmvgKuoXbMPAzWNtwUwtuMhkby8rc61Ue+Lg==",
- "requires": {
- "@chakra-ui/react-use-event-listener": "2.1.0"
- }
- },
- "@chakra-ui/react-use-interval": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-interval/-/react-use-interval-2.1.0.tgz",
- "integrity": "sha512-8iWj+I/+A0J08pgEXP1J1flcvhLBHkk0ln7ZvGIyXiEyM6XagOTJpwNhiu+Bmk59t3HoV/VyvyJTa+44sEApuw==",
- "requires": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- }
- },
- "@chakra-ui/react-use-latest-ref": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-latest-ref/-/react-use-latest-ref-2.1.0.tgz",
- "integrity": "sha512-m0kxuIYqoYB0va9Z2aW4xP/5b7BzlDeWwyXCH6QpT2PpW3/281L3hLCm1G0eOUcdVlayqrQqOeD6Mglq+5/xoQ==",
- "requires": {}
- },
- "@chakra-ui/react-use-merge-refs": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-merge-refs/-/react-use-merge-refs-2.1.0.tgz",
- "integrity": "sha512-lERa6AWF1cjEtWSGjxWTaSMvneccnAVH4V4ozh8SYiN9fSPZLlSG3kNxfNzdFvMEhM7dnP60vynF7WjGdTgQbQ==",
- "requires": {}
- },
- "@chakra-ui/react-use-outside-click": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-outside-click/-/react-use-outside-click-2.2.0.tgz",
- "integrity": "sha512-PNX+s/JEaMneijbgAM4iFL+f3m1ga9+6QK0E5Yh4s8KZJQ/bLwZzdhMz8J/+mL+XEXQ5J0N8ivZN28B82N1kNw==",
- "requires": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- }
- },
- "@chakra-ui/react-use-pan-event": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-pan-event/-/react-use-pan-event-2.1.0.tgz",
- "integrity": "sha512-xmL2qOHiXqfcj0q7ZK5s9UjTh4Gz0/gL9jcWPA6GVf+A0Od5imEDa/Vz+533yQKWiNSm1QGrIj0eJAokc7O4fg==",
- "requires": {
- "@chakra-ui/event-utils": "2.0.8",
- "@chakra-ui/react-use-latest-ref": "2.1.0",
- "framesync": "6.1.2"
- }
- },
- "@chakra-ui/react-use-previous": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-previous/-/react-use-previous-2.1.0.tgz",
- "integrity": "sha512-pjxGwue1hX8AFcmjZ2XfrQtIJgqbTF3Qs1Dy3d1krC77dEsiCUbQ9GzOBfDc8pfd60DrB5N2tg5JyHbypqh0Sg==",
- "requires": {}
- },
- "@chakra-ui/react-use-safe-layout-effect": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-safe-layout-effect/-/react-use-safe-layout-effect-2.1.0.tgz",
- "integrity": "sha512-Knbrrx/bcPwVS1TorFdzrK/zWA8yuU/eaXDkNj24IrKoRlQrSBFarcgAEzlCHtzuhufP3OULPkELTzz91b0tCw==",
- "requires": {}
- },
- "@chakra-ui/react-use-size": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-size/-/react-use-size-2.1.0.tgz",
- "integrity": "sha512-tbLqrQhbnqOjzTaMlYytp7wY8BW1JpL78iG7Ru1DlV4EWGiAmXFGvtnEt9HftU0NJ0aJyjgymkxfVGI55/1Z4A==",
- "requires": {
- "@zag-js/element-size": "0.10.5"
- }
- },
- "@chakra-ui/react-use-timeout": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-timeout/-/react-use-timeout-2.1.0.tgz",
- "integrity": "sha512-cFN0sobKMM9hXUhyCofx3/Mjlzah6ADaEl/AXl5Y+GawB5rgedgAcu2ErAgarEkwvsKdP6c68CKjQ9dmTQlJxQ==",
- "requires": {
- "@chakra-ui/react-use-callback-ref": "2.1.0"
- }
- },
- "@chakra-ui/react-use-update-effect": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-use-update-effect/-/react-use-update-effect-2.1.0.tgz",
- "integrity": "sha512-ND4Q23tETaR2Qd3zwCKYOOS1dfssojPLJMLvUtUbW5M9uW1ejYWgGUobeAiOVfSplownG8QYMmHTP86p/v0lbA==",
- "requires": {}
- },
- "@chakra-ui/react-utils": {
- "version": "2.0.12",
- "resolved": "https://registry.npmjs.org/@chakra-ui/react-utils/-/react-utils-2.0.12.tgz",
- "integrity": "sha512-GbSfVb283+YA3kA8w8xWmzbjNWk14uhNpntnipHCftBibl0lxtQ9YqMFQLwuFOO0U2gYVocszqqDWX+XNKq9hw==",
- "requires": {
- "@chakra-ui/utils": "2.0.15"
- }
- },
- "@chakra-ui/select": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/select/-/select-2.1.2.tgz",
- "integrity": "sha512-ZwCb7LqKCVLJhru3DXvKXpZ7Pbu1TDZ7N0PdQ0Zj1oyVLJyrpef1u9HR5u0amOpqcH++Ugt0f5JSmirjNlctjA==",
- "requires": {
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/shared-utils": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@chakra-ui/shared-utils/-/shared-utils-2.0.5.tgz",
- "integrity": "sha512-4/Wur0FqDov7Y0nCXl7HbHzCg4aq86h+SXdoUeuCMD3dSj7dpsVnStLYhng1vxvlbUnLpdF4oz5Myt3i/a7N3Q=="
- },
- "@chakra-ui/skeleton": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/skeleton/-/skeleton-2.1.0.tgz",
- "integrity": "sha512-JNRuMPpdZGd6zFVKjVQ0iusu3tXAdI29n4ZENYwAJEMf/fN0l12sVeirOxkJ7oEL0yOx2AgEYFSKdbcAgfUsAQ==",
- "requires": {
- "@chakra-ui/media-query": "3.3.0",
- "@chakra-ui/react-use-previous": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/skip-nav": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/skip-nav/-/skip-nav-2.1.0.tgz",
- "integrity": "sha512-Hk+FG+vadBSH0/7hwp9LJnLjkO0RPGnx7gBJWI4/SpoJf3e4tZlWYtwGj0toYY4aGKl93jVghuwGbDBEMoHDug==",
- "requires": {}
- },
- "@chakra-ui/slider": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/slider/-/slider-2.1.0.tgz",
- "integrity": "sha512-lUOBcLMCnFZiA/s2NONXhELJh6sY5WtbRykPtclGfynqqOo47lwWJx+VP7xaeuhDOPcWSSecWc9Y1BfPOCz9cQ==",
- "requires": {
- "@chakra-ui/number-utils": "2.0.7",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-callback-ref": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-latest-ref": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-pan-event": "2.1.0",
- "@chakra-ui/react-use-size": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0"
- }
- },
- "@chakra-ui/spinner": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/spinner/-/spinner-2.1.0.tgz",
- "integrity": "sha512-hczbnoXt+MMv/d3gE+hjQhmkzLiKuoTo42YhUG7Bs9OSv2lg1fZHW1fGNRFP3wTi6OIbD044U1P9HK+AOgFH3g==",
- "requires": {
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/stat": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/stat/-/stat-2.1.1.tgz",
- "integrity": "sha512-LDn0d/LXQNbAn2KaR3F1zivsZCewY4Jsy1qShmfBMKwn6rI8yVlbvu6SiA3OpHS0FhxbsZxQI6HefEoIgtqY6Q==",
- "requires": {
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/stepper": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/stepper/-/stepper-2.3.1.tgz",
- "integrity": "sha512-ky77lZbW60zYkSXhYz7kbItUpAQfEdycT0Q4bkHLxfqbuiGMf8OmgZOQkOB9uM4v0zPwy2HXhe0vq4Dd0xa55Q==",
- "requires": {
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/styled-system": {
- "version": "2.9.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/styled-system/-/styled-system-2.9.2.tgz",
- "integrity": "sha512-To/Z92oHpIE+4nk11uVMWqo2GGRS86coeMmjxtpnErmWRdLcp1WVCVRAvn+ZwpLiNR+reWFr2FFqJRsREuZdAg==",
- "requires": {
- "@chakra-ui/shared-utils": "2.0.5",
- "csstype": "^3.1.2",
- "lodash.mergewith": "4.6.2"
- }
- },
- "@chakra-ui/switch": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/switch/-/switch-2.1.2.tgz",
- "integrity": "sha512-pgmi/CC+E1v31FcnQhsSGjJnOE2OcND4cKPyTE+0F+bmGm48Q/b5UmKD9Y+CmZsrt/7V3h8KNczowupfuBfIHA==",
- "requires": {
- "@chakra-ui/checkbox": "2.3.2",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/system": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/system/-/system-2.6.2.tgz",
- "integrity": "sha512-EGtpoEjLrUu4W1fHD+a62XR+hzC5YfsWm+6lO0Kybcga3yYEij9beegO0jZgug27V+Rf7vns95VPVP6mFd/DEQ==",
- "requires": {
- "@chakra-ui/color-mode": "2.2.0",
- "@chakra-ui/object-utils": "2.1.0",
- "@chakra-ui/react-utils": "2.0.12",
- "@chakra-ui/styled-system": "2.9.2",
- "@chakra-ui/theme-utils": "2.0.21",
- "@chakra-ui/utils": "2.0.15",
- "react-fast-compare": "3.2.2"
- }
- },
- "@chakra-ui/table": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/table/-/table-2.1.0.tgz",
- "integrity": "sha512-o5OrjoHCh5uCLdiUb0Oc0vq9rIAeHSIRScc2ExTC9Qg/uVZl2ygLrjToCaKfaaKl1oQexIeAcZDKvPG8tVkHyQ==",
- "requires": {
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/tabs": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/tabs/-/tabs-3.0.0.tgz",
- "integrity": "sha512-6Mlclp8L9lqXmsGWF5q5gmemZXOiOYuh0SGT/7PgJVNPz3LXREXlXg2an4MBUD8W5oTkduCX+3KTMCwRrVrDYw==",
- "requires": {
- "@chakra-ui/clickable": "2.1.0",
- "@chakra-ui/descendant": "3.1.0",
- "@chakra-ui/lazy-utils": "2.0.5",
- "@chakra-ui/react-children-utils": "2.0.6",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-controllable-state": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/react-use-safe-layout-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/tag": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/tag/-/tag-3.1.1.tgz",
- "integrity": "sha512-Bdel79Dv86Hnge2PKOU+t8H28nm/7Y3cKd4Kfk9k3lOpUh4+nkSGe58dhRzht59lEqa4N9waCgQiBdkydjvBXQ==",
- "requires": {
- "@chakra-ui/icon": "3.2.0",
- "@chakra-ui/react-context": "2.1.0"
- }
- },
- "@chakra-ui/textarea": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/textarea/-/textarea-2.1.2.tgz",
- "integrity": "sha512-ip7tvklVCZUb2fOHDb23qPy/Fr2mzDOGdkrpbNi50hDCiV4hFX02jdQJdi3ydHZUyVgZVBKPOJ+lT9i7sKA2wA==",
- "requires": {
- "@chakra-ui/form-control": "2.2.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/theme": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/theme/-/theme-3.3.1.tgz",
- "integrity": "sha512-Hft/VaT8GYnItGCBbgWd75ICrIrIFrR7lVOhV/dQnqtfGqsVDlrztbSErvMkoPKt0UgAkd9/o44jmZ6X4U2nZQ==",
- "requires": {
- "@chakra-ui/anatomy": "2.2.2",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/theme-tools": "2.1.2"
- }
- },
- "@chakra-ui/theme-tools": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/theme-tools/-/theme-tools-2.1.2.tgz",
- "integrity": "sha512-Qdj8ajF9kxY4gLrq7gA+Azp8CtFHGO9tWMN2wfF9aQNgG9AuMhPrUzMq9AMQ0MXiYcgNq/FD3eegB43nHVmXVA==",
- "requires": {
- "@chakra-ui/anatomy": "2.2.2",
- "@chakra-ui/shared-utils": "2.0.5",
- "color2k": "^2.0.2"
- }
- },
- "@chakra-ui/theme-utils": {
- "version": "2.0.21",
- "resolved": "https://registry.npmjs.org/@chakra-ui/theme-utils/-/theme-utils-2.0.21.tgz",
- "integrity": "sha512-FjH5LJbT794r0+VSCXB3lT4aubI24bLLRWB+CuRKHijRvsOg717bRdUN/N1fEmEpFnRVrbewttWh/OQs0EWpWw==",
- "requires": {
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/styled-system": "2.9.2",
- "@chakra-ui/theme": "3.3.1",
- "lodash.mergewith": "4.6.2"
- }
- },
- "@chakra-ui/toast": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/@chakra-ui/toast/-/toast-7.0.2.tgz",
- "integrity": "sha512-yvRP8jFKRs/YnkuE41BVTq9nB2v/KDRmje9u6dgDmE5+1bFt3bwjdf9gVbif4u5Ve7F7BGk5E093ARRVtvLvXA==",
- "requires": {
- "@chakra-ui/alert": "2.2.2",
- "@chakra-ui/close-button": "2.1.1",
- "@chakra-ui/portal": "2.1.0",
- "@chakra-ui/react-context": "2.1.0",
- "@chakra-ui/react-use-timeout": "2.1.0",
- "@chakra-ui/react-use-update-effect": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5",
- "@chakra-ui/styled-system": "2.9.2",
- "@chakra-ui/theme": "3.3.1"
- }
- },
- "@chakra-ui/tooltip": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/@chakra-ui/tooltip/-/tooltip-2.3.1.tgz",
- "integrity": "sha512-Rh39GBn/bL4kZpuEMPPRwYNnccRCL+w9OqamWHIB3Qboxs6h8cOyXfIdGxjo72lvhu1QI/a4KFqkM3St+WfC0A==",
- "requires": {
- "@chakra-ui/dom-utils": "2.1.0",
- "@chakra-ui/popper": "3.1.0",
- "@chakra-ui/portal": "2.1.0",
- "@chakra-ui/react-types": "2.0.7",
- "@chakra-ui/react-use-disclosure": "2.1.0",
- "@chakra-ui/react-use-event-listener": "2.1.0",
- "@chakra-ui/react-use-merge-refs": "2.1.0",
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/transition": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/transition/-/transition-2.1.0.tgz",
- "integrity": "sha512-orkT6T/Dt+/+kVwJNy7zwJ+U2xAZ3EU7M3XCs45RBvUnZDr/u9vdmaM/3D/rOpmQJWgQBwKPJleUXrYWUagEDQ==",
- "requires": {
- "@chakra-ui/shared-utils": "2.0.5"
- }
- },
- "@chakra-ui/utils": {
- "version": "2.0.15",
- "resolved": "https://registry.npmjs.org/@chakra-ui/utils/-/utils-2.0.15.tgz",
- "integrity": "sha512-El4+jL0WSaYYs+rJbuYFDbjmfCcfGDmRY95GO4xwzit6YAPZBLcR65rOEwLps+XWluZTy1xdMrusg/hW0c1aAA==",
- "requires": {
- "@types/lodash.mergewith": "4.6.7",
- "css-box-model": "1.2.1",
- "framesync": "6.1.2",
- "lodash.mergewith": "4.6.2"
- }
- },
- "@chakra-ui/visually-hidden": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@chakra-ui/visually-hidden/-/visually-hidden-2.2.0.tgz",
- "integrity": "sha512-KmKDg01SrQ7VbTD3+cPWf/UfpF5MSwm3v7MWi0n5t8HnnadT13MF0MJCDSXbBWnzLv1ZKJ6zlyAOeARWX+DpjQ==",
- "requires": {}
- },
- "@emotion/babel-plugin": {
- "version": "11.11.0",
- "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz",
- "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==",
- "requires": {
- "@babel/helper-module-imports": "^7.16.7",
- "@babel/runtime": "^7.18.3",
- "@emotion/hash": "^0.9.1",
- "@emotion/memoize": "^0.8.1",
- "@emotion/serialize": "^1.1.2",
- "babel-plugin-macros": "^3.1.0",
- "convert-source-map": "^1.5.0",
- "escape-string-regexp": "^4.0.0",
- "find-root": "^1.1.0",
- "source-map": "^0.5.7",
- "stylis": "4.2.0"
- },
- "dependencies": {
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="
- }
- }
- },
- "@emotion/cache": {
- "version": "11.11.0",
- "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz",
- "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==",
- "requires": {
- "@emotion/memoize": "^0.8.1",
- "@emotion/sheet": "^1.2.2",
- "@emotion/utils": "^1.2.1",
- "@emotion/weak-memoize": "^0.3.1",
- "stylis": "4.2.0"
- }
- },
- "@emotion/hash": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz",
- "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ=="
- },
- "@emotion/is-prop-valid": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz",
- "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==",
- "requires": {
- "@emotion/memoize": "^0.8.1"
- }
- },
- "@emotion/memoize": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
- "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
- },
- "@emotion/react": {
- "version": "11.11.3",
- "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz",
- "integrity": "sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==",
- "requires": {
- "@babel/runtime": "^7.18.3",
- "@emotion/babel-plugin": "^11.11.0",
- "@emotion/cache": "^11.11.0",
- "@emotion/serialize": "^1.1.3",
- "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1",
- "@emotion/utils": "^1.2.1",
- "@emotion/weak-memoize": "^0.3.1",
- "hoist-non-react-statics": "^3.3.1"
- }
- },
- "@emotion/serialize": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz",
- "integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==",
- "requires": {
- "@emotion/hash": "^0.9.1",
- "@emotion/memoize": "^0.8.1",
- "@emotion/unitless": "^0.8.1",
- "@emotion/utils": "^1.2.1",
- "csstype": "^3.0.2"
- }
- },
- "@emotion/sheet": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz",
- "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA=="
- },
- "@emotion/styled": {
- "version": "11.11.0",
- "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz",
- "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==",
- "requires": {
- "@babel/runtime": "^7.18.3",
- "@emotion/babel-plugin": "^11.11.0",
- "@emotion/is-prop-valid": "^1.2.1",
- "@emotion/serialize": "^1.1.2",
- "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1",
- "@emotion/utils": "^1.2.1"
- }
- },
- "@emotion/unitless": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz",
- "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ=="
- },
- "@emotion/use-insertion-effect-with-fallbacks": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz",
- "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==",
- "requires": {}
- },
- "@emotion/utils": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz",
- "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg=="
- },
- "@emotion/weak-memoize": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz",
- "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww=="
- },
- "@esbuild/android-arm": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.8.tgz",
- "integrity": "sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/android-arm64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz",
- "integrity": "sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/android-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.8.tgz",
- "integrity": "sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==",
- "dev": true,
- "optional": true
- },
- "@esbuild/darwin-arm64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz",
- "integrity": "sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==",
- "dev": true,
- "optional": true
- },
- "@esbuild/darwin-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz",
- "integrity": "sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==",
- "dev": true,
- "optional": true
- },
- "@esbuild/freebsd-arm64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz",
- "integrity": "sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==",
- "dev": true,
- "optional": true
- },
- "@esbuild/freebsd-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz",
- "integrity": "sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-arm": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz",
- "integrity": "sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-arm64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz",
- "integrity": "sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-ia32": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz",
- "integrity": "sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-loong64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz",
- "integrity": "sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-mips64el": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz",
- "integrity": "sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-ppc64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz",
- "integrity": "sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-riscv64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz",
- "integrity": "sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-s390x": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz",
- "integrity": "sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz",
- "integrity": "sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/netbsd-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz",
- "integrity": "sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==",
- "dev": true,
- "optional": true
- },
- "@esbuild/openbsd-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz",
- "integrity": "sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/sunos-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz",
- "integrity": "sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-arm64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz",
- "integrity": "sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-ia32": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz",
- "integrity": "sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-x64": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz",
- "integrity": "sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==",
- "dev": true,
- "optional": true
- },
- "@hey-api/openapi-ts": {
- "version": "0.34.1",
- "resolved": "https://registry.npmjs.org/@hey-api/openapi-ts/-/openapi-ts-0.34.1.tgz",
- "integrity": "sha512-7Ak+0nvf4Nhzk04tXGg6h4eM7lnWRgfjCPmMl2MyXrhS5urxd3Bg/PhtpB84u18wnwcM4rIeCUlTwDDQ/OB3NQ==",
- "dev": true,
- "requires": {
- "@apidevtools/json-schema-ref-parser": "11.5.4",
- "camelcase": "8.0.0",
- "commander": "12.0.0",
- "handlebars": "4.7.8"
- },
- "dependencies": {
- "@apidevtools/json-schema-ref-parser": {
- "version": "11.5.4",
- "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.5.4.tgz",
- "integrity": "sha512-o2fsypTGU0WxRxbax8zQoHiIB4dyrkwYfcm8TxZ+bx9pCzcWZbQtiMqpgBvWA/nJ2TrGjK5adCLfTH8wUeU/Wg==",
- "dev": true,
- "requires": {
- "@jsdevtools/ono": "^7.1.3",
- "@types/json-schema": "^7.0.15",
- "js-yaml": "^4.1.0"
- }
- },
- "camelcase": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz",
- "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==",
- "dev": true
- },
- "commander": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz",
- "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==",
- "dev": true
- }
- }
- },
- "@jsdevtools/ono": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
- "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
- "dev": true
- },
- "@playwright/test": {
- "version": "1.45.2",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.2.tgz",
- "integrity": "sha512-JxG9eq92ET75EbVi3s+4sYbcG7q72ECeZNbdBlaMkGcNbiDQ4cAi8U2QP5oKkOx+1gpaiL1LDStmzCaEM1Z6fQ==",
- "dev": true,
- "requires": {
- "playwright": "1.45.2"
- }
- },
- "@popperjs/core": {
- "version": "2.11.8",
- "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
- "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
- },
- "@rollup/rollup-android-arm-eabi": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.6.1.tgz",
- "integrity": "sha512-0WQ0ouLejaUCRsL93GD4uft3rOmB8qoQMU05Kb8CmMtMBe7XUDLAltxVZI1q6byNqEtU7N1ZX1Vw5lIpgulLQA==",
- "dev": true,
- "optional": true
- },
- "@rollup/rollup-android-arm64": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.6.1.tgz",
- "integrity": "sha512-1TKm25Rn20vr5aTGGZqo6E4mzPicCUD79k17EgTLAsXc1zysyi4xXKACfUbwyANEPAEIxkzwue6JZ+stYzWUTA==",
- "dev": true,
- "optional": true
- },
- "@rollup/rollup-darwin-arm64": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.6.1.tgz",
- "integrity": "sha512-cEXJQY/ZqMACb+nxzDeX9IPLAg7S94xouJJCNVE5BJM8JUEP4HeTF+ti3cmxWeSJo+5D+o8Tc0UAWUkfENdeyw==",
- "dev": true,
- "optional": true
- },
- "@rollup/rollup-darwin-x64": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.6.1.tgz",
- "integrity": "sha512-LoSU9Xu56isrkV2jLldcKspJ7sSXmZWkAxg7sW/RfF7GS4F5/v4EiqKSMCFbZtDu2Nc1gxxFdQdKwkKS4rwxNg==",
- "dev": true,
- "optional": true
- },
- "@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.6.1.tgz",
- "integrity": "sha512-EfI3hzYAy5vFNDqpXsNxXcgRDcFHUWSx5nnRSCKwXuQlI5J9dD84g2Usw81n3FLBNsGCegKGwwTVsSKK9cooSQ==",
- "dev": true,
- "optional": true
- },
- "@rollup/rollup-linux-arm64-gnu": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.6.1.tgz",
- "integrity": "sha512-9lhc4UZstsegbNLhH0Zu6TqvDfmhGzuCWtcTFXY10VjLLUe4Mr0Ye2L3rrtHaDd/J5+tFMEuo5LTCSCMXWfUKw==",
- "dev": true,
- "optional": true
- },
- "@rollup/rollup-linux-arm64-musl": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.6.1.tgz",
- "integrity": "sha512-FfoOK1yP5ksX3wwZ4Zk1NgyGHZyuRhf99j64I5oEmirV8EFT7+OhUZEnP+x17lcP/QHJNWGsoJwrz4PJ9fBEXw==",
- "dev": true,
- "optional": true
- },
- "@rollup/rollup-linux-x64-gnu": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.6.1.tgz",
- "integrity": "sha512-DNGZvZDO5YF7jN5fX8ZqmGLjZEXIJRdJEdTFMhiyXqyXubBa0WVLDWSNlQ5JR2PNgDbEV1VQowhVRUh+74D+RA==",
- "dev": true,
- "optional": true
- },
- "@rollup/rollup-linux-x64-musl": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.6.1.tgz",
- "integrity": "sha512-RkJVNVRM+piYy87HrKmhbexCHg3A6Z6MU0W9GHnJwBQNBeyhCJG9KDce4SAMdicQnpURggSvtbGo9xAWOfSvIQ==",
- "dev": true,
- "optional": true
- },
- "@rollup/rollup-win32-arm64-msvc": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.6.1.tgz",
- "integrity": "sha512-v2FVT6xfnnmTe3W9bJXl6r5KwJglMK/iRlkKiIFfO6ysKs0rDgz7Cwwf3tjldxQUrHL9INT/1r4VA0n9L/F1vQ==",
- "dev": true,
- "optional": true
- },
- "@rollup/rollup-win32-ia32-msvc": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.6.1.tgz",
- "integrity": "sha512-YEeOjxRyEjqcWphH9dyLbzgkF8wZSKAKUkldRY6dgNR5oKs2LZazqGB41cWJ4Iqqcy9/zqYgmzBkRoVz3Q9MLw==",
- "dev": true,
- "optional": true
- },
- "@rollup/rollup-win32-x64-msvc": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.6.1.tgz",
- "integrity": "sha512-0zfTlFAIhgz8V2G8STq8toAjsYYA6eci1hnXuyOTUFnymrtJwnS6uGKiv3v5UrPZkBlamLvrLV2iiaeqCKzb0A==",
- "dev": true,
- "optional": true
- },
- "@swc/core": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.100.tgz",
- "integrity": "sha512-7dKgTyxJjlrMwFZYb1auj3Xq0D8ZBe+5oeIgfMlRU05doXZypYJe0LAk0yjj3WdbwYzpF+T1PLxwTWizI0pckw==",
- "dev": true,
- "requires": {
- "@swc/core-darwin-arm64": "1.3.100",
- "@swc/core-darwin-x64": "1.3.100",
- "@swc/core-linux-arm64-gnu": "1.3.100",
- "@swc/core-linux-arm64-musl": "1.3.100",
- "@swc/core-linux-x64-gnu": "1.3.100",
- "@swc/core-linux-x64-musl": "1.3.100",
- "@swc/core-win32-arm64-msvc": "1.3.100",
- "@swc/core-win32-ia32-msvc": "1.3.100",
- "@swc/core-win32-x64-msvc": "1.3.100",
- "@swc/counter": "^0.1.1",
- "@swc/types": "^0.1.5"
- }
- },
- "@swc/core-darwin-arm64": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.100.tgz",
- "integrity": "sha512-XVWFsKe6ei+SsDbwmsuRkYck1SXRpO60Hioa4hoLwR8fxbA9eVp6enZtMxzVVMBi8ej5seZ4HZQeAWepbukiBw==",
- "dev": true,
- "optional": true
- },
- "@swc/core-darwin-x64": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.100.tgz",
- "integrity": "sha512-KF/MXrnH1nakm1wbt4XV8FS7kvqD9TGmVxeJ0U4bbvxXMvzeYUurzg3AJUTXYmXDhH/VXOYJE5N5RkwZZPs5iA==",
- "dev": true,
- "optional": true
- },
- "@swc/core-linux-arm64-gnu": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.100.tgz",
- "integrity": "sha512-p8hikNnAEJrw5vHCtKiFT4hdlQxk1V7vqPmvUDgL/qe2menQDK/i12tbz7/3BEQ4UqUPnvwpmVn2d19RdEMNxw==",
- "dev": true,
- "optional": true
- },
- "@swc/core-linux-arm64-musl": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.100.tgz",
- "integrity": "sha512-BWx/0EeY89WC4q3AaIaBSGfQxkYxIlS3mX19dwy2FWJs/O+fMvF9oLk/CyJPOZzbp+1DjGeeoGFuDYpiNO91JA==",
- "dev": true,
- "optional": true
- },
- "@swc/core-linux-x64-gnu": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.100.tgz",
- "integrity": "sha512-XUdGu3dxAkjsahLYnm8WijPfKebo+jHgHphDxaW0ovI6sTdmEGFDew7QzKZRlbYL2jRkUuuKuDGvD6lO5frmhA==",
- "dev": true,
- "optional": true
- },
- "@swc/core-linux-x64-musl": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.100.tgz",
- "integrity": "sha512-PhoXKf+f0OaNW/GCuXjJ0/KfK9EJX7z2gko+7nVnEA0p3aaPtbP6cq1Ubbl6CMoPL+Ci3gZ7nYumDqXNc3CtLQ==",
- "dev": true,
- "optional": true
- },
- "@swc/core-win32-arm64-msvc": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.100.tgz",
- "integrity": "sha512-PwLADZN6F9cXn4Jw52FeP/MCLVHm8vwouZZSOoOScDtihjY495SSjdPnlosMaRSR4wJQssGwiD/4MbpgQPqbAw==",
- "dev": true,
- "optional": true
- },
- "@swc/core-win32-ia32-msvc": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.100.tgz",
- "integrity": "sha512-0f6nicKSLlDKlyPRl2JEmkpBV4aeDfRQg6n8mPqgL7bliZIcDahG0ej+HxgNjZfS3e0yjDxsNRa6sAqWU2Z60A==",
- "dev": true,
- "optional": true
- },
- "@swc/core-win32-x64-msvc": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.100.tgz",
- "integrity": "sha512-b7J0rPoMkRTa3XyUGt8PwCaIBuYWsL2DqbirrQKRESzgCvif5iNpqaM6kjIjI/5y5q1Ycv564CB51YDpiS8EtQ==",
- "dev": true,
- "optional": true
- },
- "@swc/counter": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz",
- "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==",
- "dev": true
- },
- "@swc/types": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz",
- "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==",
- "dev": true
- },
- "@tanstack/history": {
- "version": "1.15.13",
- "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.15.13.tgz",
- "integrity": "sha512-ToaeMtK5S4YaxCywAlYexc7KPFN0esjyTZ4vXzJhXEWAkro9iHgh7m/4ozPJb7oTo65WkHWX0W9GjcZbInSD8w=="
- },
- "@tanstack/query-core": {
- "version": "5.28.13",
- "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.28.13.tgz",
- "integrity": "sha512-C3+CCOcza+mrZ7LglQbjeYEOTEC3LV0VN0eYaIN6GvqAZ8Foegdgch7n6QYPtT4FuLae5ALy+m+ZMEKpD6tMCQ=="
- },
- "@tanstack/query-devtools": {
- "version": "5.28.10",
- "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.28.10.tgz",
- "integrity": "sha512-5UN629fKa5/1K/2Pd26gaU7epxRrYiT1gy+V+pW5K6hnf1DeUKK3pANSb2eHKlecjIKIhTwyF7k9XdyE2gREvQ=="
- },
- "@tanstack/react-query": {
- "version": "5.28.14",
- "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.28.14.tgz",
- "integrity": "sha512-cZqt03Igb3I9tM72qNX5TAAmeYl75Z+k4Mv92VkXIXc2hCrv0fIywd7GN3JV1BBJl4mr7Cc+OOKKOPy8sNVOkA==",
- "requires": {
- "@tanstack/query-core": "5.28.13"
- }
- },
- "@tanstack/react-query-devtools": {
- "version": "5.28.14",
- "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.28.14.tgz",
- "integrity": "sha512-4CrFBI1O5wibV1ZdGAnBMmTuc7SiShhxWubxRMyIloeEioxs3DQkFbouGBea5nexuwIxAkvhUB8khpPnNjhxMw==",
- "requires": {
- "@tanstack/query-devtools": "5.28.10"
- }
- },
- "@tanstack/react-router": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.19.1.tgz",
- "integrity": "sha512-a4Xf074qo2fQLmSi8PTncEFn8XakaH3+DT7Dted4OPClzQFS+c6yU3HONVNAsuYWZ7lDK1HMKoHPDFbnHPEWvA==",
- "requires": {
- "@tanstack/history": "1.15.13",
- "@tanstack/react-store": "^0.2.1",
- "tiny-invariant": "^1.3.1",
- "tiny-warning": "^1.0.3"
- }
- },
- "@tanstack/react-store": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.2.1.tgz",
- "integrity": "sha512-tEbMCQjbeVw9KOP/202LfqZMSNAVi6zYkkp1kBom8nFuMx/965Hzes3+6G6b/comCwVxoJU8Gg9IrcF8yRPthw==",
- "requires": {
- "@tanstack/store": "0.1.3",
- "use-sync-external-store": "^1.2.0"
- }
- },
- "@tanstack/router-devtools": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/@tanstack/router-devtools/-/router-devtools-1.19.1.tgz",
- "integrity": "sha512-l560JHnffcDccSTo/sOtB+gKvtgaWYpOKOu9MyvswN9XB2pt752UFFIN1Yt/Gsp2Iooq/FcYlYnEPHb4GFzalg==",
- "dev": true,
- "requires": {
- "@tanstack/react-router": "1.19.1",
- "clsx": "^2.1.0",
- "date-fns": "^2.29.1",
- "goober": "^2.1.14"
- }
- },
- "@tanstack/router-generator": {
- "version": "1.19.0",
- "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.19.0.tgz",
- "integrity": "sha512-vFF8Q7SdyygiYC7lfJ83GRif0vcxjak9SAcgtX/w7TLR0O+qdxRXFPvhKTQQXH6vVezy5Au9bSaSI2EgDD1ubA==",
- "dev": true,
- "requires": {
- "prettier": "^3.1.1",
- "zod": "^3.22.4"
- }
- },
- "@tanstack/router-vite-plugin": {
- "version": "1.19.0",
- "resolved": "https://registry.npmjs.org/@tanstack/router-vite-plugin/-/router-vite-plugin-1.19.0.tgz",
- "integrity": "sha512-yvvQnJ7JvqsnxAFqwiHhNTV2n1jKkidjc+XbgS2aNnEHC0aHnYH2ygPlmmfiVD7PMO7x64PdI5e12TzY/aKoFA==",
- "dev": true,
- "requires": {
- "@tanstack/router-generator": "1.19.0"
- }
- },
- "@tanstack/store": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.1.3.tgz",
- "integrity": "sha512-GnolmC8Fr4mvsHE1fGQmR3Nm0eBO3KnZjDU0a+P3TeQNM/dDscFGxtA7p31NplQNW3KwBw4t1RVFmz0VeKLxcw=="
- },
- "@types/json-schema": {
- "version": "7.0.15",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
- "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
- "dev": true
- },
- "@types/lodash": {
- "version": "4.14.202",
- "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
- "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ=="
- },
- "@types/lodash.mergewith": {
- "version": "4.6.7",
- "resolved": "https://registry.npmjs.org/@types/lodash.mergewith/-/lodash.mergewith-4.6.7.tgz",
- "integrity": "sha512-3m+lkO5CLRRYU0fhGRp7zbsGi6+BZj0uTVSwvcKU+nSlhjA9/QRNfuSGnD2mX6hQA7ZbmcCkzk5h4ZYGOtk14A==",
- "requires": {
- "@types/lodash": "*"
- }
- },
- "@types/node": {
- "version": "20.10.5",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz",
- "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==",
- "dev": true,
- "requires": {
- "undici-types": "~5.26.4"
- }
- },
- "@types/parse-json": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
- "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="
- },
- "@types/prop-types": {
- "version": "15.7.11",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz",
- "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==",
- "devOptional": true
- },
- "@types/react": {
- "version": "18.2.39",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.39.tgz",
- "integrity": "sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==",
- "devOptional": true,
- "requires": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- }
- },
- "@types/react-dom": {
- "version": "18.2.17",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.17.tgz",
- "integrity": "sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==",
- "dev": true,
- "requires": {
- "@types/react": "*"
- }
- },
- "@types/scheduler": {
- "version": "0.16.8",
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
- "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==",
- "devOptional": true
- },
- "@vitejs/plugin-react-swc": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.5.0.tgz",
- "integrity": "sha512-1PrOvAaDpqlCV+Up8RkAh9qaiUjoDUcjtttyhXDKw53XA6Ve16SOp6cCOpRs8Dj8DqUQs6eTW5YkLcLJjrXAig==",
- "dev": true,
- "requires": {
- "@swc/core": "^1.3.96"
- }
- },
- "@zag-js/dom-query": {
- "version": "0.16.0",
- "resolved": "https://registry.npmjs.org/@zag-js/dom-query/-/dom-query-0.16.0.tgz",
- "integrity": "sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ=="
- },
- "@zag-js/element-size": {
- "version": "0.10.5",
- "resolved": "https://registry.npmjs.org/@zag-js/element-size/-/element-size-0.10.5.tgz",
- "integrity": "sha512-uQre5IidULANvVkNOBQ1tfgwTQcGl4hliPSe69Fct1VfYb2Fd0jdAcGzqQgPhfrXFpR62MxLPB7erxJ/ngtL8w=="
- },
- "@zag-js/focus-visible": {
- "version": "0.16.0",
- "resolved": "https://registry.npmjs.org/@zag-js/focus-visible/-/focus-visible-0.16.0.tgz",
- "integrity": "sha512-a7U/HSopvQbrDU4GLerpqiMcHKEkQkNPeDZJWz38cw/6Upunh41GjHetq5TB84hxyCaDzJ6q2nEdNoBQfC0FKA==",
- "requires": {
- "@zag-js/dom-query": "0.16.0"
- }
- },
- "argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "aria-hidden": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz",
- "integrity": "sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==",
- "requires": {
- "tslib": "^2.0.0"
- }
- },
- "asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
- },
- "axios": {
- "version": "1.7.4",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz",
- "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==",
- "requires": {
- "follow-redirects": "^1.15.6",
- "form-data": "^4.0.0",
- "proxy-from-env": "^1.1.0"
- }
- },
- "babel-plugin-macros": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
- "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "cosmiconfig": "^7.0.0",
- "resolve": "^1.19.0"
- }
- },
- "callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
- },
- "clsx": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
- "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
- "dev": true
- },
- "color2k": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/color2k/-/color2k-2.0.3.tgz",
- "integrity": "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog=="
- },
- "combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "requires": {
- "delayed-stream": "~1.0.0"
- }
- },
- "compute-scroll-into-view": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.0.3.tgz",
- "integrity": "sha512-nadqwNxghAGTamwIqQSG433W6OADZx2vCo3UXHNrzTRHK/htu+7+L0zhjEoaeaQVNAi3YgqWDv8+tzf0hRfR+A=="
- },
- "convert-source-map": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
- "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
- },
- "copy-to-clipboard": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
- "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
- "requires": {
- "toggle-selection": "^1.0.6"
- }
- },
- "cosmiconfig": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
- "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
- "requires": {
- "@types/parse-json": "^4.0.0",
- "import-fresh": "^3.2.1",
- "parse-json": "^5.0.0",
- "path-type": "^4.0.0",
- "yaml": "^1.10.0"
- }
- },
- "css-box-model": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
- "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==",
- "requires": {
- "tiny-invariant": "^1.0.6"
- }
- },
- "csstype": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
- "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
- },
- "date-fns": {
- "version": "2.30.0",
- "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
- "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.21.0"
- }
- },
- "delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
- },
- "detect-node-es": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
- "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
- },
- "dotenv": {
- "version": "16.4.5",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
- "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
- "dev": true
- },
- "error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
- "requires": {
- "is-arrayish": "^0.2.1"
- }
- },
- "esbuild": {
- "version": "0.19.8",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.8.tgz",
- "integrity": "sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==",
- "dev": true,
- "requires": {
- "@esbuild/android-arm": "0.19.8",
- "@esbuild/android-arm64": "0.19.8",
- "@esbuild/android-x64": "0.19.8",
- "@esbuild/darwin-arm64": "0.19.8",
- "@esbuild/darwin-x64": "0.19.8",
- "@esbuild/freebsd-arm64": "0.19.8",
- "@esbuild/freebsd-x64": "0.19.8",
- "@esbuild/linux-arm": "0.19.8",
- "@esbuild/linux-arm64": "0.19.8",
- "@esbuild/linux-ia32": "0.19.8",
- "@esbuild/linux-loong64": "0.19.8",
- "@esbuild/linux-mips64el": "0.19.8",
- "@esbuild/linux-ppc64": "0.19.8",
- "@esbuild/linux-riscv64": "0.19.8",
- "@esbuild/linux-s390x": "0.19.8",
- "@esbuild/linux-x64": "0.19.8",
- "@esbuild/netbsd-x64": "0.19.8",
- "@esbuild/openbsd-x64": "0.19.8",
- "@esbuild/sunos-x64": "0.19.8",
- "@esbuild/win32-arm64": "0.19.8",
- "@esbuild/win32-ia32": "0.19.8",
- "@esbuild/win32-x64": "0.19.8"
- }
- },
- "escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
- },
- "find-root": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
- "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
- },
- "focus-lock": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-1.3.3.tgz",
- "integrity": "sha512-hfXkZha7Xt4RQtrL1HBfspAuIj89Y0fb6GX0dfJilb8S2G/lvL4akPAcHq6xoD2NuZnDMCnZL/zQesMyeu6Psg==",
- "requires": {
- "tslib": "^2.0.3"
- }
- },
- "follow-redirects": {
- "version": "1.15.6",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
- "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA=="
- },
- "form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- }
- },
- "framer-motion": {
- "version": "10.16.16",
- "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.16.16.tgz",
- "integrity": "sha512-je6j91rd7NmUX7L1XHouwJ4v3R+SO4umso2LUcgOct3rHZ0PajZ80ETYZTajzEXEl9DlKyzjyt4AvGQ+lrebOw==",
- "requires": {
- "@emotion/is-prop-valid": "^0.8.2",
- "tslib": "^2.4.0"
- },
- "dependencies": {
- "@emotion/is-prop-valid": {
- "version": "0.8.8",
- "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
- "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
- "optional": true,
- "requires": {
- "@emotion/memoize": "0.7.4"
- }
- },
- "@emotion/memoize": {
- "version": "0.7.4",
- "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
- "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
- "optional": true
- }
- }
- },
- "framesync": {
- "version": "6.1.2",
- "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.1.2.tgz",
- "integrity": "sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==",
- "requires": {
- "tslib": "2.4.0"
- },
- "dependencies": {
- "tslib": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
- "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
- }
- }
- },
- "fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "optional": true
- },
- "function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
- },
- "get-nonce": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
- "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="
- },
- "goober": {
- "version": "2.1.14",
- "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.14.tgz",
- "integrity": "sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==",
- "dev": true,
- "requires": {}
- },
- "handlebars": {
- "version": "4.7.8",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
- "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.5",
- "neo-async": "^2.6.2",
- "source-map": "^0.6.1",
- "uglify-js": "^3.1.4",
- "wordwrap": "^1.0.0"
- }
- },
- "hasown": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
- "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
- "requires": {
- "function-bind": "^1.1.2"
- }
- },
- "hoist-non-react-statics": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
- "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
- "requires": {
- "react-is": "^16.7.0"
- }
- },
- "import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "requires": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- }
- },
- "invariant": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
- "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
- "requires": {
- "loose-envify": "^1.0.0"
- }
- },
- "is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
- },
- "is-core-module": {
- "version": "2.13.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
- "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
- "requires": {
- "hasown": "^2.0.0"
- }
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
- },
- "js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "requires": {
- "argparse": "^2.0.1"
- }
- },
- "json-parse-even-better-errors": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
- "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
- },
- "lines-and-columns": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
- "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
- },
- "lodash.mergewith": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
- "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="
- },
- "loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
- "mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
- },
- "mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "requires": {
- "mime-db": "1.52.0"
- }
- },
- "minimist": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
- "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "dev": true
- },
- "nanoid": {
- "version": "3.3.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
- "dev": true
- },
- "neo-async": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
- "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
- "dev": true
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
- },
- "parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "requires": {
- "callsites": "^3.0.0"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
- },
- "path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
- },
- "picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
- },
- "playwright": {
- "version": "1.45.2",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.2.tgz",
- "integrity": "sha512-ReywF2t/0teRvNBpfIgh5e4wnrI/8Su8ssdo5XsQKpjxJj+jspm00jSoz9BTg91TT0c9HRjXO7LBNVrgYj9X0g==",
- "dev": true,
- "requires": {
- "fsevents": "2.3.2",
- "playwright-core": "1.45.2"
- },
- "dependencies": {
- "fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "optional": true
- }
- }
- },
- "playwright-core": {
- "version": "1.45.2",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.2.tgz",
- "integrity": "sha512-ha175tAWb0dTK0X4orvBIqi3jGEt701SMxMhyujxNrgd8K0Uy5wMSwwcQHtyB4om7INUkfndx02XnQ2p6dvLDw==",
- "dev": true
- },
- "postcss": {
- "version": "8.4.35",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
- "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
- "dev": true,
- "requires": {
- "nanoid": "^3.3.7",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
- }
- },
- "prettier": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
- "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
- "dev": true
- },
- "prop-types": {
- "version": "15.8.1",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
- }
- },
- "proxy-from-env": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
- "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
- },
- "react": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
- "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
- "requires": {
- "loose-envify": "^1.1.0"
- }
- },
- "react-clientside-effect": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz",
- "integrity": "sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==",
- "requires": {
- "@babel/runtime": "^7.12.13"
- }
- },
- "react-dom": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
- "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
- "requires": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.0"
- }
- },
- "react-error-boundary": {
- "version": "4.0.13",
- "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz",
- "integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==",
- "requires": {
- "@babel/runtime": "^7.12.5"
- }
- },
- "react-fast-compare": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
- "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
- },
- "react-focus-lock": {
- "version": "2.11.1",
- "resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.11.1.tgz",
- "integrity": "sha512-IXLwnTBrLTlKTpASZXqqXJ8oymWrgAlOfuuDYN4XCuN1YJ72dwX198UCaF1QqGUk5C3QOnlMik//n3ufcfe8Ig==",
- "requires": {
- "@babel/runtime": "^7.0.0",
- "focus-lock": "^1.3.2",
- "prop-types": "^15.6.2",
- "react-clientside-effect": "^1.2.6",
- "use-callback-ref": "^1.3.0",
- "use-sidecar": "^1.1.2"
- }
- },
- "react-hook-form": {
- "version": "7.49.3",
- "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.49.3.tgz",
- "integrity": "sha512-foD6r3juidAT1cOZzpmD/gOKt7fRsDhXXZ0y28+Al1CHgX+AY1qIN9VSIIItXRq1dN68QrRwl1ORFlwjBaAqeQ==",
- "requires": {}
- },
- "react-icons": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz",
- "integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==",
- "requires": {}
- },
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
- },
- "react-remove-scroll": {
- "version": "2.5.7",
- "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz",
- "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==",
- "requires": {
- "react-remove-scroll-bar": "^2.3.4",
- "react-style-singleton": "^2.2.1",
- "tslib": "^2.1.0",
- "use-callback-ref": "^1.3.0",
- "use-sidecar": "^1.1.2"
- }
- },
- "react-remove-scroll-bar": {
- "version": "2.3.5",
- "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.5.tgz",
- "integrity": "sha512-3cqjOqg6s0XbOjWvmasmqHch+RLxIEk2r/70rzGXuz3iIGQsQheEQyqYCBb5EECoD01Vo2SIbDqW4paLeLTASw==",
- "requires": {
- "react-style-singleton": "^2.2.1",
- "tslib": "^2.0.0"
- }
- },
- "react-style-singleton": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
- "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
- "requires": {
- "get-nonce": "^1.0.0",
- "invariant": "^2.2.4",
- "tslib": "^2.0.0"
- }
- },
- "regenerator-runtime": {
- "version": "0.14.1",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
- "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
- },
- "resolve": {
- "version": "1.22.8",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
- "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
- "requires": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- }
- },
- "resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
- },
- "rollup": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.6.1.tgz",
- "integrity": "sha512-jZHaZotEHQaHLgKr8JnQiDT1rmatjgKlMekyksz+yk9jt/8z9quNjnKNRoaM0wd9DC2QKXjmWWuDYtM3jfF8pQ==",
- "dev": true,
- "requires": {
- "@rollup/rollup-android-arm-eabi": "4.6.1",
- "@rollup/rollup-android-arm64": "4.6.1",
- "@rollup/rollup-darwin-arm64": "4.6.1",
- "@rollup/rollup-darwin-x64": "4.6.1",
- "@rollup/rollup-linux-arm-gnueabihf": "4.6.1",
- "@rollup/rollup-linux-arm64-gnu": "4.6.1",
- "@rollup/rollup-linux-arm64-musl": "4.6.1",
- "@rollup/rollup-linux-x64-gnu": "4.6.1",
- "@rollup/rollup-linux-x64-musl": "4.6.1",
- "@rollup/rollup-win32-arm64-msvc": "4.6.1",
- "@rollup/rollup-win32-ia32-msvc": "4.6.1",
- "@rollup/rollup-win32-x64-msvc": "4.6.1",
- "fsevents": "~2.3.2"
- }
- },
- "scheduler": {
- "version": "0.23.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
- "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
- "requires": {
- "loose-envify": "^1.1.0"
- }
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
- },
- "source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "dev": true
- },
- "stylis": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
- "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
- },
- "supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
- },
- "tiny-invariant": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
- "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
- },
- "tiny-warning": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
- "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
- },
- "to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog=="
- },
- "toggle-selection": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
- "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
- },
- "tslib": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
- },
- "typescript": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz",
- "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==",
- "dev": true
- },
- "uglify-js": {
- "version": "3.17.4",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
- "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
- "dev": true,
- "optional": true
- },
- "undici-types": {
- "version": "5.26.5",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
- "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
- "dev": true
- },
- "use-callback-ref": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.1.tgz",
- "integrity": "sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==",
- "requires": {
- "tslib": "^2.0.0"
- }
- },
- "use-sidecar": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
- "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==",
- "requires": {
- "detect-node-es": "^1.1.0",
- "tslib": "^2.0.0"
- }
- },
- "use-sync-external-store": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
- "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
- "requires": {}
- },
- "vite": {
- "version": "5.0.13",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.13.tgz",
- "integrity": "sha512-/9ovhv2M2dGTuA+dY93B9trfyWMDRQw2jdVBhHNP6wr0oF34wG2i/N55801iZIpgUpnHDm4F/FabGQLyc+eOgg==",
- "dev": true,
- "requires": {
- "esbuild": "^0.19.3",
- "fsevents": "~2.3.3",
- "postcss": "^8.4.32",
- "rollup": "^4.2.0"
- }
- },
- "wordwrap": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
- "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
- "dev": true
- },
- "yaml": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
- "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
- },
- "zod": {
- "version": "3.22.4",
- "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
- "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
- "dev": true
- }
- }
-}
diff --git a/frontend/package.json b/frontend/package.json
deleted file mode 100644
index 1a7a547f68..0000000000
--- a/frontend/package.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "name": "frontend",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "vite",
- "build": "tsc && vite build",
- "lint": "biome check --apply-unsafe --no-errors-on-unmatched --files-ignore-unknown=true ./",
- "preview": "vite preview",
- "generate-client": "openapi-ts --input ./openapi.json --output ./src/client --client axios --exportSchemas true"
- },
- "dependencies": {
- "@chakra-ui/icons": "2.1.1",
- "@chakra-ui/react": "2.8.2",
- "@emotion/react": "11.11.3",
- "@emotion/styled": "11.11.0",
- "@tanstack/react-query": "^5.28.14",
- "@tanstack/react-query-devtools": "^5.28.14",
- "@tanstack/react-router": "1.19.1",
- "axios": "1.7.4",
- "form-data": "4.0.0",
- "framer-motion": "10.16.16",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-error-boundary": "^4.0.13",
- "react-hook-form": "7.49.3",
- "react-icons": "5.0.1"
- },
- "devDependencies": {
- "@biomejs/biome": "1.6.1",
- "@hey-api/openapi-ts": "^0.34.1",
- "@playwright/test": "^1.45.2",
- "@tanstack/router-devtools": "1.19.1",
- "@tanstack/router-vite-plugin": "1.19.0",
- "@types/node": "^20.10.5",
- "@types/react": "^18.2.37",
- "@types/react-dom": "^18.2.15",
- "@vitejs/plugin-react-swc": "^3.5.0",
- "dotenv": "^16.4.5",
- "typescript": "^5.2.2",
- "vite": "^5.0.13"
- }
-}
diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts
deleted file mode 100644
index dcdd6fec81..0000000000
--- a/frontend/playwright.config.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import { defineConfig, devices } from '@playwright/test';
-
-
-/**
- * Read environment variables from file.
- * https://github.com/motdotla/dotenv
- */
-// require('dotenv').config();
-
-/**
- * See https://playwright.dev/docs/test-configuration.
- */
-export default defineConfig({
- testDir: './tests',
- /* Run tests in files in parallel */
- fullyParallel: true,
- /* Fail the build on CI if you accidentally left test.only in the source code. */
- forbidOnly: !!process.env.CI,
- /* Retry on CI only */
- retries: process.env.CI ? 2 : 0,
- /* Opt out of parallel tests on CI. */
- workers: process.env.CI ? 1 : undefined,
- /* Reporter to use. See https://playwright.dev/docs/test-reporters */
- reporter: 'html',
- /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
- use: {
- /* Base URL to use in actions like `await page.goto('/')`. */
- baseURL: 'http://localhost:5173',
-
- /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
- trace: 'on-first-retry',
- },
-
- /* Configure projects for major browsers */
- projects: [
- { name: 'setup', testMatch: /.*\.setup\.ts/ },
-
- {
- name: 'chromium',
- use: {
- ...devices['Desktop Chrome'],
- storageState: 'playwright/.auth/user.json',
- },
- dependencies: ['setup'],
- },
-
- // {
- // name: 'firefox',
- // use: {
- // ...devices['Desktop Firefox'],
- // storageState: 'playwright/.auth/user.json',
- // },
- // dependencies: ['setup'],
- // },
-
- // {
- // name: 'webkit',
- // use: {
- // ...devices['Desktop Safari'],
- // storageState: 'playwright/.auth/user.json',
- // },
- // dependencies: ['setup'],
- // },
-
- /* Test against mobile viewports. */
- // {
- // name: 'Mobile Chrome',
- // use: { ...devices['Pixel 5'] },
- // },
- // {
- // name: 'Mobile Safari',
- // use: { ...devices['iPhone 12'] },
- // },
-
- /* Test against branded browsers. */
- // {
- // name: 'Microsoft Edge',
- // use: { ...devices['Desktop Edge'], channel: 'msedge' },
- // },
- // {
- // name: 'Google Chrome',
- // use: { ...devices['Desktop Chrome'], channel: 'chrome' },
- // },
- ],
-
- /* Run your local dev server before starting the tests */
- webServer: {
- command: 'npm run dev',
- url: 'http://localhost:5173',
- reuseExistingServer: !process.env.CI,
- },
-});
diff --git a/frontend/public/assets/images/fastapi-logo.svg b/frontend/public/assets/images/fastapi-logo.svg
deleted file mode 100644
index d3dad4bec8..0000000000
--- a/frontend/public/assets/images/fastapi-logo.svg
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
diff --git a/frontend/public/assets/images/favicon.png b/frontend/public/assets/images/favicon.png
deleted file mode 100644
index e5b7c3ada7..0000000000
Binary files a/frontend/public/assets/images/favicon.png and /dev/null differ
diff --git a/frontend/src/client/core/ApiError.ts b/frontend/src/client/core/ApiError.ts
deleted file mode 100644
index 5499aa8f05..0000000000
--- a/frontend/src/client/core/ApiError.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import type { ApiRequestOptions } from "./ApiRequestOptions"
-import type { ApiResult } from "./ApiResult"
-
-export class ApiError extends Error {
- public readonly url: string
- public readonly status: number
- public readonly statusText: string
- public readonly body: unknown
- public readonly request: ApiRequestOptions
-
- constructor(
- request: ApiRequestOptions,
- response: ApiResult,
- message: string,
- ) {
- super(message)
-
- this.name = "ApiError"
- this.url = response.url
- this.status = response.status
- this.statusText = response.statusText
- this.body = response.body
- this.request = request
- }
-}
diff --git a/frontend/src/client/core/ApiRequestOptions.ts b/frontend/src/client/core/ApiRequestOptions.ts
deleted file mode 100644
index 4cc259284f..0000000000
--- a/frontend/src/client/core/ApiRequestOptions.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-export type ApiRequestOptions = {
- readonly method:
- | "GET"
- | "PUT"
- | "POST"
- | "DELETE"
- | "OPTIONS"
- | "HEAD"
- | "PATCH"
- readonly url: string
- readonly path?: Record
- readonly cookies?: Record
- readonly headers?: Record
- readonly query?: Record
- readonly formData?: Record
- readonly body?: any
- readonly mediaType?: string
- readonly responseHeader?: string
- readonly errors?: Record
-}
diff --git a/frontend/src/client/core/ApiResult.ts b/frontend/src/client/core/ApiResult.ts
deleted file mode 100644
index f88b8c64f1..0000000000
--- a/frontend/src/client/core/ApiResult.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export type ApiResult = {
- readonly body: TData
- readonly ok: boolean
- readonly status: number
- readonly statusText: string
- readonly url: string
-}
diff --git a/frontend/src/client/core/CancelablePromise.ts b/frontend/src/client/core/CancelablePromise.ts
deleted file mode 100644
index f47db79eae..0000000000
--- a/frontend/src/client/core/CancelablePromise.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-export class CancelError extends Error {
- constructor(message: string) {
- super(message)
- this.name = "CancelError"
- }
-
- public get isCancelled(): boolean {
- return true
- }
-}
-
-export interface OnCancel {
- readonly isResolved: boolean
- readonly isRejected: boolean
- readonly isCancelled: boolean
-
- (cancelHandler: () => void): void
-}
-
-export class CancelablePromise implements Promise {
- private _isResolved: boolean
- private _isRejected: boolean
- private _isCancelled: boolean
- readonly cancelHandlers: (() => void)[]
- readonly promise: Promise
- private _resolve?: (value: T | PromiseLike) => void
- private _reject?: (reason?: unknown) => void
-
- constructor(
- executor: (
- resolve: (value: T | PromiseLike) => void,
- reject: (reason?: unknown) => void,
- onCancel: OnCancel,
- ) => void,
- ) {
- this._isResolved = false
- this._isRejected = false
- this._isCancelled = false
- this.cancelHandlers = []
- this.promise = new Promise((resolve, reject) => {
- this._resolve = resolve
- this._reject = reject
-
- const onResolve = (value: T | PromiseLike): void => {
- if (this._isResolved || this._isRejected || this._isCancelled) {
- return
- }
- this._isResolved = true
- if (this._resolve) this._resolve(value)
- }
-
- const onReject = (reason?: unknown): void => {
- if (this._isResolved || this._isRejected || this._isCancelled) {
- return
- }
- this._isRejected = true
- if (this._reject) this._reject(reason)
- }
-
- const onCancel = (cancelHandler: () => void): void => {
- if (this._isResolved || this._isRejected || this._isCancelled) {
- return
- }
- this.cancelHandlers.push(cancelHandler)
- }
-
- Object.defineProperty(onCancel, "isResolved", {
- get: (): boolean => this._isResolved,
- })
-
- Object.defineProperty(onCancel, "isRejected", {
- get: (): boolean => this._isRejected,
- })
-
- Object.defineProperty(onCancel, "isCancelled", {
- get: (): boolean => this._isCancelled,
- })
-
- return executor(onResolve, onReject, onCancel as OnCancel)
- })
- }
-
- get [Symbol.toStringTag]() {
- return "Cancellable Promise"
- }
-
- public then(
- onFulfilled?: ((value: T) => TResult1 | PromiseLike) | null,
- onRejected?: ((reason: unknown) => TResult2 | PromiseLike) | null,
- ): Promise {
- return this.promise.then(onFulfilled, onRejected)
- }
-
- public catch(
- onRejected?: ((reason: unknown) => TResult | PromiseLike) | null,
- ): Promise {
- return this.promise.catch(onRejected)
- }
-
- public finally(onFinally?: (() => void) | null): Promise {
- return this.promise.finally(onFinally)
- }
-
- public cancel(): void {
- if (this._isResolved || this._isRejected || this._isCancelled) {
- return
- }
- this._isCancelled = true
- if (this.cancelHandlers.length) {
- try {
- for (const cancelHandler of this.cancelHandlers) {
- cancelHandler()
- }
- } catch (error) {
- console.warn("Cancellation threw an error", error)
- return
- }
- }
- this.cancelHandlers.length = 0
- if (this._reject) this._reject(new CancelError("Request aborted"))
- }
-
- public get isCancelled(): boolean {
- return this._isCancelled
- }
-}
diff --git a/frontend/src/client/core/OpenAPI.ts b/frontend/src/client/core/OpenAPI.ts
deleted file mode 100644
index 746df5e61d..0000000000
--- a/frontend/src/client/core/OpenAPI.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import type { AxiosRequestConfig, AxiosResponse } from "axios"
-import type { ApiRequestOptions } from "./ApiRequestOptions"
-import type { TResult } from "./types"
-
-type Headers = Record
-type Middleware = (value: T) => T | Promise
-type Resolver = (options: ApiRequestOptions) => Promise
-
-export class Interceptors {
- _fns: Middleware[]
-
- constructor() {
- this._fns = []
- }
-
- eject(fn: Middleware) {
- const index = this._fns.indexOf(fn)
- if (index !== -1) {
- this._fns = [...this._fns.slice(0, index), ...this._fns.slice(index + 1)]
- }
- }
-
- use(fn: Middleware) {
- this._fns = [...this._fns, fn]
- }
-}
-
-export type OpenAPIConfig = {
- BASE: string
- CREDENTIALS: "include" | "omit" | "same-origin"
- ENCODE_PATH?: ((path: string) => string) | undefined
- HEADERS?: Headers | Resolver | undefined
- PASSWORD?: string | Resolver | undefined
- RESULT?: TResult
- TOKEN?: string | Resolver | undefined
- USERNAME?: string | Resolver | undefined
- VERSION: string
- WITH_CREDENTIALS: boolean
- interceptors: {
- request: Interceptors
- response: Interceptors
- }
-}
-
-export const OpenAPI: OpenAPIConfig = {
- BASE: "",
- CREDENTIALS: "include",
- ENCODE_PATH: undefined,
- HEADERS: undefined,
- PASSWORD: undefined,
- RESULT: "body",
- TOKEN: undefined,
- USERNAME: undefined,
- VERSION: "0.1.0",
- WITH_CREDENTIALS: false,
- interceptors: { request: new Interceptors(), response: new Interceptors() },
-}
diff --git a/frontend/src/client/core/request.ts b/frontend/src/client/core/request.ts
deleted file mode 100644
index 99d38b46f1..0000000000
--- a/frontend/src/client/core/request.ts
+++ /dev/null
@@ -1,376 +0,0 @@
-import axios from "axios"
-import type {
- AxiosError,
- AxiosRequestConfig,
- AxiosResponse,
- AxiosInstance,
-} from "axios"
-
-import { ApiError } from "./ApiError"
-import type { ApiRequestOptions } from "./ApiRequestOptions"
-import type { ApiResult } from "./ApiResult"
-import { CancelablePromise } from "./CancelablePromise"
-import type { OnCancel } from "./CancelablePromise"
-import type { OpenAPIConfig } from "./OpenAPI"
-
-export const isString = (value: unknown): value is string => {
- return typeof value === "string"
-}
-
-export const isStringWithValue = (value: unknown): value is string => {
- return isString(value) && value !== ""
-}
-
-export const isBlob = (value: any): value is Blob => {
- return value instanceof Blob
-}
-
-export const isFormData = (value: unknown): value is FormData => {
- return value instanceof FormData
-}
-
-export const isSuccess = (status: number): boolean => {
- return status >= 200 && status < 300
-}
-
-export const base64 = (str: string): string => {
- try {
- return btoa(str)
- } catch (err) {
- // @ts-ignore
- return Buffer.from(str).toString("base64")
- }
-}
-
-export const getQueryString = (params: Record): string => {
- const qs: string[] = []
-
- const append = (key: string, value: unknown) => {
- qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
- }
-
- const encodePair = (key: string, value: unknown) => {
- if (value === undefined || value === null) {
- return
- }
-
- if (Array.isArray(value)) {
- value.forEach((v) => encodePair(key, v))
- } else if (typeof value === "object") {
- Object.entries(value).forEach(([k, v]) => encodePair(`${key}[${k}]`, v))
- } else {
- append(key, value)
- }
- }
-
- Object.entries(params).forEach(([key, value]) => encodePair(key, value))
-
- return qs.length ? `?${qs.join("&")}` : ""
-}
-
-const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => {
- const encoder = config.ENCODE_PATH || encodeURI
-
- const path = options.url
- .replace("{api-version}", config.VERSION)
- .replace(/{(.*?)}/g, (substring: string, group: string) => {
- if (options.path?.hasOwnProperty(group)) {
- return encoder(String(options.path[group]))
- }
- return substring
- })
-
- const url = config.BASE + path
- return options.query ? url + getQueryString(options.query) : url
-}
-
-export const getFormData = (
- options: ApiRequestOptions,
-): FormData | undefined => {
- if (options.formData) {
- const formData = new FormData()
-
- const process = (key: string, value: unknown) => {
- if (isString(value) || isBlob(value)) {
- formData.append(key, value)
- } else {
- formData.append(key, JSON.stringify(value))
- }
- }
-
- Object.entries(options.formData)
- .filter(([, value]) => value !== undefined && value !== null)
- .forEach(([key, value]) => {
- if (Array.isArray(value)) {
- value.forEach((v) => process(key, v))
- } else {
- process(key, value)
- }
- })
-
- return formData
- }
- return undefined
-}
-
-type Resolver = (options: ApiRequestOptions) => Promise
-
-export const resolve = async (
- options: ApiRequestOptions,
- resolver?: T | Resolver,
-): Promise => {
- if (typeof resolver === "function") {
- return (resolver as Resolver)(options)
- }
- return resolver
-}
-
-export const getHeaders = async (
- config: OpenAPIConfig,
- options: ApiRequestOptions,
-): Promise> => {
- const [token, username, password, additionalHeaders] = await Promise.all([
- resolve(options, config.TOKEN),
- resolve(options, config.USERNAME),
- resolve(options, config.PASSWORD),
- resolve(options, config.HEADERS),
- ])
-
- const headers = Object.entries({
- Accept: "application/json",
- ...additionalHeaders,
- ...options.headers,
- })
- .filter(([, value]) => value !== undefined && value !== null)
- .reduce(
- (headers, [key, value]) => ({
- ...headers,
- [key]: String(value),
- }),
- {} as Record,
- )
-
- if (isStringWithValue(token)) {
- headers["Authorization"] = `Bearer ${token}`
- }
-
- if (isStringWithValue(username) && isStringWithValue(password)) {
- const credentials = base64(`${username}:${password}`)
- headers["Authorization"] = `Basic ${credentials}`
- }
-
- if (options.body !== undefined) {
- if (options.mediaType) {
- headers["Content-Type"] = options.mediaType
- } else if (isBlob(options.body)) {
- headers["Content-Type"] = options.body.type || "application/octet-stream"
- } else if (isString(options.body)) {
- headers["Content-Type"] = "text/plain"
- } else if (!isFormData(options.body)) {
- headers["Content-Type"] = "application/json"
- }
- } else if (options.formData !== undefined) {
- if (options.mediaType) {
- headers["Content-Type"] = options.mediaType
- }
- }
-
- return headers
-}
-
-export const getRequestBody = (options: ApiRequestOptions): unknown => {
- if (options.body) {
- return options.body
- }
- return undefined
-}
-
-export const sendRequest = async (
- config: OpenAPIConfig,
- options: ApiRequestOptions,
- url: string,
- body: unknown,
- formData: FormData | undefined,
- headers: Record,
- onCancel: OnCancel,
- axiosClient: AxiosInstance,
-): Promise> => {
- const controller = new AbortController()
-
- let requestConfig: AxiosRequestConfig = {
- data: body ?? formData,
- headers,
- method: options.method,
- signal: controller.signal,
- url,
- withCredentials: config.WITH_CREDENTIALS,
- }
-
- onCancel(() => controller.abort())
-
- for (const fn of config.interceptors.request._fns) {
- requestConfig = await fn(requestConfig)
- }
-
- try {
- return await axiosClient.request(requestConfig)
- } catch (error) {
- const axiosError = error as AxiosError
- if (axiosError.response) {
- return axiosError.response
- }
- throw error
- }
-}
-
-export const getResponseHeader = (
- response: AxiosResponse,
- responseHeader?: string,
-): string | undefined => {
- if (responseHeader) {
- const content = response.headers[responseHeader]
- if (isString(content)) {
- return content
- }
- }
- return undefined
-}
-
-export const getResponseBody = (response: AxiosResponse): unknown => {
- if (response.status !== 204) {
- return response.data
- }
- return undefined
-}
-
-export const catchErrorCodes = (
- options: ApiRequestOptions,
- result: ApiResult,
-): void => {
- const errors: Record = {
- 400: "Bad Request",
- 401: "Unauthorized",
- 402: "Payment Required",
- 403: "Forbidden",
- 404: "Not Found",
- 405: "Method Not Allowed",
- 406: "Not Acceptable",
- 407: "Proxy Authentication Required",
- 408: "Request Timeout",
- 409: "Conflict",
- 410: "Gone",
- 411: "Length Required",
- 412: "Precondition Failed",
- 413: "Payload Too Large",
- 414: "URI Too Long",
- 415: "Unsupported Media Type",
- 416: "Range Not Satisfiable",
- 417: "Expectation Failed",
- 418: "Im a teapot",
- 421: "Misdirected Request",
- 422: "Unprocessable Content",
- 423: "Locked",
- 424: "Failed Dependency",
- 425: "Too Early",
- 426: "Upgrade Required",
- 428: "Precondition Required",
- 429: "Too Many Requests",
- 431: "Request Header Fields Too Large",
- 451: "Unavailable For Legal Reasons",
- 500: "Internal Server Error",
- 501: "Not Implemented",
- 502: "Bad Gateway",
- 503: "Service Unavailable",
- 504: "Gateway Timeout",
- 505: "HTTP Version Not Supported",
- 506: "Variant Also Negotiates",
- 507: "Insufficient Storage",
- 508: "Loop Detected",
- 510: "Not Extended",
- 511: "Network Authentication Required",
- ...options.errors,
- }
-
- const error = errors[result.status]
- if (error) {
- throw new ApiError(options, result, error)
- }
-
- if (!result.ok) {
- const errorStatus = result.status ?? "unknown"
- const errorStatusText = result.statusText ?? "unknown"
- const errorBody = (() => {
- try {
- return JSON.stringify(result.body, null, 2)
- } catch (e) {
- return undefined
- }
- })()
-
- throw new ApiError(
- options,
- result,
- `Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}`,
- )
- }
-}
-
-/**
- * Request method
- * @param config The OpenAPI configuration object
- * @param options The request options from the service
- * @param axiosClient The axios client instance to use
- * @returns CancelablePromise
- * @throws ApiError
- */
-export const request = (
- config: OpenAPIConfig,
- options: ApiRequestOptions,
- axiosClient: AxiosInstance = axios,
-): CancelablePromise => {
- return new CancelablePromise(async (resolve, reject, onCancel) => {
- try {
- const url = getUrl(config, options)
- const formData = getFormData(options)
- const body = getRequestBody(options)
- const headers = await getHeaders(config, options)
-
- if (!onCancel.isCancelled) {
- let response = await sendRequest(
- config,
- options,
- url,
- body,
- formData,
- headers,
- onCancel,
- axiosClient,
- )
-
- for (const fn of config.interceptors.response._fns) {
- response = await fn(response)
- }
-
- const responseBody = getResponseBody(response)
- const responseHeader = getResponseHeader(
- response,
- options.responseHeader,
- )
-
- const result: ApiResult = {
- url,
- ok: isSuccess(response.status),
- status: response.status,
- statusText: response.statusText,
- body: responseHeader ?? responseBody,
- }
-
- catchErrorCodes(options, result)
-
- resolve(result.body)
- }
- } catch (error) {
- reject(error)
- }
- })
-}
diff --git a/frontend/src/client/core/types.ts b/frontend/src/client/core/types.ts
deleted file mode 100644
index 199c08d3df..0000000000
--- a/frontend/src/client/core/types.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import type { ApiResult } from "./ApiResult"
-
-export type TResult = "body" | "raw"
-
-export type TApiResponse = Exclude<
- T,
- "raw"
-> extends never
- ? ApiResult
- : ApiResult["body"]
-
-export type TConfig = {
- _result?: T
-}
diff --git a/frontend/src/client/index.ts b/frontend/src/client/index.ts
deleted file mode 100644
index adf1d0cabf..0000000000
--- a/frontend/src/client/index.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export { ApiError } from "./core/ApiError"
-export { CancelablePromise, CancelError } from "./core/CancelablePromise"
-export { OpenAPI } from "./core/OpenAPI"
-export type { OpenAPIConfig } from "./core/OpenAPI"
-
-export * from "./models"
-export * from "./schemas"
-export * from "./services"
diff --git a/frontend/src/client/models.ts b/frontend/src/client/models.ts
deleted file mode 100644
index 2c8074ddd6..0000000000
--- a/frontend/src/client/models.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-export type Body_login_login_access_token = {
- grant_type?: string | null
- username: string
- password: string
- scope?: string
- client_id?: string | null
- client_secret?: string | null
-}
-
-export type HTTPValidationError = {
- detail?: Array
-}
-
-export type ItemCreate = {
- title: string
- description?: string | null
-}
-
-export type ItemPublic = {
- title: string
- description?: string | null
- id: string
- owner_id: string
-}
-
-export type ItemUpdate = {
- title?: string | null
- description?: string | null
-}
-
-export type ItemsPublic = {
- data: Array
- count: number
-}
-
-export type Message = {
- message: string
-}
-
-export type NewPassword = {
- token: string
- new_password: string
-}
-
-export type Token = {
- access_token: string
- token_type?: string
-}
-
-export type UpdatePassword = {
- current_password: string
- new_password: string
-}
-
-export type UserCreate = {
- email: string
- is_active?: boolean
- is_superuser?: boolean
- full_name?: string | null
- password: string
-}
-
-export type UserPublic = {
- email: string
- is_active?: boolean
- is_superuser?: boolean
- full_name?: string | null
- id: string
-}
-
-export type UserRegister = {
- email: string
- password: string
- full_name?: string | null
-}
-
-export type UserUpdate = {
- email?: string | null
- is_active?: boolean
- is_superuser?: boolean
- full_name?: string | null
- password?: string | null
-}
-
-export type UserUpdateMe = {
- full_name?: string | null
- email?: string | null
-}
-
-export type UsersPublic = {
- data: Array
- count: number
-}
-
-export type ValidationError = {
- loc: Array
- msg: string
- type: string
-}
diff --git a/frontend/src/client/schemas.ts b/frontend/src/client/schemas.ts
deleted file mode 100644
index 9e92efd106..0000000000
--- a/frontend/src/client/schemas.ts
+++ /dev/null
@@ -1,444 +0,0 @@
-export const $Body_login_login_access_token = {
- properties: {
- grant_type: {
- type: "any-of",
- contains: [
- {
- type: "string",
- pattern: "password",
- },
- {
- type: "null",
- },
- ],
- },
- username: {
- type: "string",
- isRequired: true,
- },
- password: {
- type: "string",
- isRequired: true,
- },
- scope: {
- type: "string",
- default: "",
- },
- client_id: {
- type: "any-of",
- contains: [
- {
- type: "string",
- },
- {
- type: "null",
- },
- ],
- },
- client_secret: {
- type: "any-of",
- contains: [
- {
- type: "string",
- },
- {
- type: "null",
- },
- ],
- },
- },
-} as const
-
-export const $HTTPValidationError = {
- properties: {
- detail: {
- type: "array",
- contains: {
- type: "ValidationError",
- },
- },
- },
-} as const
-
-export const $ItemCreate = {
- properties: {
- title: {
- type: "string",
- isRequired: true,
- maxLength: 255,
- minLength: 1,
- },
- description: {
- type: "any-of",
- contains: [
- {
- type: "string",
- maxLength: 255,
- },
- {
- type: "null",
- },
- ],
- },
- },
-} as const
-
-export const $ItemPublic = {
- properties: {
- title: {
- type: "string",
- isRequired: true,
- maxLength: 255,
- minLength: 1,
- },
- description: {
- type: "any-of",
- contains: [
- {
- type: "string",
- maxLength: 255,
- },
- {
- type: "null",
- },
- ],
- },
- id: {
- type: "string",
- isRequired: true,
- format: "uuid",
- },
- owner_id: {
- type: "string",
- isRequired: true,
- format: "uuid",
- },
- },
-} as const
-
-export const $ItemUpdate = {
- properties: {
- title: {
- type: "any-of",
- contains: [
- {
- type: "string",
- maxLength: 255,
- minLength: 1,
- },
- {
- type: "null",
- },
- ],
- },
- description: {
- type: "any-of",
- contains: [
- {
- type: "string",
- maxLength: 255,
- },
- {
- type: "null",
- },
- ],
- },
- },
-} as const
-
-export const $ItemsPublic = {
- properties: {
- data: {
- type: "array",
- contains: {
- type: "ItemPublic",
- },
- isRequired: true,
- },
- count: {
- type: "number",
- isRequired: true,
- },
- },
-} as const
-
-export const $Message = {
- properties: {
- message: {
- type: "string",
- isRequired: true,
- },
- },
-} as const
-
-export const $NewPassword = {
- properties: {
- token: {
- type: "string",
- isRequired: true,
- },
- new_password: {
- type: "string",
- isRequired: true,
- maxLength: 40,
- minLength: 8,
- },
- },
-} as const
-
-export const $Token = {
- properties: {
- access_token: {
- type: "string",
- isRequired: true,
- },
- token_type: {
- type: "string",
- default: "bearer",
- },
- },
-} as const
-
-export const $UpdatePassword = {
- properties: {
- current_password: {
- type: "string",
- isRequired: true,
- maxLength: 40,
- minLength: 8,
- },
- new_password: {
- type: "string",
- isRequired: true,
- maxLength: 40,
- minLength: 8,
- },
- },
-} as const
-
-export const $UserCreate = {
- properties: {
- email: {
- type: "string",
- isRequired: true,
- format: "email",
- maxLength: 255,
- },
- is_active: {
- type: "boolean",
- default: true,
- },
- is_superuser: {
- type: "boolean",
- default: false,
- },
- full_name: {
- type: "any-of",
- contains: [
- {
- type: "string",
- maxLength: 255,
- },
- {
- type: "null",
- },
- ],
- },
- password: {
- type: "string",
- isRequired: true,
- maxLength: 40,
- minLength: 8,
- },
- },
-} as const
-
-export const $UserPublic = {
- properties: {
- email: {
- type: "string",
- isRequired: true,
- format: "email",
- maxLength: 255,
- },
- is_active: {
- type: "boolean",
- default: true,
- },
- is_superuser: {
- type: "boolean",
- default: false,
- },
- full_name: {
- type: "any-of",
- contains: [
- {
- type: "string",
- maxLength: 255,
- },
- {
- type: "null",
- },
- ],
- },
- id: {
- type: "string",
- isRequired: true,
- format: "uuid",
- },
- },
-} as const
-
-export const $UserRegister = {
- properties: {
- email: {
- type: "string",
- isRequired: true,
- format: "email",
- maxLength: 255,
- },
- password: {
- type: "string",
- isRequired: true,
- maxLength: 40,
- minLength: 8,
- },
- full_name: {
- type: "any-of",
- contains: [
- {
- type: "string",
- maxLength: 255,
- },
- {
- type: "null",
- },
- ],
- },
- },
-} as const
-
-export const $UserUpdate = {
- properties: {
- email: {
- type: "any-of",
- contains: [
- {
- type: "string",
- format: "email",
- maxLength: 255,
- },
- {
- type: "null",
- },
- ],
- },
- is_active: {
- type: "boolean",
- default: true,
- },
- is_superuser: {
- type: "boolean",
- default: false,
- },
- full_name: {
- type: "any-of",
- contains: [
- {
- type: "string",
- maxLength: 255,
- },
- {
- type: "null",
- },
- ],
- },
- password: {
- type: "any-of",
- contains: [
- {
- type: "string",
- maxLength: 40,
- minLength: 8,
- },
- {
- type: "null",
- },
- ],
- },
- },
-} as const
-
-export const $UserUpdateMe = {
- properties: {
- full_name: {
- type: "any-of",
- contains: [
- {
- type: "string",
- maxLength: 255,
- },
- {
- type: "null",
- },
- ],
- },
- email: {
- type: "any-of",
- contains: [
- {
- type: "string",
- format: "email",
- maxLength: 255,
- },
- {
- type: "null",
- },
- ],
- },
- },
-} as const
-
-export const $UsersPublic = {
- properties: {
- data: {
- type: "array",
- contains: {
- type: "UserPublic",
- },
- isRequired: true,
- },
- count: {
- type: "number",
- isRequired: true,
- },
- },
-} as const
-
-export const $ValidationError = {
- properties: {
- loc: {
- type: "array",
- contains: {
- type: "any-of",
- contains: [
- {
- type: "string",
- },
- {
- type: "number",
- },
- ],
- },
- isRequired: true,
- },
- msg: {
- type: "string",
- isRequired: true,
- },
- type: {
- type: "string",
- isRequired: true,
- },
- },
-} as const
diff --git a/frontend/src/client/services.ts b/frontend/src/client/services.ts
deleted file mode 100644
index b99e4ac515..0000000000
--- a/frontend/src/client/services.ts
+++ /dev/null
@@ -1,517 +0,0 @@
-import type { CancelablePromise } from "./core/CancelablePromise"
-import { OpenAPI } from "./core/OpenAPI"
-import { request as __request } from "./core/request"
-
-import type {
- Body_login_login_access_token,
- Message,
- NewPassword,
- Token,
- UserPublic,
- UpdatePassword,
- UserCreate,
- UserRegister,
- UsersPublic,
- UserUpdate,
- UserUpdateMe,
- ItemCreate,
- ItemPublic,
- ItemsPublic,
- ItemUpdate,
-} from "./models"
-
-export type TDataLoginAccessToken = {
- formData: Body_login_login_access_token
-}
-export type TDataRecoverPassword = {
- email: string
-}
-export type TDataResetPassword = {
- requestBody: NewPassword
-}
-export type TDataRecoverPasswordHtmlContent = {
- email: string
-}
-
-export class LoginService {
- /**
- * Login Access Token
- * OAuth2 compatible token login, get an access token for future requests
- * @returns Token Successful Response
- * @throws ApiError
- */
- public static loginAccessToken(
- data: TDataLoginAccessToken,
- ): CancelablePromise {
- const { formData } = data
- return __request(OpenAPI, {
- method: "POST",
- url: "/api/v1/login/access-token",
- formData: formData,
- mediaType: "application/x-www-form-urlencoded",
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Test Token
- * Test access token
- * @returns UserPublic Successful Response
- * @throws ApiError
- */
- public static testToken(): CancelablePromise {
- return __request(OpenAPI, {
- method: "POST",
- url: "/api/v1/login/test-token",
- })
- }
-
- /**
- * Recover Password
- * Password Recovery
- * @returns Message Successful Response
- * @throws ApiError
- */
- public static recoverPassword(
- data: TDataRecoverPassword,
- ): CancelablePromise {
- const { email } = data
- return __request(OpenAPI, {
- method: "POST",
- url: "/api/v1/password-recovery/{email}",
- path: {
- email,
- },
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Reset Password
- * Reset password
- * @returns Message Successful Response
- * @throws ApiError
- */
- public static resetPassword(
- data: TDataResetPassword,
- ): CancelablePromise {
- const { requestBody } = data
- return __request(OpenAPI, {
- method: "POST",
- url: "/api/v1/reset-password/",
- body: requestBody,
- mediaType: "application/json",
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Recover Password Html Content
- * HTML Content for Password Recovery
- * @returns string Successful Response
- * @throws ApiError
- */
- public static recoverPasswordHtmlContent(
- data: TDataRecoverPasswordHtmlContent,
- ): CancelablePromise {
- const { email } = data
- return __request(OpenAPI, {
- method: "POST",
- url: "/api/v1/password-recovery-html-content/{email}",
- path: {
- email,
- },
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-}
-
-export type TDataReadUsers = {
- limit?: number
- skip?: number
-}
-export type TDataCreateUser = {
- requestBody: UserCreate
-}
-export type TDataUpdateUserMe = {
- requestBody: UserUpdateMe
-}
-export type TDataUpdatePasswordMe = {
- requestBody: UpdatePassword
-}
-export type TDataRegisterUser = {
- requestBody: UserRegister
-}
-export type TDataReadUserById = {
- userId: string
-}
-export type TDataUpdateUser = {
- requestBody: UserUpdate
- userId: string
-}
-export type TDataDeleteUser = {
- userId: string
-}
-
-export class UsersService {
- /**
- * Read Users
- * Retrieve users.
- * @returns UsersPublic Successful Response
- * @throws ApiError
- */
- public static readUsers(
- data: TDataReadUsers = {},
- ): CancelablePromise {
- const { limit = 100, skip = 0 } = data
- return __request(OpenAPI, {
- method: "GET",
- url: "/api/v1/users/",
- query: {
- skip,
- limit,
- },
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Create User
- * Create new user.
- * @returns UserPublic Successful Response
- * @throws ApiError
- */
- public static createUser(
- data: TDataCreateUser,
- ): CancelablePromise {
- const { requestBody } = data
- return __request(OpenAPI, {
- method: "POST",
- url: "/api/v1/users/",
- body: requestBody,
- mediaType: "application/json",
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Read User Me
- * Get current user.
- * @returns UserPublic Successful Response
- * @throws ApiError
- */
- public static readUserMe(): CancelablePromise {
- return __request(OpenAPI, {
- method: "GET",
- url: "/api/v1/users/me",
- })
- }
-
- /**
- * Delete User Me
- * Delete own user.
- * @returns Message Successful Response
- * @throws ApiError
- */
- public static deleteUserMe(): CancelablePromise {
- return __request(OpenAPI, {
- method: "DELETE",
- url: "/api/v1/users/me",
- })
- }
-
- /**
- * Update User Me
- * Update own user.
- * @returns UserPublic Successful Response
- * @throws ApiError
- */
- public static updateUserMe(
- data: TDataUpdateUserMe,
- ): CancelablePromise {
- const { requestBody } = data
- return __request(OpenAPI, {
- method: "PATCH",
- url: "/api/v1/users/me",
- body: requestBody,
- mediaType: "application/json",
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Update Password Me
- * Update own password.
- * @returns Message Successful Response
- * @throws ApiError
- */
- public static updatePasswordMe(
- data: TDataUpdatePasswordMe,
- ): CancelablePromise {
- const { requestBody } = data
- return __request(OpenAPI, {
- method: "PATCH",
- url: "/api/v1/users/me/password",
- body: requestBody,
- mediaType: "application/json",
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Register User
- * Create new user without the need to be logged in.
- * @returns UserPublic Successful Response
- * @throws ApiError
- */
- public static registerUser(
- data: TDataRegisterUser,
- ): CancelablePromise {
- const { requestBody } = data
- return __request(OpenAPI, {
- method: "POST",
- url: "/api/v1/users/signup",
- body: requestBody,
- mediaType: "application/json",
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Read User By Id
- * Get a specific user by id.
- * @returns UserPublic Successful Response
- * @throws ApiError
- */
- public static readUserById(
- data: TDataReadUserById,
- ): CancelablePromise {
- const { userId } = data
- return __request(OpenAPI, {
- method: "GET",
- url: "/api/v1/users/{user_id}",
- path: {
- user_id: userId,
- },
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Update User
- * Update a user.
- * @returns UserPublic Successful Response
- * @throws ApiError
- */
- public static updateUser(
- data: TDataUpdateUser,
- ): CancelablePromise {
- const { requestBody, userId } = data
- return __request(OpenAPI, {
- method: "PATCH",
- url: "/api/v1/users/{user_id}",
- path: {
- user_id: userId,
- },
- body: requestBody,
- mediaType: "application/json",
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Delete User
- * Delete a user.
- * @returns Message Successful Response
- * @throws ApiError
- */
- public static deleteUser(data: TDataDeleteUser): CancelablePromise {
- const { userId } = data
- return __request(OpenAPI, {
- method: "DELETE",
- url: "/api/v1/users/{user_id}",
- path: {
- user_id: userId,
- },
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-}
-
-export type TDataTestEmail = {
- emailTo: string
-}
-
-export class UtilsService {
- /**
- * Test Email
- * Test emails.
- * @returns Message Successful Response
- * @throws ApiError
- */
- public static testEmail(data: TDataTestEmail): CancelablePromise {
- const { emailTo } = data
- return __request(OpenAPI, {
- method: "POST",
- url: "/api/v1/utils/test-email/",
- query: {
- email_to: emailTo,
- },
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-}
-
-export type TDataReadItems = {
- limit?: number
- skip?: number
-}
-export type TDataCreateItem = {
- requestBody: ItemCreate
-}
-export type TDataReadItem = {
- id: string
-}
-export type TDataUpdateItem = {
- id: string
- requestBody: ItemUpdate
-}
-export type TDataDeleteItem = {
- id: string
-}
-
-export class ItemsService {
- /**
- * Read Items
- * Retrieve items.
- * @returns ItemsPublic Successful Response
- * @throws ApiError
- */
- public static readItems(
- data: TDataReadItems = {},
- ): CancelablePromise {
- const { limit = 100, skip = 0 } = data
- return __request(OpenAPI, {
- method: "GET",
- url: "/api/v1/items/",
- query: {
- skip,
- limit,
- },
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Create Item
- * Create new item.
- * @returns ItemPublic Successful Response
- * @throws ApiError
- */
- public static createItem(
- data: TDataCreateItem,
- ): CancelablePromise {
- const { requestBody } = data
- return __request(OpenAPI, {
- method: "POST",
- url: "/api/v1/items/",
- body: requestBody,
- mediaType: "application/json",
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Read Item
- * Get item by ID.
- * @returns ItemPublic Successful Response
- * @throws ApiError
- */
- public static readItem(data: TDataReadItem): CancelablePromise {
- const { id } = data
- return __request(OpenAPI, {
- method: "GET",
- url: "/api/v1/items/{id}",
- path: {
- id,
- },
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Update Item
- * Update an item.
- * @returns ItemPublic Successful Response
- * @throws ApiError
- */
- public static updateItem(
- data: TDataUpdateItem,
- ): CancelablePromise {
- const { id, requestBody } = data
- return __request(OpenAPI, {
- method: "PUT",
- url: "/api/v1/items/{id}",
- path: {
- id,
- },
- body: requestBody,
- mediaType: "application/json",
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-
- /**
- * Delete Item
- * Delete an item.
- * @returns Message Successful Response
- * @throws ApiError
- */
- public static deleteItem(data: TDataDeleteItem): CancelablePromise {
- const { id } = data
- return __request(OpenAPI, {
- method: "DELETE",
- url: "/api/v1/items/{id}",
- path: {
- id,
- },
- errors: {
- 422: `Validation Error`,
- },
- })
- }
-}
diff --git a/frontend/src/components/Admin/AddUser.tsx b/frontend/src/components/Admin/AddUser.tsx
deleted file mode 100644
index a24a18a78e..0000000000
--- a/frontend/src/components/Admin/AddUser.tsx
+++ /dev/null
@@ -1,182 +0,0 @@
-import {
- Button,
- Checkbox,
- Flex,
- FormControl,
- FormErrorMessage,
- FormLabel,
- Input,
- Modal,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalFooter,
- ModalHeader,
- ModalOverlay,
-} from "@chakra-ui/react"
-import { useMutation, useQueryClient } from "@tanstack/react-query"
-import { type SubmitHandler, useForm } from "react-hook-form"
-
-import { type UserCreate, UsersService } from "../../client"
-import type { ApiError } from "../../client/core/ApiError"
-import useCustomToast from "../../hooks/useCustomToast"
-import { emailPattern, handleError } from "../../utils"
-
-interface AddUserProps {
- isOpen: boolean
- onClose: () => void
-}
-
-interface UserCreateForm extends UserCreate {
- confirm_password: string
-}
-
-const AddUser = ({ isOpen, onClose }: AddUserProps) => {
- const queryClient = useQueryClient()
- const showToast = useCustomToast()
- const {
- register,
- handleSubmit,
- reset,
- getValues,
- formState: { errors, isSubmitting },
- } = useForm({
- mode: "onBlur",
- criteriaMode: "all",
- defaultValues: {
- email: "",
- full_name: "",
- password: "",
- confirm_password: "",
- is_superuser: false,
- is_active: false,
- },
- })
-
- const mutation = useMutation({
- mutationFn: (data: UserCreate) =>
- UsersService.createUser({ requestBody: data }),
- onSuccess: () => {
- showToast("Success!", "User created successfully.", "success")
- reset()
- onClose()
- },
- onError: (err: ApiError) => {
- handleError(err, showToast)
- },
- onSettled: () => {
- queryClient.invalidateQueries({ queryKey: ["users"] })
- },
- })
-
- const onSubmit: SubmitHandler = (data) => {
- mutation.mutate(data)
- }
-
- return (
- <>
-
-
-
- Add User
-
-
-
- Email
-
- {errors.email && (
- {errors.email.message}
- )}
-
-
- Full name
-
- {errors.full_name && (
- {errors.full_name.message}
- )}
-
-
- Set Password
-
- {errors.password && (
- {errors.password.message}
- )}
-
-
- Confirm Password
-
- value === getValues().password ||
- "The passwords do not match",
- })}
- placeholder="Password"
- type="password"
- />
- {errors.confirm_password && (
-
- {errors.confirm_password.message}
-
- )}
-
-
-
-
- Is superuser?
-
-
-
-
- Is active?
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-export default AddUser
diff --git a/frontend/src/components/Admin/EditUser.tsx b/frontend/src/components/Admin/EditUser.tsx
deleted file mode 100644
index d7885ab174..0000000000
--- a/frontend/src/components/Admin/EditUser.tsx
+++ /dev/null
@@ -1,180 +0,0 @@
-import {
- Button,
- Checkbox,
- Flex,
- FormControl,
- FormErrorMessage,
- FormLabel,
- Input,
- Modal,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalFooter,
- ModalHeader,
- ModalOverlay,
-} from "@chakra-ui/react"
-import { useMutation, useQueryClient } from "@tanstack/react-query"
-import { type SubmitHandler, useForm } from "react-hook-form"
-
-import {
- type ApiError,
- type UserPublic,
- type UserUpdate,
- UsersService,
-} from "../../client"
-import useCustomToast from "../../hooks/useCustomToast"
-import { emailPattern, handleError } from "../../utils"
-
-interface EditUserProps {
- user: UserPublic
- isOpen: boolean
- onClose: () => void
-}
-
-interface UserUpdateForm extends UserUpdate {
- confirm_password: string
-}
-
-const EditUser = ({ user, isOpen, onClose }: EditUserProps) => {
- const queryClient = useQueryClient()
- const showToast = useCustomToast()
-
- const {
- register,
- handleSubmit,
- reset,
- getValues,
- formState: { errors, isSubmitting, isDirty },
- } = useForm({
- mode: "onBlur",
- criteriaMode: "all",
- defaultValues: user,
- })
-
- const mutation = useMutation({
- mutationFn: (data: UserUpdateForm) =>
- UsersService.updateUser({ userId: user.id, requestBody: data }),
- onSuccess: () => {
- showToast("Success!", "User updated successfully.", "success")
- onClose()
- },
- onError: (err: ApiError) => {
- handleError(err, showToast)
- },
- onSettled: () => {
- queryClient.invalidateQueries({ queryKey: ["users"] })
- },
- })
-
- const onSubmit: SubmitHandler = async (data) => {
- if (data.password === "") {
- data.password = undefined
- }
- mutation.mutate(data)
- }
-
- const onCancel = () => {
- reset()
- onClose()
- }
-
- return (
- <>
-
-
-
- Edit User
-
-
-
- Email
-
- {errors.email && (
- {errors.email.message}
- )}
-
-
- Full name
-
-
-
- Set Password
-
- {errors.password && (
- {errors.password.message}
- )}
-
-
- Confirm Password
-
- value === getValues().password ||
- "The passwords do not match",
- })}
- placeholder="Password"
- type="password"
- />
- {errors.confirm_password && (
-
- {errors.confirm_password.message}
-
- )}
-
-
-
-
- Is superuser?
-
-
-
-
- Is active?
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-export default EditUser
diff --git a/frontend/src/components/Common/ActionsMenu.tsx b/frontend/src/components/Common/ActionsMenu.tsx
deleted file mode 100644
index 4ff94ee3ea..0000000000
--- a/frontend/src/components/Common/ActionsMenu.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import {
- Button,
- Menu,
- MenuButton,
- MenuItem,
- MenuList,
- useDisclosure,
-} from "@chakra-ui/react"
-import { BsThreeDotsVertical } from "react-icons/bs"
-import { FiEdit, FiTrash } from "react-icons/fi"
-
-import type { ItemPublic, UserPublic } from "../../client"
-import EditUser from "../Admin/EditUser"
-import EditItem from "../Items/EditItem"
-import Delete from "./DeleteAlert"
-
-interface ActionsMenuProps {
- type: string
- value: ItemPublic | UserPublic
- disabled?: boolean
-}
-
-const ActionsMenu = ({ type, value, disabled }: ActionsMenuProps) => {
- const editUserModal = useDisclosure()
- const deleteModal = useDisclosure()
-
- return (
- <>
-
- >
- )
-}
-
-export default ActionsMenu
diff --git a/frontend/src/components/Common/DeleteAlert.tsx b/frontend/src/components/Common/DeleteAlert.tsx
deleted file mode 100644
index 1528fc5fe1..0000000000
--- a/frontend/src/components/Common/DeleteAlert.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-import {
- AlertDialog,
- AlertDialogBody,
- AlertDialogContent,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogOverlay,
- Button,
-} from "@chakra-ui/react"
-import { useMutation, useQueryClient } from "@tanstack/react-query"
-import React from "react"
-import { useForm } from "react-hook-form"
-
-import { ItemsService, UsersService } from "../../client"
-import useCustomToast from "../../hooks/useCustomToast"
-
-interface DeleteProps {
- type: string
- id: string
- isOpen: boolean
- onClose: () => void
-}
-
-const Delete = ({ type, id, isOpen, onClose }: DeleteProps) => {
- const queryClient = useQueryClient()
- const showToast = useCustomToast()
- const cancelRef = React.useRef(null)
- const {
- handleSubmit,
- formState: { isSubmitting },
- } = useForm()
-
- const deleteEntity = async (id: string) => {
- if (type === "Item") {
- await ItemsService.deleteItem({ id: id })
- } else if (type === "User") {
- await UsersService.deleteUser({ userId: id })
- } else {
- throw new Error(`Unexpected type: ${type}`)
- }
- }
-
- const mutation = useMutation({
- mutationFn: deleteEntity,
- onSuccess: () => {
- showToast(
- "Success",
- `The ${type.toLowerCase()} was deleted successfully.`,
- "success",
- )
- onClose()
- },
- onError: () => {
- showToast(
- "An error occurred.",
- `An error occurred while deleting the ${type.toLowerCase()}.`,
- "error",
- )
- },
- onSettled: () => {
- queryClient.invalidateQueries({
- queryKey: [type === "Item" ? "items" : "users"],
- })
- },
- })
-
- const onSubmit = async () => {
- mutation.mutate(id)
- }
-
- return (
- <>
-
-
-
- Delete {type}
-
-
- {type === "User" && (
-
- All items associated with this user will also be{" "}
- permantly deleted.
-
- )}
- Are you sure? You will not be able to undo this action.
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-export default Delete
diff --git a/frontend/src/components/Common/Navbar.tsx b/frontend/src/components/Common/Navbar.tsx
deleted file mode 100644
index 2aba31c362..0000000000
--- a/frontend/src/components/Common/Navbar.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import type { ComponentType, ElementType } from "react"
-
-import { Button, Flex, Icon, useDisclosure } from "@chakra-ui/react"
-import { FaPlus } from "react-icons/fa"
-
-interface NavbarProps {
- type: string
- addModalAs: ComponentType | ElementType
-}
-
-const Navbar = ({ type, addModalAs }: NavbarProps) => {
- const addModal = useDisclosure()
-
- const AddModal = addModalAs
- return (
- <>
-
- {/* TODO: Complete search functionality */}
- {/*
-
-
-
-
- */}
-
-
-
- >
- )
-}
-
-export default Navbar
diff --git a/frontend/src/components/Common/NotFound.tsx b/frontend/src/components/Common/NotFound.tsx
deleted file mode 100644
index 66ea559c01..0000000000
--- a/frontend/src/components/Common/NotFound.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { Button, Container, Text } from "@chakra-ui/react"
-import { Link } from "@tanstack/react-router"
-
-const NotFound = () => {
- return (
- <>
-
-
- 404
-
- Oops!
- Page not found.
-
-
- >
- )
-}
-
-export default NotFound
diff --git a/frontend/src/components/Common/Sidebar.tsx b/frontend/src/components/Common/Sidebar.tsx
deleted file mode 100644
index 3cc522cc57..0000000000
--- a/frontend/src/components/Common/Sidebar.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import {
- Box,
- Drawer,
- DrawerBody,
- DrawerCloseButton,
- DrawerContent,
- DrawerOverlay,
- Flex,
- IconButton,
- Image,
- Text,
- useColorModeValue,
- useDisclosure,
-} from "@chakra-ui/react"
-import { useQueryClient } from "@tanstack/react-query"
-import { FiLogOut, FiMenu } from "react-icons/fi"
-
-import Logo from "/assets/images/fastapi-logo.svg"
-import type { UserPublic } from "../../client"
-import useAuth from "../../hooks/useAuth"
-import SidebarItems from "./SidebarItems"
-
-const Sidebar = () => {
- const queryClient = useQueryClient()
- const bgColor = useColorModeValue("ui.light", "ui.dark")
- const textColor = useColorModeValue("ui.dark", "ui.light")
- const secBgColor = useColorModeValue("ui.secondary", "ui.darkSlate")
- const currentUser = queryClient.getQueryData(["currentUser"])
- const { isOpen, onOpen, onClose } = useDisclosure()
- const { logout } = useAuth()
-
- const handleLogout = async () => {
- logout()
- }
-
- return (
- <>
- {/* Mobile */}
- }
- />
-
-
-
-
-
-
-
-
-
-
-
- Log out
-
-
- {currentUser?.email && (
-
- Logged in as: {currentUser.email}
-
- )}
-
-
-
-
-
- {/* Desktop */}
-
-
-
-
-
-
- {currentUser?.email && (
-
- Logged in as: {currentUser.email}
-
- )}
-
-
- >
- )
-}
-
-export default Sidebar
diff --git a/frontend/src/components/Common/SidebarItems.tsx b/frontend/src/components/Common/SidebarItems.tsx
deleted file mode 100644
index 929e8f785e..0000000000
--- a/frontend/src/components/Common/SidebarItems.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import { Box, Flex, Icon, Text, useColorModeValue } from "@chakra-ui/react"
-import { useQueryClient } from "@tanstack/react-query"
-import { Link } from "@tanstack/react-router"
-import { FiBriefcase, FiHome, FiSettings, FiUsers } from "react-icons/fi"
-
-import type { UserPublic } from "../../client"
-
-const items = [
- { icon: FiHome, title: "Dashboard", path: "/" },
- { icon: FiBriefcase, title: "Items", path: "/items" },
- { icon: FiSettings, title: "User Settings", path: "/settings" },
-]
-
-interface SidebarItemsProps {
- onClose?: () => void
-}
-
-const SidebarItems = ({ onClose }: SidebarItemsProps) => {
- const queryClient = useQueryClient()
- const textColor = useColorModeValue("ui.main", "ui.light")
- const bgActive = useColorModeValue("#E2E8F0", "#4A5568")
- const currentUser = queryClient.getQueryData(["currentUser"])
-
- const finalItems = currentUser?.is_superuser
- ? [...items, { icon: FiUsers, title: "Admin", path: "/admin" }]
- : items
-
- const listItems = finalItems.map(({ icon, title, path }) => (
-
-
- {title}
-
- ))
-
- return (
- <>
- {listItems}
- >
- )
-}
-
-export default SidebarItems
diff --git a/frontend/src/components/Common/UserMenu.tsx b/frontend/src/components/Common/UserMenu.tsx
deleted file mode 100644
index e3d54ac26b..0000000000
--- a/frontend/src/components/Common/UserMenu.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import {
- Box,
- IconButton,
- Menu,
- MenuButton,
- MenuItem,
- MenuList,
-} from "@chakra-ui/react"
-import { Link } from "@tanstack/react-router"
-import { FaUserAstronaut } from "react-icons/fa"
-import { FiLogOut, FiUser } from "react-icons/fi"
-
-import useAuth from "../../hooks/useAuth"
-
-const UserMenu = () => {
- const { logout } = useAuth()
-
- const handleLogout = async () => {
- logout()
- }
-
- return (
- <>
- {/* Desktop */}
-
-
-
- >
- )
-}
-
-export default UserMenu
diff --git a/frontend/src/components/Items/AddItem.tsx b/frontend/src/components/Items/AddItem.tsx
deleted file mode 100644
index fa5682da3f..0000000000
--- a/frontend/src/components/Items/AddItem.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-import {
- Button,
- FormControl,
- FormErrorMessage,
- FormLabel,
- Input,
- Modal,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalFooter,
- ModalHeader,
- ModalOverlay,
-} from "@chakra-ui/react"
-import { useMutation, useQueryClient } from "@tanstack/react-query"
-import { type SubmitHandler, useForm } from "react-hook-form"
-
-import { type ApiError, type ItemCreate, ItemsService } from "../../client"
-import useCustomToast from "../../hooks/useCustomToast"
-import { handleError } from "../../utils"
-
-interface AddItemProps {
- isOpen: boolean
- onClose: () => void
-}
-
-const AddItem = ({ isOpen, onClose }: AddItemProps) => {
- const queryClient = useQueryClient()
- const showToast = useCustomToast()
- const {
- register,
- handleSubmit,
- reset,
- formState: { errors, isSubmitting },
- } = useForm({
- mode: "onBlur",
- criteriaMode: "all",
- defaultValues: {
- title: "",
- description: "",
- },
- })
-
- const mutation = useMutation({
- mutationFn: (data: ItemCreate) =>
- ItemsService.createItem({ requestBody: data }),
- onSuccess: () => {
- showToast("Success!", "Item created successfully.", "success")
- reset()
- onClose()
- },
- onError: (err: ApiError) => {
- handleError(err, showToast)
- },
- onSettled: () => {
- queryClient.invalidateQueries({ queryKey: ["items"] })
- },
- })
-
- const onSubmit: SubmitHandler = (data) => {
- mutation.mutate(data)
- }
-
- return (
- <>
-
-
-
- Add Item
-
-
-
- Title
-
- {errors.title && (
- {errors.title.message}
- )}
-
-
- Description
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-export default AddItem
diff --git a/frontend/src/components/Items/EditItem.tsx b/frontend/src/components/Items/EditItem.tsx
deleted file mode 100644
index 3d40cdc03a..0000000000
--- a/frontend/src/components/Items/EditItem.tsx
+++ /dev/null
@@ -1,124 +0,0 @@
-import {
- Button,
- FormControl,
- FormErrorMessage,
- FormLabel,
- Input,
- Modal,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalFooter,
- ModalHeader,
- ModalOverlay,
-} from "@chakra-ui/react"
-import { useMutation, useQueryClient } from "@tanstack/react-query"
-import { type SubmitHandler, useForm } from "react-hook-form"
-
-import {
- type ApiError,
- type ItemPublic,
- type ItemUpdate,
- ItemsService,
-} from "../../client"
-import useCustomToast from "../../hooks/useCustomToast"
-import { handleError } from "../../utils"
-
-interface EditItemProps {
- item: ItemPublic
- isOpen: boolean
- onClose: () => void
-}
-
-const EditItem = ({ item, isOpen, onClose }: EditItemProps) => {
- const queryClient = useQueryClient()
- const showToast = useCustomToast()
- const {
- register,
- handleSubmit,
- reset,
- formState: { isSubmitting, errors, isDirty },
- } = useForm({
- mode: "onBlur",
- criteriaMode: "all",
- defaultValues: item,
- })
-
- const mutation = useMutation({
- mutationFn: (data: ItemUpdate) =>
- ItemsService.updateItem({ id: item.id, requestBody: data }),
- onSuccess: () => {
- showToast("Success!", "Item updated successfully.", "success")
- onClose()
- },
- onError: (err: ApiError) => {
- handleError(err, showToast)
- },
- onSettled: () => {
- queryClient.invalidateQueries({ queryKey: ["items"] })
- },
- })
-
- const onSubmit: SubmitHandler = async (data) => {
- mutation.mutate(data)
- }
-
- const onCancel = () => {
- reset()
- onClose()
- }
-
- return (
- <>
-
-
-
- Edit Item
-
-
-
- Title
-
- {errors.title && (
- {errors.title.message}
- )}
-
-
- Description
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-export default EditItem
diff --git a/frontend/src/components/UserSettings/Appearance.tsx b/frontend/src/components/UserSettings/Appearance.tsx
deleted file mode 100644
index a2ab4b0a60..0000000000
--- a/frontend/src/components/UserSettings/Appearance.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import {
- Badge,
- Container,
- Heading,
- Radio,
- RadioGroup,
- Stack,
- useColorMode,
-} from "@chakra-ui/react"
-
-const Appearance = () => {
- const { colorMode, toggleColorMode } = useColorMode()
-
- return (
- <>
-
-
- Appearance
-
-
-
- {/* TODO: Add system default option */}
-
- Light Mode
-
- Default
-
-
-
- Dark Mode
-
-
-
-
- >
- )
-}
-export default Appearance
diff --git a/frontend/src/components/UserSettings/ChangePassword.tsx b/frontend/src/components/UserSettings/ChangePassword.tsx
deleted file mode 100644
index 73217939fc..0000000000
--- a/frontend/src/components/UserSettings/ChangePassword.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import {
- Box,
- Button,
- Container,
- FormControl,
- FormErrorMessage,
- FormLabel,
- Heading,
- Input,
- useColorModeValue,
-} from "@chakra-ui/react"
-import { useMutation } from "@tanstack/react-query"
-import { type SubmitHandler, useForm } from "react-hook-form"
-
-import { type ApiError, type UpdatePassword, UsersService } from "../../client"
-import useCustomToast from "../../hooks/useCustomToast"
-import { confirmPasswordRules, handleError, passwordRules } from "../../utils"
-
-interface UpdatePasswordForm extends UpdatePassword {
- confirm_password: string
-}
-
-const ChangePassword = () => {
- const color = useColorModeValue("inherit", "ui.light")
- const showToast = useCustomToast()
- const {
- register,
- handleSubmit,
- reset,
- getValues,
- formState: { errors, isSubmitting },
- } = useForm({
- mode: "onBlur",
- criteriaMode: "all",
- })
-
- const mutation = useMutation({
- mutationFn: (data: UpdatePassword) =>
- UsersService.updatePasswordMe({ requestBody: data }),
- onSuccess: () => {
- showToast("Success!", "Password updated successfully.", "success")
- reset()
- },
- onError: (err: ApiError) => {
- handleError(err, showToast)
- },
- })
-
- const onSubmit: SubmitHandler = async (data) => {
- mutation.mutate(data)
- }
-
- return (
- <>
-
-
- Change Password
-
-
-
-
- Current Password
-
-
- {errors.current_password && (
-
- {errors.current_password.message}
-
- )}
-
-
- Set Password
-
- {errors.new_password && (
- {errors.new_password.message}
- )}
-
-
- Confirm Password
-
- {errors.confirm_password && (
-
- {errors.confirm_password.message}
-
- )}
-
-
-
-
- >
- )
-}
-export default ChangePassword
diff --git a/frontend/src/components/UserSettings/DeleteAccount.tsx b/frontend/src/components/UserSettings/DeleteAccount.tsx
deleted file mode 100644
index 7ca3b92c95..0000000000
--- a/frontend/src/components/UserSettings/DeleteAccount.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import {
- Button,
- Container,
- Heading,
- Text,
- useDisclosure,
-} from "@chakra-ui/react"
-
-import DeleteConfirmation from "./DeleteConfirmation"
-
-const DeleteAccount = () => {
- const confirmationModal = useDisclosure()
-
- return (
- <>
-
-
- Delete Account
-
-
- Permanently delete your data and everything associated with your
- account.
-
-
-
-
- >
- )
-}
-export default DeleteAccount
diff --git a/frontend/src/components/UserSettings/DeleteConfirmation.tsx b/frontend/src/components/UserSettings/DeleteConfirmation.tsx
deleted file mode 100644
index 5bbdcdd6c7..0000000000
--- a/frontend/src/components/UserSettings/DeleteConfirmation.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import {
- AlertDialog,
- AlertDialogBody,
- AlertDialogContent,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogOverlay,
- Button,
-} from "@chakra-ui/react"
-import { useMutation, useQueryClient } from "@tanstack/react-query"
-import React from "react"
-import { useForm } from "react-hook-form"
-
-import { type ApiError, UsersService } from "../../client"
-import useAuth from "../../hooks/useAuth"
-import useCustomToast from "../../hooks/useCustomToast"
-import { handleError } from "../../utils"
-
-interface DeleteProps {
- isOpen: boolean
- onClose: () => void
-}
-
-const DeleteConfirmation = ({ isOpen, onClose }: DeleteProps) => {
- const queryClient = useQueryClient()
- const showToast = useCustomToast()
- const cancelRef = React.useRef(null)
- const {
- handleSubmit,
- formState: { isSubmitting },
- } = useForm()
- const { logout } = useAuth()
-
- const mutation = useMutation({
- mutationFn: () => UsersService.deleteUserMe(),
- onSuccess: () => {
- showToast(
- "Success",
- "Your account has been successfully deleted.",
- "success",
- )
- logout()
- onClose()
- },
- onError: (err: ApiError) => {
- handleError(err, showToast)
- },
- onSettled: () => {
- queryClient.invalidateQueries({ queryKey: ["currentUser"] })
- },
- })
-
- const onSubmit = async () => {
- mutation.mutate()
- }
-
- return (
- <>
-
-
-
- Confirmation Required
-
-
- All your account data will be{" "}
- permanently deleted. If you are sure, please
- click "Confirm" to proceed. This action cannot be
- undone.
-
-
-
-
-
-
-
-
-
- >
- )
-}
-
-export default DeleteConfirmation
diff --git a/frontend/src/components/UserSettings/UserInformation.tsx b/frontend/src/components/UserSettings/UserInformation.tsx
deleted file mode 100644
index d066a846a6..0000000000
--- a/frontend/src/components/UserSettings/UserInformation.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-import {
- Box,
- Button,
- Container,
- Flex,
- FormControl,
- FormErrorMessage,
- FormLabel,
- Heading,
- Input,
- Text,
- useColorModeValue,
-} from "@chakra-ui/react"
-import { useMutation, useQueryClient } from "@tanstack/react-query"
-import { useState } from "react"
-import { type SubmitHandler, useForm } from "react-hook-form"
-
-import {
- type ApiError,
- type UserPublic,
- type UserUpdateMe,
- UsersService,
-} from "../../client"
-import useAuth from "../../hooks/useAuth"
-import useCustomToast from "../../hooks/useCustomToast"
-import { emailPattern, handleError } from "../../utils"
-
-const UserInformation = () => {
- const queryClient = useQueryClient()
- const color = useColorModeValue("inherit", "ui.light")
- const showToast = useCustomToast()
- const [editMode, setEditMode] = useState(false)
- const { user: currentUser } = useAuth()
- const {
- register,
- handleSubmit,
- reset,
- getValues,
- formState: { isSubmitting, errors, isDirty },
- } = useForm({
- mode: "onBlur",
- criteriaMode: "all",
- defaultValues: {
- full_name: currentUser?.full_name,
- email: currentUser?.email,
- },
- })
-
- const toggleEditMode = () => {
- setEditMode(!editMode)
- }
-
- const mutation = useMutation({
- mutationFn: (data: UserUpdateMe) =>
- UsersService.updateUserMe({ requestBody: data }),
- onSuccess: () => {
- showToast("Success!", "User updated successfully.", "success")
- },
- onError: (err: ApiError) => {
- handleError(err, showToast)
- },
- onSettled: () => {
- queryClient.invalidateQueries()
- },
- })
-
- const onSubmit: SubmitHandler = async (data) => {
- mutation.mutate(data)
- }
-
- const onCancel = () => {
- reset()
- toggleEditMode()
- }
-
- return (
- <>
-
-
- User Information
-
-
-
-
- Full name
-
- {editMode ? (
-
- ) : (
-
- {currentUser?.full_name || "N/A"}
-
- )}
-
-
-
- Email
-
- {editMode ? (
-
- ) : (
-
- {currentUser?.email}
-
- )}
- {errors.email && (
- {errors.email.message}
- )}
-
-
-
- {editMode && (
-
- )}
-
-
-
- >
- )
-}
-
-export default UserInformation
diff --git a/frontend/src/hooks/useAuth.ts b/frontend/src/hooks/useAuth.ts
deleted file mode 100644
index 76b0abdfd3..0000000000
--- a/frontend/src/hooks/useAuth.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
-import { useNavigate } from "@tanstack/react-router"
-import { useState } from "react"
-
-import { AxiosError } from "axios"
-import {
- type Body_login_login_access_token as AccessToken,
- type ApiError,
- LoginService,
- type UserPublic,
- type UserRegister,
- UsersService,
-} from "../client"
-import useCustomToast from "./useCustomToast"
-
-const isLoggedIn = () => {
- return localStorage.getItem("access_token") !== null
-}
-
-const useAuth = () => {
- const [error, setError] = useState(null)
- const navigate = useNavigate()
- const showToast = useCustomToast()
- const queryClient = useQueryClient()
- const { data: user, isLoading } = useQuery({
- queryKey: ["currentUser"],
- queryFn: UsersService.readUserMe,
- enabled: isLoggedIn(),
- })
-
- const signUpMutation = useMutation({
- mutationFn: (data: UserRegister) =>
- UsersService.registerUser({ requestBody: data }),
-
- onSuccess: () => {
- navigate({ to: "/login" })
- showToast(
- "Account created.",
- "Your account has been created successfully.",
- "success",
- )
- },
- onError: (err: ApiError) => {
- let errDetail = (err.body as any)?.detail
-
- if (err instanceof AxiosError) {
- errDetail = err.message
- }
-
- showToast("Something went wrong.", errDetail, "error")
- },
- onSettled: () => {
- queryClient.invalidateQueries({ queryKey: ["users"] })
- },
- })
-
- const login = async (data: AccessToken) => {
- const response = await LoginService.loginAccessToken({
- formData: data,
- })
- localStorage.setItem("access_token", response.access_token)
- }
-
- const loginMutation = useMutation({
- mutationFn: login,
- onSuccess: () => {
- navigate({ to: "/" })
- },
- onError: (err: ApiError) => {
- let errDetail = (err.body as any)?.detail
-
- if (err instanceof AxiosError) {
- errDetail = err.message
- }
-
- if (Array.isArray(errDetail)) {
- errDetail = "Something went wrong"
- }
-
- setError(errDetail)
- },
- })
-
- const logout = () => {
- localStorage.removeItem("access_token")
- navigate({ to: "/login" })
- }
-
- return {
- signUpMutation,
- loginMutation,
- logout,
- user,
- isLoading,
- error,
- resetError: () => setError(null),
- }
-}
-
-export { isLoggedIn }
-export default useAuth
diff --git a/frontend/src/hooks/useCustomToast.ts b/frontend/src/hooks/useCustomToast.ts
deleted file mode 100644
index 06bc8a6ab8..0000000000
--- a/frontend/src/hooks/useCustomToast.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { useToast } from "@chakra-ui/react"
-import { useCallback } from "react"
-
-const useCustomToast = () => {
- const toast = useToast()
-
- const showToast = useCallback(
- (title: string, description: string, status: "success" | "error") => {
- toast({
- title,
- description,
- status,
- isClosable: true,
- position: "bottom-right",
- })
- },
- [toast],
- )
-
- return showToast
-}
-
-export default useCustomToast
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx
deleted file mode 100644
index afc904538b..0000000000
--- a/frontend/src/main.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { ChakraProvider } from "@chakra-ui/react"
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
-import { RouterProvider, createRouter } from "@tanstack/react-router"
-import ReactDOM from "react-dom/client"
-import { routeTree } from "./routeTree.gen"
-
-import { StrictMode } from "react"
-import { OpenAPI } from "./client"
-import theme from "./theme"
-
-OpenAPI.BASE = import.meta.env.VITE_API_URL
-OpenAPI.TOKEN = async () => {
- return localStorage.getItem("access_token") || ""
-}
-
-const queryClient = new QueryClient()
-
-const router = createRouter({ routeTree })
-declare module "@tanstack/react-router" {
- interface Register {
- router: typeof router
- }
-}
-
-ReactDOM.createRoot(document.getElementById("root")!).render(
-
-
-
-
-
-
- ,
-)
diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts
deleted file mode 100644
index 0e78c9ba20..0000000000
--- a/frontend/src/routeTree.gen.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-/* prettier-ignore-start */
-
-/* eslint-disable */
-
-// @ts-nocheck
-
-// noinspection JSUnusedGlobalSymbols
-
-// This file is auto-generated by TanStack Router
-
-// Import Routes
-
-import { Route as rootRoute } from './routes/__root'
-import { Route as SignupImport } from './routes/signup'
-import { Route as ResetPasswordImport } from './routes/reset-password'
-import { Route as RecoverPasswordImport } from './routes/recover-password'
-import { Route as LoginImport } from './routes/login'
-import { Route as LayoutImport } from './routes/_layout'
-import { Route as LayoutIndexImport } from './routes/_layout/index'
-import { Route as LayoutSettingsImport } from './routes/_layout/settings'
-import { Route as LayoutItemsImport } from './routes/_layout/items'
-import { Route as LayoutAdminImport } from './routes/_layout/admin'
-
-// Create/Update Routes
-
-const SignupRoute = SignupImport.update({
- path: '/signup',
- getParentRoute: () => rootRoute,
-} as any)
-
-const ResetPasswordRoute = ResetPasswordImport.update({
- path: '/reset-password',
- getParentRoute: () => rootRoute,
-} as any)
-
-const RecoverPasswordRoute = RecoverPasswordImport.update({
- path: '/recover-password',
- getParentRoute: () => rootRoute,
-} as any)
-
-const LoginRoute = LoginImport.update({
- path: '/login',
- getParentRoute: () => rootRoute,
-} as any)
-
-const LayoutRoute = LayoutImport.update({
- id: '/_layout',
- getParentRoute: () => rootRoute,
-} as any)
-
-const LayoutIndexRoute = LayoutIndexImport.update({
- path: '/',
- getParentRoute: () => LayoutRoute,
-} as any)
-
-const LayoutSettingsRoute = LayoutSettingsImport.update({
- path: '/settings',
- getParentRoute: () => LayoutRoute,
-} as any)
-
-const LayoutItemsRoute = LayoutItemsImport.update({
- path: '/items',
- getParentRoute: () => LayoutRoute,
-} as any)
-
-const LayoutAdminRoute = LayoutAdminImport.update({
- path: '/admin',
- getParentRoute: () => LayoutRoute,
-} as any)
-
-// Populate the FileRoutesByPath interface
-
-declare module '@tanstack/react-router' {
- interface FileRoutesByPath {
- '/_layout': {
- preLoaderRoute: typeof LayoutImport
- parentRoute: typeof rootRoute
- }
- '/login': {
- preLoaderRoute: typeof LoginImport
- parentRoute: typeof rootRoute
- }
- '/recover-password': {
- preLoaderRoute: typeof RecoverPasswordImport
- parentRoute: typeof rootRoute
- }
- '/reset-password': {
- preLoaderRoute: typeof ResetPasswordImport
- parentRoute: typeof rootRoute
- }
- '/signup': {
- preLoaderRoute: typeof SignupImport
- parentRoute: typeof rootRoute
- }
- '/_layout/admin': {
- preLoaderRoute: typeof LayoutAdminImport
- parentRoute: typeof LayoutImport
- }
- '/_layout/items': {
- preLoaderRoute: typeof LayoutItemsImport
- parentRoute: typeof LayoutImport
- }
- '/_layout/settings': {
- preLoaderRoute: typeof LayoutSettingsImport
- parentRoute: typeof LayoutImport
- }
- '/_layout/': {
- preLoaderRoute: typeof LayoutIndexImport
- parentRoute: typeof LayoutImport
- }
- }
-}
-
-// Create and export the route tree
-
-export const routeTree = rootRoute.addChildren([
- LayoutRoute.addChildren([
- LayoutAdminRoute,
- LayoutItemsRoute,
- LayoutSettingsRoute,
- LayoutIndexRoute,
- ]),
- LoginRoute,
- RecoverPasswordRoute,
- ResetPasswordRoute,
- SignupRoute,
-])
-
-/* prettier-ignore-end */
diff --git a/frontend/src/routes/__root.tsx b/frontend/src/routes/__root.tsx
deleted file mode 100644
index 5da6383f2a..0000000000
--- a/frontend/src/routes/__root.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Outlet, createRootRoute } from "@tanstack/react-router"
-import React, { Suspense } from "react"
-
-import NotFound from "../components/Common/NotFound"
-
-const loadDevtools = () =>
- Promise.all([
- import("@tanstack/router-devtools"),
- import("@tanstack/react-query-devtools"),
- ]).then(([routerDevtools, reactQueryDevtools]) => {
- return {
- default: () => (
- <>
-
-
- >
- ),
- }
- })
-
-const TanStackDevtools =
- process.env.NODE_ENV === "production" ? () => null : React.lazy(loadDevtools)
-
-export const Route = createRootRoute({
- component: () => (
- <>
-
-
-
-
- >
- ),
- notFoundComponent: () => ,
-})
diff --git a/frontend/src/routes/_layout.tsx b/frontend/src/routes/_layout.tsx
deleted file mode 100644
index 9a6cfa3b81..0000000000
--- a/frontend/src/routes/_layout.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { Flex, Spinner } from "@chakra-ui/react"
-import { Outlet, createFileRoute, redirect } from "@tanstack/react-router"
-
-import Sidebar from "../components/Common/Sidebar"
-import UserMenu from "../components/Common/UserMenu"
-import useAuth, { isLoggedIn } from "../hooks/useAuth"
-
-export const Route = createFileRoute("/_layout")({
- component: Layout,
- beforeLoad: async () => {
- if (!isLoggedIn()) {
- throw redirect({
- to: "/login",
- })
- }
- },
-})
-
-function Layout() {
- const { isLoading } = useAuth()
-
- return (
-
-
- {isLoading ? (
-
-
-
- ) : (
-
- )}
-
-
- )
-}
diff --git a/frontend/src/routes/_layout/admin.tsx b/frontend/src/routes/_layout/admin.tsx
deleted file mode 100644
index 644653ff79..0000000000
--- a/frontend/src/routes/_layout/admin.tsx
+++ /dev/null
@@ -1,170 +0,0 @@
-import {
- Badge,
- Box,
- Button,
- Container,
- Flex,
- Heading,
- SkeletonText,
- Table,
- TableContainer,
- Tbody,
- Td,
- Th,
- Thead,
- Tr,
-} from "@chakra-ui/react"
-import { useQuery, useQueryClient } from "@tanstack/react-query"
-import { createFileRoute, useNavigate } from "@tanstack/react-router"
-import { useEffect } from "react"
-import { z } from "zod"
-
-import { type UserPublic, UsersService } from "../../client"
-import AddUser from "../../components/Admin/AddUser"
-import ActionsMenu from "../../components/Common/ActionsMenu"
-import Navbar from "../../components/Common/Navbar"
-
-const usersSearchSchema = z.object({
- page: z.number().catch(1),
-})
-
-export const Route = createFileRoute("/_layout/admin")({
- component: Admin,
- validateSearch: (search) => usersSearchSchema.parse(search),
-})
-
-const PER_PAGE = 5
-
-function getUsersQueryOptions({ page }: { page: number }) {
- return {
- queryFn: () =>
- UsersService.readUsers({ skip: (page - 1) * PER_PAGE, limit: PER_PAGE }),
- queryKey: ["users", { page }],
- }
-}
-
-function UsersTable() {
- const queryClient = useQueryClient()
- const currentUser = queryClient.getQueryData(["currentUser"])
- const { page } = Route.useSearch()
- const navigate = useNavigate({ from: Route.fullPath })
- const setPage = (page: number) =>
- navigate({ search: (prev) => ({ ...prev, page }) })
-
- const {
- data: users,
- isPending,
- isPlaceholderData,
- } = useQuery({
- ...getUsersQueryOptions({ page }),
- placeholderData: (prevData) => prevData,
- })
-
- const hasNextPage = !isPlaceholderData && users?.data.length === PER_PAGE
- const hasPreviousPage = page > 1
-
- useEffect(() => {
- if (hasNextPage) {
- queryClient.prefetchQuery(getUsersQueryOptions({ page: page + 1 }))
- }
- }, [page, queryClient, hasNextPage])
-
- return (
- <>
-
-
-
-
- Full name |
- Email |
- Role |
- Status |
- Actions |
-
-
- {isPending ? (
-
-
- {new Array(4).fill(null).map((_, index) => (
-
-
- |
- ))}
-
-
- ) : (
-
- {users?.data.map((user) => (
-
-
- {user.full_name || "N/A"}
- {currentUser?.id === user.id && (
-
- You
-
- )}
- |
-
- {user.email}
- |
- {user.is_superuser ? "Superuser" : "User"} |
-
-
-
- {user.is_active ? "Active" : "Inactive"}
-
- |
-
-
- |
-
- ))}
-
- )}
-
-
-
-
- Page {page}
-
-
- >
- )
-}
-
-function Admin() {
- return (
-
-
- Users Management
-
-
-
-
-
- )
-}
diff --git a/frontend/src/routes/_layout/index.tsx b/frontend/src/routes/_layout/index.tsx
deleted file mode 100644
index 80cc934083..0000000000
--- a/frontend/src/routes/_layout/index.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Box, Container, Text } from "@chakra-ui/react"
-import { createFileRoute } from "@tanstack/react-router"
-
-import useAuth from "../../hooks/useAuth"
-
-export const Route = createFileRoute("/_layout/")({
- component: Dashboard,
-})
-
-function Dashboard() {
- const { user: currentUser } = useAuth()
-
- return (
- <>
-
-
-
- Hi, {currentUser?.full_name || currentUser?.email} 👋🏼
-
- Welcome back, nice to see you again!
-
-
- >
- )
-}
diff --git a/frontend/src/routes/_layout/items.tsx b/frontend/src/routes/_layout/items.tsx
deleted file mode 100644
index 174fa83c9b..0000000000
--- a/frontend/src/routes/_layout/items.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-import {
- Button,
- Container,
- Flex,
- Heading,
- SkeletonText,
- Table,
- TableContainer,
- Tbody,
- Td,
- Th,
- Thead,
- Tr,
-} from "@chakra-ui/react"
-import { useQuery, useQueryClient } from "@tanstack/react-query"
-import { createFileRoute, useNavigate } from "@tanstack/react-router"
-import { useEffect } from "react"
-import { z } from "zod"
-
-import { ItemsService } from "../../client"
-import ActionsMenu from "../../components/Common/ActionsMenu"
-import Navbar from "../../components/Common/Navbar"
-import AddItem from "../../components/Items/AddItem"
-
-const itemsSearchSchema = z.object({
- page: z.number().catch(1),
-})
-
-export const Route = createFileRoute("/_layout/items")({
- component: Items,
- validateSearch: (search) => itemsSearchSchema.parse(search),
-})
-
-const PER_PAGE = 5
-
-function getItemsQueryOptions({ page }: { page: number }) {
- return {
- queryFn: () =>
- ItemsService.readItems({ skip: (page - 1) * PER_PAGE, limit: PER_PAGE }),
- queryKey: ["items", { page }],
- }
-}
-
-function ItemsTable() {
- const queryClient = useQueryClient()
- const { page } = Route.useSearch()
- const navigate = useNavigate({ from: Route.fullPath })
- const setPage = (page: number) =>
- navigate({ search: (prev) => ({ ...prev, page }) })
-
- const {
- data: items,
- isPending,
- isPlaceholderData,
- } = useQuery({
- ...getItemsQueryOptions({ page }),
- placeholderData: (prevData) => prevData,
- })
-
- const hasNextPage = !isPlaceholderData && items?.data.length === PER_PAGE
- const hasPreviousPage = page > 1
-
- useEffect(() => {
- if (hasNextPage) {
- queryClient.prefetchQuery(getItemsQueryOptions({ page: page + 1 }))
- }
- }, [page, queryClient, hasNextPage])
-
- return (
- <>
-
-
-
-
- ID |
- Title |
- Description |
- Actions |
-
-
- {isPending ? (
-
-
- {new Array(4).fill(null).map((_, index) => (
-
-
- |
- ))}
-
-
- ) : (
-
- {items?.data.map((item) => (
-
- {item.id} |
-
- {item.title}
- |
-
- {item.description || "N/A"}
- |
-
-
- |
-
- ))}
-
- )}
-
-
-
-
- Page {page}
-
-
- >
- )
-}
-
-function Items() {
- return (
-
-
- Items Management
-
-
-
-
-
- )
-}
diff --git a/frontend/src/routes/_layout/settings.tsx b/frontend/src/routes/_layout/settings.tsx
deleted file mode 100644
index 68266c6b9a..0000000000
--- a/frontend/src/routes/_layout/settings.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import {
- Container,
- Heading,
- Tab,
- TabList,
- TabPanel,
- TabPanels,
- Tabs,
-} from "@chakra-ui/react"
-import { useQueryClient } from "@tanstack/react-query"
-import { createFileRoute } from "@tanstack/react-router"
-
-import type { UserPublic } from "../../client"
-import Appearance from "../../components/UserSettings/Appearance"
-import ChangePassword from "../../components/UserSettings/ChangePassword"
-import DeleteAccount from "../../components/UserSettings/DeleteAccount"
-import UserInformation from "../../components/UserSettings/UserInformation"
-
-const tabsConfig = [
- { title: "My profile", component: UserInformation },
- { title: "Password", component: ChangePassword },
- { title: "Appearance", component: Appearance },
- { title: "Danger zone", component: DeleteAccount },
-]
-
-export const Route = createFileRoute("/_layout/settings")({
- component: UserSettings,
-})
-
-function UserSettings() {
- const queryClient = useQueryClient()
- const currentUser = queryClient.getQueryData(["currentUser"])
- const finalTabs = currentUser?.is_superuser
- ? tabsConfig.slice(0, 3)
- : tabsConfig
-
- return (
-
-
- User Settings
-
-
-
- {finalTabs.map((tab, index) => (
- {tab.title}
- ))}
-
-
- {finalTabs.map((tab, index) => (
-
-
-
- ))}
-
-
-
- )
-}
diff --git a/frontend/src/routes/login.tsx b/frontend/src/routes/login.tsx
deleted file mode 100644
index 20a9be6564..0000000000
--- a/frontend/src/routes/login.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-import { ViewIcon, ViewOffIcon } from "@chakra-ui/icons"
-import {
- Button,
- Container,
- FormControl,
- FormErrorMessage,
- Icon,
- Image,
- Input,
- InputGroup,
- InputRightElement,
- Link,
- Text,
- useBoolean,
-} from "@chakra-ui/react"
-import {
- Link as RouterLink,
- createFileRoute,
- redirect,
-} from "@tanstack/react-router"
-import { type SubmitHandler, useForm } from "react-hook-form"
-
-import Logo from "/assets/images/fastapi-logo.svg"
-import type { Body_login_login_access_token as AccessToken } from "../client"
-import useAuth, { isLoggedIn } from "../hooks/useAuth"
-import { emailPattern } from "../utils"
-
-export const Route = createFileRoute("/login")({
- component: Login,
- beforeLoad: async () => {
- if (isLoggedIn()) {
- throw redirect({
- to: "/",
- })
- }
- },
-})
-
-function Login() {
- const [show, setShow] = useBoolean()
- const { loginMutation, error, resetError } = useAuth()
- const {
- register,
- handleSubmit,
- formState: { errors, isSubmitting },
- } = useForm({
- mode: "onBlur",
- criteriaMode: "all",
- defaultValues: {
- username: "",
- password: "",
- },
- })
-
- const onSubmit: SubmitHandler = async (data) => {
- if (isSubmitting) return
-
- resetError()
-
- try {
- await loginMutation.mutateAsync(data)
- } catch {
- // error is handled by useAuth hook
- }
- }
-
- return (
- <>
-
-
-
-
- {errors.username && (
- {errors.username.message}
- )}
-
-
-
-
-
-
- {show ? : }
-
-
-
- {error && {error}}
-
-
- Forgot password?
-
-
-
- Don't have an account?{" "}
-
- Sign up
-
-
-
- >
- )
-}
diff --git a/frontend/src/routes/recover-password.tsx b/frontend/src/routes/recover-password.tsx
deleted file mode 100644
index 5716728bbb..0000000000
--- a/frontend/src/routes/recover-password.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import {
- Button,
- Container,
- FormControl,
- FormErrorMessage,
- Heading,
- Input,
- Text,
-} from "@chakra-ui/react"
-import { useMutation } from "@tanstack/react-query"
-import { createFileRoute, redirect } from "@tanstack/react-router"
-import { type SubmitHandler, useForm } from "react-hook-form"
-
-import { type ApiError, LoginService } from "../client"
-import { isLoggedIn } from "../hooks/useAuth"
-import useCustomToast from "../hooks/useCustomToast"
-import { emailPattern, handleError } from "../utils"
-
-interface FormData {
- email: string
-}
-
-export const Route = createFileRoute("/recover-password")({
- component: RecoverPassword,
- beforeLoad: async () => {
- if (isLoggedIn()) {
- throw redirect({
- to: "/",
- })
- }
- },
-})
-
-function RecoverPassword() {
- const {
- register,
- handleSubmit,
- reset,
- formState: { errors, isSubmitting },
- } = useForm()
- const showToast = useCustomToast()
-
- const recoverPassword = async (data: FormData) => {
- await LoginService.recoverPassword({
- email: data.email,
- })
- }
-
- const mutation = useMutation({
- mutationFn: recoverPassword,
- onSuccess: () => {
- showToast(
- "Email sent.",
- "We sent an email with a link to get back into your account.",
- "success",
- )
- reset()
- },
- onError: (err: ApiError) => {
- handleError(err, showToast)
- },
- })
-
- const onSubmit: SubmitHandler = async (data) => {
- mutation.mutate(data)
- }
-
- return (
-
-
- Password Recovery
-
-
- A password recovery email will be sent to the registered account.
-
-
-
- {errors.email && (
- {errors.email.message}
- )}
-
-
-
- )
-}
diff --git a/frontend/src/routes/reset-password.tsx b/frontend/src/routes/reset-password.tsx
deleted file mode 100644
index f5ee763a3e..0000000000
--- a/frontend/src/routes/reset-password.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import {
- Button,
- Container,
- FormControl,
- FormErrorMessage,
- FormLabel,
- Heading,
- Input,
- Text,
-} from "@chakra-ui/react"
-import { useMutation } from "@tanstack/react-query"
-import { createFileRoute, redirect, useNavigate } from "@tanstack/react-router"
-import { type SubmitHandler, useForm } from "react-hook-form"
-
-import { type ApiError, LoginService, type NewPassword } from "../client"
-import { isLoggedIn } from "../hooks/useAuth"
-import useCustomToast from "../hooks/useCustomToast"
-import { confirmPasswordRules, handleError, passwordRules } from "../utils"
-
-interface NewPasswordForm extends NewPassword {
- confirm_password: string
-}
-
-export const Route = createFileRoute("/reset-password")({
- component: ResetPassword,
- beforeLoad: async () => {
- if (isLoggedIn()) {
- throw redirect({
- to: "/",
- })
- }
- },
-})
-
-function ResetPassword() {
- const {
- register,
- handleSubmit,
- getValues,
- reset,
- formState: { errors },
- } = useForm({
- mode: "onBlur",
- criteriaMode: "all",
- defaultValues: {
- new_password: "",
- },
- })
- const showToast = useCustomToast()
- const navigate = useNavigate()
-
- const resetPassword = async (data: NewPassword) => {
- const token = new URLSearchParams(window.location.search).get("token")
- if (!token) return
- await LoginService.resetPassword({
- requestBody: { new_password: data.new_password, token: token },
- })
- }
-
- const mutation = useMutation({
- mutationFn: resetPassword,
- onSuccess: () => {
- showToast("Success!", "Password updated successfully.", "success")
- reset()
- navigate({ to: "/login" })
- },
- onError: (err: ApiError) => {
- handleError(err, showToast)
- },
- })
-
- const onSubmit: SubmitHandler = async (data) => {
- mutation.mutate(data)
- }
-
- return (
-
-
- Reset Password
-
-
- Please enter your new password and confirm it to reset your password.
-
-
- Set Password
-
- {errors.new_password && (
- {errors.new_password.message}
- )}
-
-
- Confirm Password
-
- {errors.confirm_password && (
- {errors.confirm_password.message}
- )}
-
-
-
- )
-}
diff --git a/frontend/src/routes/signup.tsx b/frontend/src/routes/signup.tsx
deleted file mode 100644
index b021e73698..0000000000
--- a/frontend/src/routes/signup.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-import {
- Button,
- Container,
- Flex,
- FormControl,
- FormErrorMessage,
- FormLabel,
- Image,
- Input,
- Link,
- Text,
-} from "@chakra-ui/react"
-import {
- Link as RouterLink,
- createFileRoute,
- redirect,
-} from "@tanstack/react-router"
-import { type SubmitHandler, useForm } from "react-hook-form"
-
-import Logo from "/assets/images/fastapi-logo.svg"
-import type { UserRegister } from "../client"
-import useAuth, { isLoggedIn } from "../hooks/useAuth"
-import { confirmPasswordRules, emailPattern, passwordRules } from "../utils"
-
-export const Route = createFileRoute("/signup")({
- component: SignUp,
- beforeLoad: async () => {
- if (isLoggedIn()) {
- throw redirect({
- to: "/",
- })
- }
- },
-})
-
-interface UserRegisterForm extends UserRegister {
- confirm_password: string
-}
-
-function SignUp() {
- const { signUpMutation } = useAuth()
- const {
- register,
- handleSubmit,
- getValues,
- formState: { errors, isSubmitting },
- } = useForm({
- mode: "onBlur",
- criteriaMode: "all",
- defaultValues: {
- email: "",
- full_name: "",
- password: "",
- confirm_password: "",
- },
- })
-
- const onSubmit: SubmitHandler = (data) => {
- signUpMutation.mutate(data)
- }
-
- return (
- <>
-
-
-
-
-
- Full Name
-
-
- {errors.full_name && (
- {errors.full_name.message}
- )}
-
-
-
- Email
-
-
- {errors.email && (
- {errors.email.message}
- )}
-
-
-
- Password
-
-
- {errors.password && (
- {errors.password.message}
- )}
-
-
-
- Confirm Password
-
-
-
- {errors.confirm_password && (
-
- {errors.confirm_password.message}
-
- )}
-
-
-
- Already have an account?{" "}
-
- Log In
-
-
-
-
- >
- )
-}
-
-export default SignUp
diff --git a/frontend/src/theme.tsx b/frontend/src/theme.tsx
deleted file mode 100644
index 71675dddca..0000000000
--- a/frontend/src/theme.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import { extendTheme } from "@chakra-ui/react"
-
-const disabledStyles = {
- _disabled: {
- backgroundColor: "ui.main",
- },
-}
-
-const theme = extendTheme({
- colors: {
- ui: {
- main: "#009688",
- secondary: "#EDF2F7",
- success: "#48BB78",
- danger: "#E53E3E",
- light: "#FAFAFA",
- dark: "#1A202C",
- darkSlate: "#252D3D",
- dim: "#A0AEC0",
- },
- },
- components: {
- Button: {
- variants: {
- primary: {
- backgroundColor: "ui.main",
- color: "ui.light",
- _hover: {
- backgroundColor: "#00766C",
- },
- _disabled: {
- ...disabledStyles,
- _hover: {
- ...disabledStyles,
- },
- },
- },
- danger: {
- backgroundColor: "ui.danger",
- color: "ui.light",
- _hover: {
- backgroundColor: "#E32727",
- },
- },
- },
- },
- Tabs: {
- variants: {
- enclosed: {
- tab: {
- _selected: {
- color: "ui.main",
- },
- },
- },
- },
- },
- },
-})
-
-export default theme
diff --git a/frontend/src/utils.ts b/frontend/src/utils.ts
deleted file mode 100644
index 99f906303c..0000000000
--- a/frontend/src/utils.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import type { ApiError } from "./client"
-
-export const emailPattern = {
- value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
- message: "Invalid email address",
-}
-
-export const namePattern = {
- value: /^[A-Za-z\s\u00C0-\u017F]{1,30}$/,
- message: "Invalid name",
-}
-
-export const passwordRules = (isRequired = true) => {
- const rules: any = {
- minLength: {
- value: 8,
- message: "Password must be at least 8 characters",
- },
- }
-
- if (isRequired) {
- rules.required = "Password is required"
- }
-
- return rules
-}
-
-export const confirmPasswordRules = (
- getValues: () => any,
- isRequired = true,
-) => {
- const rules: any = {
- validate: (value: string) => {
- const password = getValues().password || getValues().new_password
- return value === password ? true : "The passwords do not match"
- },
- }
-
- if (isRequired) {
- rules.required = "Password confirmation is required"
- }
-
- return rules
-}
-
-export const handleError = (err: ApiError, showToast: any) => {
- const errDetail = (err.body as any)?.detail
- let errorMessage = errDetail || "Something went wrong."
- if (Array.isArray(errDetail) && errDetail.length > 0) {
- errorMessage = errDetail[0].msg
- }
- showToast("Error", errorMessage, "error")
-}
diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts
deleted file mode 100644
index 11f02fe2a0..0000000000
--- a/frontend/src/vite-env.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-///
diff --git a/frontend/tests/auth.setup.ts b/frontend/tests/auth.setup.ts
deleted file mode 100644
index 3882f4f810..0000000000
--- a/frontend/tests/auth.setup.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { test as setup } from "@playwright/test"
-import { firstSuperuser, firstSuperuserPassword } from "./config.ts"
-
-const authFile = "playwright/.auth/user.json"
-
-setup("authenticate", async ({ page }) => {
- await page.goto("/login")
- await page.getByPlaceholder("Email").fill(firstSuperuser)
- await page.getByPlaceholder("Password").fill(firstSuperuserPassword)
- await page.getByRole("button", { name: "Log In" }).click()
- await page.waitForURL("/")
- await page.context().storageState({ path: authFile })
-})
diff --git a/frontend/tests/config.ts b/frontend/tests/config.ts
deleted file mode 100644
index 188cb367e3..0000000000
--- a/frontend/tests/config.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import path from "node:path"
-import { fileURLToPath } from "node:url"
-import dotenv from "dotenv"
-
-const __filename = fileURLToPath(import.meta.url)
-const __dirname = path.dirname(__filename)
-
-dotenv.config({ path: path.join(__dirname, "../../.env") })
-
-const { FIRST_SUPERUSER, FIRST_SUPERUSER_PASSWORD } = process.env
-
-if (typeof FIRST_SUPERUSER !== "string") {
- throw new Error("Environment variable FIRST_SUPERUSER is undefined")
-}
-
-if (typeof FIRST_SUPERUSER_PASSWORD !== "string") {
- throw new Error("Environment variable FIRST_SUPERUSER_PASSWORD is undefined")
-}
-
-export const firstSuperuser = FIRST_SUPERUSER as string
-export const firstSuperuserPassword = FIRST_SUPERUSER_PASSWORD as string
diff --git a/frontend/tests/login.spec.ts b/frontend/tests/login.spec.ts
deleted file mode 100644
index 97c2284f40..0000000000
--- a/frontend/tests/login.spec.ts
+++ /dev/null
@@ -1,117 +0,0 @@
-import { type Page, expect, test } from "@playwright/test"
-import { firstSuperuser, firstSuperuserPassword } from "./config.ts"
-import { randomPassword } from "./utils/random.ts"
-
-test.use({ storageState: { cookies: [], origins: [] } })
-
-type OptionsType = {
- exact?: boolean
-}
-
-const fillForm = async (page: Page, email: string, password: string) => {
- await page.getByPlaceholder("Email").fill(email)
- await page.getByPlaceholder("Password", { exact: true }).fill(password)
-}
-
-const verifyInput = async (
- page: Page,
- placeholder: string,
- options?: OptionsType,
-) => {
- const input = page.getByPlaceholder(placeholder, options)
- await expect(input).toBeVisible()
- await expect(input).toHaveText("")
- await expect(input).toBeEditable()
-}
-
-test("Inputs are visible, empty and editable", async ({ page }) => {
- await page.goto("/login")
-
- await verifyInput(page, "Email")
- await verifyInput(page, "Password", { exact: true })
-})
-
-test("Log In button is visible", async ({ page }) => {
- await page.goto("/login")
-
- await expect(page.getByRole("button", { name: "Log In" })).toBeVisible()
-})
-
-test("Forgot Password link is visible", async ({ page }) => {
- await page.goto("/login")
-
- await expect(
- page.getByRole("link", { name: "Forgot password?" }),
- ).toBeVisible()
-})
-
-test("Log in with valid email and password ", async ({ page }) => {
- await page.goto("/login")
-
- await fillForm(page, firstSuperuser, firstSuperuserPassword)
- await page.getByRole("button", { name: "Log In" }).click()
-
- await page.waitForURL("/")
-
- await expect(
- page.getByText("Welcome back, nice to see you again!"),
- ).toBeVisible()
-})
-
-test("Log in with invalid email", async ({ page }) => {
- await page.goto("/login")
-
- await fillForm(page, "invalidemail", firstSuperuserPassword)
- await page.getByRole("button", { name: "Log In" }).click()
-
- await expect(page.getByText("Invalid email address")).toBeVisible()
-})
-
-test("Log in with invalid password", async ({ page }) => {
- const password = randomPassword()
-
- await page.goto("/login")
- await fillForm(page, firstSuperuser, password)
- await page.getByRole("button", { name: "Log In" }).click()
-
- await expect(page.getByText("Incorrect email or password")).toBeVisible()
-})
-
-// Log out
-
-test("Successful log out", async ({ page }) => {
- await page.goto("/login")
-
- await fillForm(page, firstSuperuser, firstSuperuserPassword)
- await page.getByRole("button", { name: "Log In" }).click()
-
- await page.waitForURL("/")
-
- await expect(
- page.getByText("Welcome back, nice to see you again!"),
- ).toBeVisible()
-
- await page.getByTestId("user-menu").click()
- await page.getByRole("menuitem", { name: "Log out" }).click()
- await page.waitForURL("/login")
-})
-
-test("Logged-out user cannot access protected routes", async ({ page }) => {
- await page.goto("/login")
-
- await fillForm(page, firstSuperuser, firstSuperuserPassword)
- await page.getByRole("button", { name: "Log In" }).click()
-
- await page.waitForURL("/")
-
- await expect(
- page.getByText("Welcome back, nice to see you again!"),
- ).toBeVisible()
-
- await page.getByTestId("user-menu").click()
- await page.getByRole("menuitem", { name: "Log out" }).click()
- await page.waitForURL("/login")
-
- await page.goto("/settings")
- await page.waitForURL("/login")
-})
diff --git a/frontend/tests/reset-password.spec.ts b/frontend/tests/reset-password.spec.ts
deleted file mode 100644
index 88ec798791..0000000000
--- a/frontend/tests/reset-password.spec.ts
+++ /dev/null
@@ -1,121 +0,0 @@
-import { expect, test } from "@playwright/test"
-import { findLastEmail } from "./utils/mailcatcher"
-import { randomEmail, randomPassword } from "./utils/random"
-import { logInUser, signUpNewUser } from "./utils/user"
-
-test.use({ storageState: { cookies: [], origins: [] } })
-
-test("Password Recovery title is visible", async ({ page }) => {
- await page.goto("/recover-password")
-
- await expect(
- page.getByRole("heading", { name: "Password Recovery" }),
- ).toBeVisible()
-})
-
-test("Input is visible, empty and editable", async ({ page }) => {
- await page.goto("/recover-password")
-
- await expect(page.getByPlaceholder("Email")).toBeVisible()
- await expect(page.getByPlaceholder("Email")).toHaveText("")
- await expect(page.getByPlaceholder("Email")).toBeEditable()
-})
-
-test("Continue button is visible", async ({ page }) => {
- await page.goto("/recover-password")
-
- await expect(page.getByRole("button", { name: "Continue" })).toBeVisible()
-})
-
-test("User can reset password successfully using the link", async ({
- page,
- request,
-}) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = randomPassword()
- const newPassword = randomPassword()
-
- // Sign up a new user
- await signUpNewUser(page, fullName, email, password)
-
- await page.goto("/recover-password")
- await page.getByPlaceholder("Email").fill(email)
-
- await page.getByRole("button", { name: "Continue" }).click()
-
- const emailData = await findLastEmail({
- request,
- filter: (e) => e.recipients.includes(`<${email}>`),
- timeout: 5000,
- })
-
- await page.goto(`http://localhost:1080/messages/${emailData.id}.html`)
-
- const selector = 'a[href*="/reset-password?token="]'
-
- let url = await page.getAttribute(selector, "href")
-
- // TODO: update var instead of doing a replace
- url = url!.replace("http://localhost/", "http://localhost:5173/")
-
- // Set the new password and confirm it
- await page.goto(url)
-
- await page.getByLabel("Set Password").fill(newPassword)
- await page.getByLabel("Confirm Password").fill(newPassword)
- await page.getByRole("button", { name: "Reset Password" }).click()
- await expect(page.getByText("Password updated successfully")).toBeVisible()
-
- // Check if the user is able to login with the new password
- await logInUser(page, email, newPassword)
-})
-
-test("Expired or invalid reset link", async ({ page }) => {
- const password = randomPassword()
- const invalidUrl = "/reset-password?token=invalidtoken"
-
- await page.goto(invalidUrl)
-
- await page.getByLabel("Set Password").fill(password)
- await page.getByLabel("Confirm Password").fill(password)
- await page.getByRole("button", { name: "Reset Password" }).click()
-
- await expect(page.getByText("Invalid token")).toBeVisible()
-})
-
-test("Weak new password validation", async ({ page, request }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = randomPassword()
- const weakPassword = "123"
-
- // Sign up a new user
- await signUpNewUser(page, fullName, email, password)
-
- await page.goto("/recover-password")
- await page.getByPlaceholder("Email").fill(email)
- await page.getByRole("button", { name: "Continue" }).click()
-
- const emailData = await findLastEmail({
- request,
- filter: (e) => e.recipients.includes(`<${email}>`),
- timeout: 5000,
- })
-
- await page.goto(`http://localhost:1080/messages/${emailData.id}.html`)
-
- const selector = 'a[href*="/reset-password?token="]'
- let url = await page.getAttribute(selector, "href")
- url = url!.replace("http://localhost/", "http://localhost:5173/")
-
- // Set a weak new password
- await page.goto(url)
- await page.getByLabel("Set Password").fill(weakPassword)
- await page.getByLabel("Confirm Password").fill(weakPassword)
- await page.getByRole("button", { name: "Reset Password" }).click()
-
- await expect(
- page.getByText("Password must be at least 8 characters"),
- ).toBeVisible()
-})
diff --git a/frontend/tests/sign-up.spec.ts b/frontend/tests/sign-up.spec.ts
deleted file mode 100644
index a666123280..0000000000
--- a/frontend/tests/sign-up.spec.ts
+++ /dev/null
@@ -1,169 +0,0 @@
-import { type Page, expect, test } from "@playwright/test"
-
-import { randomEmail, randomPassword } from "./utils/random"
-
-test.use({ storageState: { cookies: [], origins: [] } })
-
-type OptionsType = {
- exact?: boolean
-}
-
-const fillForm = async (
- page: Page,
- full_name: string,
- email: string,
- password: string,
- confirm_password: string,
-) => {
- await page.getByPlaceholder("Full Name").fill(full_name)
- await page.getByPlaceholder("Email").fill(email)
- await page.getByPlaceholder("Password", { exact: true }).fill(password)
- await page.getByPlaceholder("Repeat Password").fill(confirm_password)
-}
-
-const verifyInput = async (
- page: Page,
- placeholder: string,
- options?: OptionsType,
-) => {
- const input = page.getByPlaceholder(placeholder, options)
- await expect(input).toBeVisible()
- await expect(input).toHaveText("")
- await expect(input).toBeEditable()
-}
-
-test("Inputs are visible, empty and editable", async ({ page }) => {
- await page.goto("/signup")
-
- await verifyInput(page, "Full Name")
- await verifyInput(page, "Email")
- await verifyInput(page, "Password", { exact: true })
- await verifyInput(page, "Repeat Password")
-})
-
-test("Sign Up button is visible", async ({ page }) => {
- await page.goto("/signup")
-
- await expect(page.getByRole("button", { name: "Sign Up" })).toBeVisible()
-})
-
-test("Log In link is visible", async ({ page }) => {
- await page.goto("/signup")
-
- await expect(page.getByRole("link", { name: "Log In" })).toBeVisible()
-})
-
-test("Sign up with valid name, email, and password", async ({ page }) => {
- const full_name = "Test User"
- const email = randomEmail()
- const password = randomPassword()
-
- await page.goto("/signup")
- await fillForm(page, full_name, email, password, password)
- await page.getByRole("button", { name: "Sign Up" }).click()
-})
-
-test("Sign up with invalid email", async ({ page }) => {
- await page.goto("/signup")
-
- await fillForm(
- page,
- "Playwright Test",
- "invalid-email",
- "changethis",
- "changethis",
- )
- await page.getByRole("button", { name: "Sign Up" }).click()
-
- await expect(page.getByText("Invalid email address")).toBeVisible()
-})
-
-test("Sign up with existing email", async ({ page }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = randomPassword()
-
- // Sign up with an email
- await page.goto("/signup")
-
- await fillForm(page, fullName, email, password, password)
- await page.getByRole("button", { name: "Sign Up" }).click()
-
- // Sign up again with the same email
- await page.goto("/signup")
-
- await fillForm(page, fullName, email, password, password)
- await page.getByRole("button", { name: "Sign Up" }).click()
-
- await page
- .getByText("The user with this email already exists in the system")
- .click()
-})
-
-test("Sign up with weak password", async ({ page }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = "weak"
-
- await page.goto("/signup")
-
- await fillForm(page, fullName, email, password, password)
- await page.getByRole("button", { name: "Sign Up" }).click()
-
- await expect(
- page.getByText("Password must be at least 8 characters"),
- ).toBeVisible()
-})
-
-test("Sign up with mismatched passwords", async ({ page }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = randomPassword()
- const password2 = randomPassword()
-
- await page.goto("/signup")
-
- await fillForm(page, fullName, email, password, password2)
- await page.getByRole("button", { name: "Sign Up" }).click()
-
- await expect(page.getByText("Passwords do not match")).toBeVisible()
-})
-
-test("Sign up with missing full name", async ({ page }) => {
- const fullName = ""
- const email = randomEmail()
- const password = randomPassword()
-
- await page.goto("/signup")
-
- await fillForm(page, fullName, email, password, password)
- await page.getByRole("button", { name: "Sign Up" }).click()
-
- await expect(page.getByText("Full Name is required")).toBeVisible()
-})
-
-test("Sign up with missing email", async ({ page }) => {
- const fullName = "Test User"
- const email = ""
- const password = randomPassword()
-
- await page.goto("/signup")
-
- await fillForm(page, fullName, email, password, password)
- await page.getByRole("button", { name: "Sign Up" }).click()
-
- await expect(page.getByText("Email is required")).toBeVisible()
-})
-
-test("Sign up with missing password", async ({ page }) => {
- const fullName = ""
- const email = randomEmail()
- const password = ""
-
- await page.goto("/signup")
-
- await fillForm(page, fullName, email, password, password)
- await page.getByRole("button", { name: "Sign Up" }).click()
-
- await expect(page.getByText("Password is required")).toBeVisible()
-})
diff --git a/frontend/tests/user-settings.spec.ts b/frontend/tests/user-settings.spec.ts
deleted file mode 100644
index a3a8a27490..0000000000
--- a/frontend/tests/user-settings.spec.ts
+++ /dev/null
@@ -1,288 +0,0 @@
-import { expect, test } from "@playwright/test"
-import { firstSuperuser, firstSuperuserPassword } from "./config.ts"
-import { randomEmail, randomPassword } from "./utils/random"
-import { logInUser, logOutUser, signUpNewUser } from "./utils/user"
-
-const tabs = ["My profile", "Password", "Appearance"]
-
-// User Information
-
-test("My profile tab is active by default", async ({ page }) => {
- await page.goto("/settings")
- await expect(page.getByRole("tab", { name: "My profile" })).toHaveAttribute(
- "aria-selected",
- "true",
- )
-})
-
-test("All tabs are visible", async ({ page }) => {
- await page.goto("/settings")
- for (const tab of tabs) {
- await expect(page.getByRole("tab", { name: tab })).toBeVisible()
- }
-})
-
-test.describe("Edit user full name and email successfully", () => {
- test.use({ storageState: { cookies: [], origins: [] } })
-
- test("Edit user name with a valid name", async ({ page }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const updatedName = "Test User 2"
- const password = randomPassword()
-
- // Sign up a new user
- await signUpNewUser(page, fullName, email, password)
-
- // Log in the user
- await logInUser(page, email, password)
-
- await page.goto("/settings")
- await page.getByRole("tab", { name: "My profile" }).click()
- await page.getByRole("button", { name: "Edit" }).click()
- await page.getByLabel("Full name").fill(updatedName)
- await page.getByRole("button", { name: "Save" }).click()
- await expect(page.getByText("User updated successfully")).toBeVisible()
- // Check if the new name is displayed on the page
- await expect(
- page.getByLabel("My profile").getByText(updatedName, { exact: true }),
- ).toBeVisible()
- })
-
- test("Edit user email with a valid email", async ({ page }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const updatedEmail = randomEmail()
- const password = randomPassword()
-
- // Sign up a new user
- await signUpNewUser(page, fullName, email, password)
-
- // Log in the user
- await logInUser(page, email, password)
-
- await page.goto("/settings")
- await page.getByRole("tab", { name: "My profile" }).click()
- await page.getByRole("button", { name: "Edit" }).click()
- await page.getByLabel("Email").fill(updatedEmail)
- await page.getByRole("button", { name: "Save" }).click()
- await expect(page.getByText("User updated successfully")).toBeVisible()
- await expect(
- page.getByLabel("My profile").getByText(updatedEmail, { exact: true }),
- ).toBeVisible()
- })
-})
-
-test.describe("Edit user with invalid data", () => {
- test.use({ storageState: { cookies: [], origins: [] } })
-
- test("Edit user email with an invalid email", async ({ page }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = randomPassword()
- const invalidEmail = ""
-
- // Sign up a new user
- await signUpNewUser(page, fullName, email, password)
-
- // Log in the user
- await logInUser(page, email, password)
-
- await page.goto("/settings")
- await page.getByRole("tab", { name: "My profile" }).click()
- await page.getByRole("button", { name: "Edit" }).click()
- await page.getByLabel("Email").fill(invalidEmail)
- await page.locator("body").click()
- await expect(page.getByText("Email is required")).toBeVisible()
- })
-
- test("Cancel edit action restores original name", async ({ page }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = randomPassword()
- const updatedName = "Test User"
-
- // Sign up a new user
- await signUpNewUser(page, fullName, email, password)
-
- // Log in the user
- await logInUser(page, email, password)
-
- await page.goto("/settings")
- await page.getByRole("tab", { name: "My profile" }).click()
- await page.getByRole("button", { name: "Edit" }).click()
- await page.getByLabel("Full name").fill(updatedName)
- await page.getByRole("button", { name: "Cancel" }).first().click()
- await expect(
- page.getByLabel("My profile").getByText(fullName, { exact: true }),
- ).toBeVisible()
- })
-
- test("Cancel edit action restores original email", async ({ page }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = randomPassword()
- const updatedEmail = randomEmail()
-
- // Sign up a new user
- await signUpNewUser(page, fullName, email, password)
-
- // Log in the user
- await logInUser(page, email, password)
-
- await page.goto("/settings")
- await page.getByRole("tab", { name: "My profile" }).click()
- await page.getByRole("button", { name: "Edit" }).click()
- await page.getByLabel("Email").fill(updatedEmail)
- await page.getByRole("button", { name: "Cancel" }).first().click()
- await expect(
- page.getByLabel("My profile").getByText(email, { exact: true }),
- ).toBeVisible()
- })
-})
-
-// Change Password
-
-test.describe("Change password successfully", () => {
- test.use({ storageState: { cookies: [], origins: [] } })
-
- test("Update password successfully", async ({ page }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = randomPassword()
- const NewPassword = randomPassword()
-
- // Sign up a new user
- await signUpNewUser(page, fullName, email, password)
-
- // Log in the user
- await logInUser(page, email, password)
-
- await page.goto("/settings")
- await page.getByRole("tab", { name: "Password" }).click()
- await page.getByLabel("Current Password*").fill(password)
- await page.getByLabel("Set Password*").fill(NewPassword)
- await page.getByLabel("Confirm Password*").fill(NewPassword)
- await page.getByRole("button", { name: "Save" }).click()
- await expect(page.getByText("Password updated successfully.")).toBeVisible()
-
- await logOutUser(page)
-
- // Check if the user can log in with the new password
- await logInUser(page, email, NewPassword)
- })
-})
-
-test.describe("Change password with invalid data", () => {
- test.use({ storageState: { cookies: [], origins: [] } })
-
- test("Update password with weak passwords", async ({ page }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = randomPassword()
- const weakPassword = "weak"
-
- // Sign up a new user
- await signUpNewUser(page, fullName, email, password)
-
- // Log in the user
- await logInUser(page, email, password)
-
- await page.goto("/settings")
- await page.getByRole("tab", { name: "Password" }).click()
- await page.getByLabel("Current Password*").fill(password)
- await page.getByLabel("Set Password*").fill(weakPassword)
- await page.getByLabel("Confirm Password*").fill(weakPassword)
- await expect(
- page.getByText("Password must be at least 8 characters"),
- ).toBeVisible()
- })
-
- test("New password and confirmation password do not match", async ({
- page,
- }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = randomPassword()
- const newPassword = randomPassword()
- const confirmPassword = randomPassword()
-
- // Sign up a new user
- await signUpNewUser(page, fullName, email, password)
-
- // Log in the user
- await logInUser(page, email, password)
-
- await page.goto("/settings")
- await page.getByRole("tab", { name: "Password" }).click()
- await page.getByLabel("Current Password*").fill(password)
- await page.getByLabel("Set Password*").fill(newPassword)
- await page.getByLabel("Confirm Password*").fill(confirmPassword)
- await page.getByRole("button", { name: "Save" }).click()
- await expect(page.getByText("Passwords do not match")).toBeVisible()
- })
-
- test("Current password and new password are the same", async ({ page }) => {
- const fullName = "Test User"
- const email = randomEmail()
- const password = randomPassword()
-
- // Sign up a new user
- await signUpNewUser(page, fullName, email, password)
-
- // Log in the user
- await logInUser(page, email, password)
-
- await page.goto("/settings")
- await page.getByRole("tab", { name: "Password" }).click()
- await page.getByLabel("Current Password*").fill(password)
- await page.getByLabel("Set Password*").fill(password)
- await page.getByLabel("Confirm Password*").fill(password)
- await page.getByRole("button", { name: "Save" }).click()
- await expect(
- page.getByText("New password cannot be the same as the current one"),
- ).toBeVisible()
- })
-})
-
-// Appearance
-
-test("Appearance tab is visible", async ({ page }) => {
- await page.goto("/settings")
- await page.getByRole("tab", { name: "Appearance" }).click()
- await expect(page.getByLabel("Appearance")).toBeVisible()
-})
-
-test("User can switch from light mode to dark mode", async ({ page }) => {
- await page.goto("/settings")
- await page.getByRole("tab", { name: "Appearance" }).click()
- await page.getByLabel("Appearance").locator("span").nth(3).click()
- const isDarkMode = await page.evaluate(() =>
- document.body.classList.contains("chakra-ui-dark"),
- )
- expect(isDarkMode).toBe(true)
-})
-
-test("User can switch from dark mode to light mode", async ({ page }) => {
- await page.goto("/settings")
- await page.getByRole("tab", { name: "Appearance" }).click()
- await page.getByLabel("Appearance").locator("span").first().click()
- const isLightMode = await page.evaluate(() =>
- document.body.classList.contains("chakra-ui-light"),
- )
- expect(isLightMode).toBe(true)
-})
-
-test("Selected mode is preserved across sessions", async ({ page }) => {
- await page.goto("/settings")
- await page.getByRole("tab", { name: "Appearance" }).click()
- await page.getByLabel("Appearance").locator("span").nth(3).click()
-
- await logOutUser(page)
-
- await logInUser(page, firstSuperuser, firstSuperuserPassword)
- const isDarkMode = await page.evaluate(() =>
- document.body.classList.contains("chakra-ui-dark"),
- )
- expect(isDarkMode).toBe(true)
-})
diff --git a/frontend/tests/utils/mailcatcher.ts b/frontend/tests/utils/mailcatcher.ts
deleted file mode 100644
index 601ce434fb..0000000000
--- a/frontend/tests/utils/mailcatcher.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import type { APIRequestContext } from "@playwright/test"
-
-type Email = {
- id: number
- recipients: string[]
- subject: string
-}
-
-async function findEmail({
- request,
- filter,
-}: { request: APIRequestContext; filter?: (email: Email) => boolean }) {
- const response = await request.get("http://localhost:1080/messages")
-
- let emails = await response.json()
-
- if (filter) {
- emails = emails.filter(filter)
- }
-
- const email = emails[emails.length - 1]
-
- if (email) {
- return email as Email
- }
-
- return null
-}
-
-export function findLastEmail({
- request,
- filter,
- timeout = 5000,
-}: {
- request: APIRequestContext
- filter?: (email: Email) => boolean
- timeout?: number
-}) {
- const timeoutPromise = new Promise((_, reject) =>
- setTimeout(
- () => reject(new Error("Timeout while trying to get latest email")),
- timeout,
- ),
- )
-
- const checkEmails = async () => {
- while (true) {
- const emailData = await findEmail({ request, filter })
-
- if (emailData) {
- return emailData
- }
- // Wait for 100ms before checking again
- await new Promise((resolve) => setTimeout(resolve, 100))
- }
- }
-
- return Promise.race([timeoutPromise, checkEmails()])
-}
diff --git a/frontend/tests/utils/random.ts b/frontend/tests/utils/random.ts
deleted file mode 100644
index d96f0833ce..0000000000
--- a/frontend/tests/utils/random.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export const randomEmail = () =>
- `test_${Math.random().toString(36).substring(7)}@example.com`
-
-export const randomTeamName = () =>
- `Team ${Math.random().toString(36).substring(7)}`
-
-export const randomPassword = () => `${Math.random().toString(36).substring(2)}`
-
-export const slugify = (text: string) =>
- text
- .toLowerCase()
- .replace(/\s+/g, "-")
- .replace(/[^\w-]+/g, "")
diff --git a/frontend/tests/utils/user.ts b/frontend/tests/utils/user.ts
deleted file mode 100644
index 8fcfd26cb5..0000000000
--- a/frontend/tests/utils/user.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { type Page, expect } from "@playwright/test"
-
-export async function signUpNewUser(
- page: Page,
- name: string,
- email: string,
- password: string,
-) {
- await page.goto("/signup")
-
- await page.getByPlaceholder("Full Name").fill(name)
- await page.getByPlaceholder("Email").fill(email)
- await page.getByPlaceholder("Password", { exact: true }).fill(password)
- await page.getByPlaceholder("Repeat Password").fill(password)
- await page.getByRole("button", { name: "Sign Up" }).click()
- await expect(
- page.getByText("Your account has been created successfully"),
- ).toBeVisible()
- await page.goto("/login")
-}
-
-export async function logInUser(page: Page, email: string, password: string) {
- await page.goto("/login")
-
- await page.getByPlaceholder("Email").fill(email)
- await page.getByPlaceholder("Password", { exact: true }).fill(password)
- await page.getByRole("button", { name: "Log In" }).click()
- await page.waitForURL("/")
- await expect(
- page.getByText("Welcome back, nice to see you again!"),
- ).toBeVisible()
-}
-
-export async function logOutUser(page: Page) {
- await page.getByTestId("user-menu").click()
- await page.getByRole("menuitem", { name: "Log out" }).click()
- await page.goto("/login")
-}
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
deleted file mode 100644
index baadbb9fb1..0000000000
--- a/frontend/tsconfig.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2020",
- "useDefineForClassFields": true,
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
- "module": "ESNext",
- "skipLibCheck": true,
-
- /* Bundler mode */
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "resolveJsonModule": true,
- "isolatedModules": true,
- "noEmit": true,
- "jsx": "react-jsx",
-
- /* Linting */
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true
- },
- "include": ["src", "*.ts", "**/*.ts"],
- "references": [{ "path": "./tsconfig.node.json" }]
-}
diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json
deleted file mode 100644
index 42872c59f5..0000000000
--- a/frontend/tsconfig.node.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "compilerOptions": {
- "composite": true,
- "skipLibCheck": true,
- "module": "ESNext",
- "moduleResolution": "bundler",
- "allowSyntheticDefaultImports": true
- },
- "include": ["vite.config.ts"]
-}
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
deleted file mode 100644
index 572745b8cf..0000000000
--- a/frontend/vite.config.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { TanStackRouterVite } from "@tanstack/router-vite-plugin"
-import react from "@vitejs/plugin-react-swc"
-import { defineConfig } from "vite"
-
-// https://vitejs.dev/config/
-export default defineConfig({
- plugins: [react(), TanStackRouterVite()],
-})
diff --git a/img/dashboard-create.png b/img/dashboard-create.png
deleted file mode 100644
index a394141f7b..0000000000
Binary files a/img/dashboard-create.png and /dev/null differ
diff --git a/img/dashboard-dark.png b/img/dashboard-dark.png
deleted file mode 100644
index 51040a157b..0000000000
Binary files a/img/dashboard-dark.png and /dev/null differ
diff --git a/img/dashboard-items.png b/img/dashboard-items.png
deleted file mode 100644
index f50e2e834e..0000000000
Binary files a/img/dashboard-items.png and /dev/null differ
diff --git a/img/dashboard-user-settings.png b/img/dashboard-user-settings.png
deleted file mode 100644
index 8da2e21df7..0000000000
Binary files a/img/dashboard-user-settings.png and /dev/null differ
diff --git a/img/dashboard.png b/img/dashboard.png
deleted file mode 100644
index 0f034d691b..0000000000
Binary files a/img/dashboard.png and /dev/null differ
diff --git a/img/docs.png b/img/docs.png
deleted file mode 100644
index d61c2071c7..0000000000
Binary files a/img/docs.png and /dev/null differ
diff --git a/img/github-social-preview.png b/img/github-social-preview.png
deleted file mode 100644
index f1dc5959fb..0000000000
Binary files a/img/github-social-preview.png and /dev/null differ
diff --git a/img/github-social-preview.svg b/img/github-social-preview.svg
deleted file mode 100644
index 4b7a75760e..0000000000
--- a/img/github-social-preview.svg
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
diff --git a/img/login.png b/img/login.png
deleted file mode 100644
index 66e3a7202f..0000000000
Binary files a/img/login.png and /dev/null differ
diff --git a/scripts/build-push.sh b/scripts/build-push.sh
deleted file mode 100644
index 3fa3aa7e6b..0000000000
--- a/scripts/build-push.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#! /usr/bin/env sh
-
-# Exit in case of error
-set -e
-
-TAG=${TAG?Variable not set} \
-FRONTEND_ENV=${FRONTEND_ENV-production} \
-sh ./scripts/build.sh
-
-docker-compose -f docker-compose.yml push
diff --git a/scripts/build.sh b/scripts/build.sh
deleted file mode 100644
index 21528c538e..0000000000
--- a/scripts/build.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#! /usr/bin/env sh
-
-# Exit in case of error
-set -e
-
-TAG=${TAG?Variable not set} \
-FRONTEND_ENV=${FRONTEND_ENV-production} \
-docker-compose \
--f docker-compose.yml \
-build
diff --git a/scripts/generate-client.sh b/scripts/generate-client.sh
deleted file mode 100644
index 1327ee6fd1..0000000000
--- a/scripts/generate-client.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#! /usr/bin/env bash
-
-PYTHONPATH=backend python -c "import app.main; import json; print(json.dumps(app.main.app.openapi()))" > openapi.json
-node frontend/modify-openapi-operationids.js
-mv openapi.json frontend/
-cd frontend
-npm run generate-client
-npx biome format --write ./src/client