diff --git a/.gitignore b/.gitignore index 20d5ded..1c0bb74 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,5 @@ dist/ *.doctree *.pot *.mo + +.codex \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..e29dfab --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,62 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-added-large-files + - id: check-toml + - id: check-yaml + args: + - --unsafe + - id: end-of-file-fixer + exclude: | + (?x)^( + frontend/src/client/.*| + backend/app/email-templates/build/.* + )$ + - id: trailing-whitespace + exclude: ^frontend/src/client/.* + - repo: local + hooks: + - id: local-biome-check + name: biome check + entry: npm run lint + language: system + types: [text] + files: ^frontend/ + + - id: local-ruff-check + name: ruff check + entry: uv run ruff check --force-exclude --fix --exit-non-zero-on-fix + require_serial: true + language: unsupported + types: [python] + + - id: local-ruff-format + name: ruff format + entry: uv run ruff format --force-exclude --exit-non-zero-on-format + require_serial: true + language: unsupported + types: [python] + + - id: local-ty + name: ty check + entry: uv run ty check backend/app + require_serial: true + language: unsupported + pass_filenames: false + + - id: generate-frontend-sdk + name: Generate Frontend SDK + entry: bash ./scripts/generate-client.sh + pass_filenames: false + language: unsupported + files: ^backend/.*$|^scripts/generate-client\.sh$ + + - id: add-release-date + language: unsupported + name: add date to latest release header + entry: uv run python scripts/add_latest_release_date.py + files: ^release-notes\.md$ + pass_filenames: false diff --git a/.vscode/extensions.json b/.vscode/extensions.json index c9b3a46..58ed862 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,9 +3,12 @@ "biomejs.biome", "bradlc.vscode-tailwindcss", "ms-python.debugpy", - "ms-python.python", "mechatroner.rainbow-csv", "redhat.vscode-yaml", - "ms-python.isort" + "ms-python.isort", + "charliermarsh.ruff", + "ms-python.vscode-python-envs", + "astral-sh.ty", + "tombi-toml.tombi" ] } \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f729270 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,7 @@ +Run Python commands inside the backend folder with uv run. + +Use pnpm inside the frontend folder. + +Always write type safe Python and strictly 3.14 syntax. + +frontend/src/lib/client should be generated by running `uv run app/scripts/generate_client.py` (inside of the backend folder) to generate the client after making changes to the API. diff --git a/Makefile b/Makefile index 59d4cd1..c8dc567 100644 --- a/Makefile +++ b/Makefile @@ -19,3 +19,4 @@ frontend: backend: cd backend && uv sync && uv run fastapi dev + diff --git a/README.md b/README.md index 4faa1e4..150e7c2 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,11 @@ Run common commands from the root of the project using `make`. > [!Important] > Before running anything, first create the required `.env` files. See [environment variable documentation](https://opensacorg.github.io/app-capanel-doc/developer-guide/environment-variables). +#### **TODO:** Improve environment variable documentation. + +- [ ] Add public/mock env files to the root and frontend folder. +- [ ] Document in this README the commonly needed and missed environment variables that are required to first run. + ### Backend documentation (Sphinx) `make reload` diff --git a/backend/README.md b/backend/README.md index 578c951..59389a9 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,42 +1,58 @@ -# California Accountability Panel backend +# California Accountability Panel back-end documentation -This project is a copy of the main application backend, but there are slight differences. The goals are: +This project is a copy of the main application back-end, but there are slight differences. The goals are: -- A simpler development environment without Docker. - Use Sphinx to generate documentation with autodoc. - Test the project extensively, in more ways than with the main application. +- A simpler development environment without Docker. > **Note:** This project must be manually kept in sync by copy-pasting files to and from the main application. See the [sync documentation](https://opensacorg.github.io/app-capanel-doc/developer-guide/documentation-repository-sync). -## Overvie w - -- [Developer Guide](https://opensacorg.github.io/app-capanel-doc/developer-guide/) -- [Install](https://opensacorg.github.io/app-capanel-doc/developer-guide/install/) -- [Development workflow](https://opensacorg.github.io/app-capanel-doc/developer-guide/development) -- [Run application](https://opensacorg.github.io/app-capanel-doc/developer-guide/run-application) -- [Testing](https://opensacorg.github.io/app-capanel-doc/developer-guide/testing) -- [Extended backend/frontend README reference](https://opensacorg.github.io/app-capanel-doc/developer-guide/readme-reference) - -## Requirements +## Prerequisites - [uv](https://docs.astral.sh/uv/) -## Quickstart +## Quick start -First, install the backend dependencies. +First, install the back-end dependencies. - `cd backend` - `uv sync` > [!Warning] > Before running anything, first create the required `.env` files. See [environment variable documentation](https://opensacorg.github.io/app-capanel-doc/developer-guide/environment-variables). +> [!Note] +> Python commands must be run from the backend folder. It is recommended to open the backend folders separately in VS Code. To run from the root of the project, it is recommended to use Make. + +### Run the sphinx autoload + +``` +sphinx-autobuild docs/source docs/build/html +``` + +You can also run with Make. Be aware that this will create a .venv folder inside of backend/docs. This might be confusing. + +## Run the application + ### Initialize the database -If you haven't already done so, initialize the database. This will run the migrations and create a default super user. +Initialize the database. This will run the migrations and create a default superuser. -`uv run app/scripts/initial_data.py` +``` +uv run app/scripts/initial_data.py +``` ### Start the local development server -`uv run --env-file ../.env fastapi dev` -or from the root of the project: -`uv run --env-file .env fastapi dev backend\app\main.py` + +- From the backend folder: `uv run --env-file ../.env fastapi dev` +- From the root of the project: `uv run fastapi dev backend/app/main.py`. + + +## Resources + +- [Developer Guide](https://opensacorg.github.io/app-capanel-doc/developer-guide/) +- [Install](https://opensacorg.github.io/app-capanel-doc/developer-guide/install/) +- [Development workflow](https://opensacorg.github.io/app-capanel-doc/developer-guide/development) +- [Run application](https://opensacorg.github.io/app-capanel-doc/developer-guide/run-application) +- [Testing](https://opensacorg.github.io/app-capanel-doc/developer-guide/testing) +- [Extended backend/frontend README reference](https://opensacorg.github.io/app-capanel-doc/developer-guide/readme-reference) diff --git a/backend/app/alembic/env.py b/backend/app/alembic/env.py index 5f13087..7b109ac 100755 --- a/backend/app/alembic/env.py +++ b/backend/app/alembic/env.py @@ -3,32 +3,16 @@ from alembic import context from sqlalchemy import engine_from_config, pool -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. config = context.config - -# Interpret the config file for Python logging. -# This line sets up loggers basically. -# mypy says config.config_file_name can be None, but Alembic always sets it. assert config.config_file_name is not None, "config_file_name is required" fileConfig(config.config_file_name) -# add your model's MetaData object here -# for 'autogenerate' support -# from myapp import mymodel -# target_metadata = mymodel.Base.metadata -# target_metadata = None - -from app.model.models import SQLModel # noqa +from app.model.other import SQLModel # noqa +import app.model # noqa from app.core.config import settings # noqa target_metadata = SQLModel.metadata -# 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") -# ... etc. - def get_url(): return str(settings.SQLALCHEMY_DATABASE_URI) @@ -62,7 +46,7 @@ def run_migrations_online(): and associate a connection with the context. """ - configuration = config.get_section(config.config_ini_section) + configuration = config.get_section(config.config_ini_section) or {} configuration["sqlalchemy.url"] = get_url() connectable = engine_from_config( configuration, 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 10e47a1..0000000 --- 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/1d53f36fa2de_update_censusdata_primary_key_to_schl_id.py b/backend/app/alembic/versions/1d53f36fa2de_update_censusdata_primary_key_to_schl_id.py deleted file mode 100644 index 22716ba..0000000 --- a/backend/app/alembic/versions/1d53f36fa2de_update_censusdata_primary_key_to_schl_id.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Update CensusData primary key to schl_id - -Revision ID: 1d53f36fa2de -Revises: abbe6b667292 -Create Date: 2025-08-10 09:29:15.214807 - -""" -import sqlalchemy as sa -from alembic import op - -# revision identifiers, used by Alembic. -revision = '1d53f36fa2de' -down_revision = 'abbe6b667292' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - # Drop the existing primary key constraint - op.drop_constraint('censusdata_pkey', 'censusdata', type_='primary') - # Add primary key constraint on schl_id - op.create_primary_key('censusdata_pkey', 'censusdata', ['schl_id']) - # Drop the old id column - op.drop_column('censusdata', 'id') - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - # Add back the id column - op.add_column('censusdata', sa.Column('id', sa.UUID(), autoincrement=False, nullable=False)) - # Drop the current primary key constraint - op.drop_constraint('censusdata_pkey', 'censusdata', type_='primary') - # Add primary key constraint back on id - op.create_primary_key('censusdata_pkey', 'censusdata', ['id']) - # ### end Alembic commands ### diff --git a/backend/app/alembic/versions/3b8a6856d220_add_censusdata_model.py b/backend/app/alembic/versions/3b8a6856d220_add_censusdata_model.py deleted file mode 100644 index 4be45de..0000000 --- a/backend/app/alembic/versions/3b8a6856d220_add_censusdata_model.py +++ /dev/null @@ -1,34 +0,0 @@ -"""Add CensusData model - -Revision ID: 3b8a6856d220 -Revises: 1a31ce608336 -Create Date: 2025-08-10 09:19:55.971451 - -""" -import sqlalchemy as sa -from alembic import op - -# revision identifiers, used by Alembic. -revision = '3b8a6856d220' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('censusdata', - sa.Column('id', sa.UUID(), nullable=False), - sa.Column('school_name', - sa.String(length=255), - nullable=False), - sa.Column('student_count', sa.Integer(), nullable=False), - sa.PrimaryKeyConstraint('id') - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('censusdata') - # ### end Alembic commands ### diff --git a/backend/app/alembic/versions/74673f8651ca_merge_migrations.py b/backend/app/alembic/versions/74673f8651ca_merge_migrations.py deleted file mode 100644 index f713515..0000000 --- a/backend/app/alembic/versions/74673f8651ca_merge_migrations.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Merge migrations - -Revision ID: 74673f8651ca -Revises: 1a31ce608336, 3b8a6856d220 -Create Date: 2025-08-10 09:27:32.584158 - -""" - -# revision identifiers, used by Alembic. -revision = '74673f8651ca' -down_revision = ('1a31ce608336', '3b8a6856d220') -branch_labels = None -depends_on = None - - -def upgrade(): - pass - - -def downgrade(): - pass diff --git a/backend/app/alembic/versions/8a38665e13e6_add_census_data_models.py b/backend/app/alembic/versions/8a38665e13e6_add_census_data_models.py deleted file mode 100644 index 8f614d7..0000000 --- a/backend/app/alembic/versions/8a38665e13e6_add_census_data_models.py +++ /dev/null @@ -1,29 +0,0 @@ -"""Add Census data models - -Revision ID: 8a38665e13e6 -Revises: eb18e3ec8487 -Create Date: 2025-08-10 20:06:19.178801 - -""" -import sqlalchemy as sa -from alembic import op - -# revision identifiers, used by Alembic. -revision = '8a38665e13e6' -down_revision = 'eb18e3ec8487' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('censusdata', sa.Column('census_data_id', sa.Uuid(), nullable=False)) - op.drop_column('censusdata', 'schl_id') - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('censusdata', sa.Column('schl_id', sa.UUID(), autoincrement=False, nullable=False)) - op.drop_column('censusdata', 'census_data_id') - # ### end Alembic commands ### diff --git a/backend/app/alembic/versions/92d9dd83e19d_merge_heads.py b/backend/app/alembic/versions/92d9dd83e19d_merge_heads.py deleted file mode 100644 index 35c3bda..0000000 --- a/backend/app/alembic/versions/92d9dd83e19d_merge_heads.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Merge heads - -Revision ID: 92d9dd83e19d -Revises: d3deb8989ec8, fe56fa70289e -Create Date: 2026-02-03 20:39:54.155445 - -""" -from alembic import op -import sqlalchemy as sa -import sqlmodel.sql.sqltypes - - -# revision identifiers, used by Alembic. -revision = '92d9dd83e19d' -down_revision = ('d3deb8989ec8', 'fe56fa70289e') -branch_labels = None -depends_on = None - - -def upgrade(): - pass - - -def downgrade(): - pass 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 78a4177..0000000 --- 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/a1b2c3d4e5f6_extend_academicindicator.py b/backend/app/alembic/versions/a1b2c3d4e5f6_extend_academicindicator.py deleted file mode 100644 index 5c9f95b..0000000 --- a/backend/app/alembic/versions/a1b2c3d4e5f6_extend_academicindicator.py +++ /dev/null @@ -1,143 +0,0 @@ -"""Extend academicindicator with all indicator fields - -Revision ID: a1b2c3d4e5f6 -Revises: eb9bef92a74f -Create Date: 2026-02-04 10:00:00.000000 - -""" - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = "a1b2c3d4e5f6" -down_revision = "eb9bef92a74f" -branch_labels = None -depends_on = None - - -def upgrade(): - # Common fields (Chronic, Suspension, Graduation, ELPI) - op.add_column( - "academicindicator", sa.Column("currnumer", sa.Integer(), nullable=True) - ) - op.add_column( - "academicindicator", sa.Column("priornumer", sa.Integer(), nullable=True) - ) - op.add_column( - "academicindicator", sa.Column("smalldenom", sa.String(10), nullable=True) - ) - op.add_column( - "academicindicator", sa.Column("certifyflag", sa.String(10), nullable=True) - ) - op.add_column( - "academicindicator", sa.Column("priorcertifyflag", sa.String(10), nullable=True) - ) - op.add_column( - "academicindicator", sa.Column("dataerrorflag", sa.String(10), nullable=True) - ) - - # Suspension-specific - op.add_column( - "academicindicator", sa.Column("school_type", sa.String(50), nullable=True) - ) - - # Graduation-specific - op.add_column( - "academicindicator", sa.Column("fiveyrnumer", sa.Integer(), nullable=True) - ) - - # ELPI fields (16 total) - elpi_fields = [ - "currprogressed", - "currmaintainpl4", - "currmaintainoth", - "currdeclined", - "currprogressed_alternate", - "currmaintainpl3_alternate", - "currnotprognotmain_alternate", - "curr95", - "priorprogressed", - "priormaintainpl4", - "priormaintainoth", - "priordeclined", - "priorprogressed_alternate", - "priormaintainpl3_alternate", - "priornotprognotmain_alternate", - "prior95", - ] - for field in elpi_fields: - op.add_column( - "academicindicator", sa.Column(field, sa.Integer(), nullable=True) - ) - - # CCI JSON and studentgroup_pct - op.add_column( - "academicindicator", sa.Column("cci_details", sa.JSON(), nullable=True) - ) - op.add_column( - "academicindicator", sa.Column("studentgroup_pct", sa.Float(), nullable=True) - ) - - # Indexes for better query performance - op.create_index( - "ix_academicindicator_indicator", "academicindicator", ["indicator"] - ) - op.create_index( - "ix_academicindicator_cds_indicator_year", - "academicindicator", - ["cds", "indicator", "reportingyear"], - ) - - # User preferences - add last_viewed_cds - op.add_column("user", sa.Column("last_viewed_cds", sa.String(14), nullable=True)) - - -def downgrade(): - # Remove user preferences - op.drop_column("user", "last_viewed_cds") - - # Remove indexes - op.drop_index("ix_academicindicator_cds_indicator_year", table_name="academicindicator") - op.drop_index("ix_academicindicator_indicator", table_name="academicindicator") - - # Remove CCI and studentgroup_pct - op.drop_column("academicindicator", "studentgroup_pct") - op.drop_column("academicindicator", "cci_details") - - # Remove ELPI fields - elpi_fields = [ - "currprogressed", - "currmaintainpl4", - "currmaintainoth", - "currdeclined", - "currprogressed_alternate", - "currmaintainpl3_alternate", - "currnotprognotmain_alternate", - "curr95", - "priorprogressed", - "priormaintainpl4", - "priormaintainoth", - "priordeclined", - "priorprogressed_alternate", - "priormaintainpl3_alternate", - "priornotprognotmain_alternate", - "prior95", - ] - for field in elpi_fields: - op.drop_column("academicindicator", field) - - # Remove Graduation-specific - op.drop_column("academicindicator", "fiveyrnumer") - - # Remove Suspension-specific - op.drop_column("academicindicator", "school_type") - - # Remove common fields - op.drop_column("academicindicator", "dataerrorflag") - op.drop_column("academicindicator", "priorcertifyflag") - op.drop_column("academicindicator", "certifyflag") - op.drop_column("academicindicator", "smalldenom") - op.drop_column("academicindicator", "priornumer") - op.drop_column("academicindicator", "currnumer") diff --git a/backend/app/alembic/versions/a3afd5df08ce_merge_b19f9f4b7c12_and_c1a2b3d4e5f7.py b/backend/app/alembic/versions/a3afd5df08ce_merge_b19f9f4b7c12_and_c1a2b3d4e5f7.py deleted file mode 100644 index dd60496..0000000 --- a/backend/app/alembic/versions/a3afd5df08ce_merge_b19f9f4b7c12_and_c1a2b3d4e5f7.py +++ /dev/null @@ -1,25 +0,0 @@ -"""merge_b19f9f4b7c12_and_c1a2b3d4e5f7 - -Revision ID: a3afd5df08ce -Revises: b19f9f4b7c12, c1a2b3d4e5f7 -Create Date: 2026-03-04 23:41:21.018207 - -""" -from alembic import op -import sqlalchemy as sa -import sqlmodel.sql.sqltypes - - -# revision identifiers, used by Alembic. -revision = 'a3afd5df08ce' -down_revision = ('b19f9f4b7c12', 'c1a2b3d4e5f7') -branch_labels = None -depends_on = None - - -def upgrade(): - pass - - -def downgrade(): - pass diff --git a/backend/app/alembic/versions/abbe6b667292_update_censusdata_model_with_new_fields.py b/backend/app/alembic/versions/abbe6b667292_update_censusdata_model_with_new_fields.py deleted file mode 100644 index c3703a5..0000000 --- a/backend/app/alembic/versions/abbe6b667292_update_censusdata_model_with_new_fields.py +++ /dev/null @@ -1,90 +0,0 @@ -"""Update CensusData model with new fields - -Revision ID: abbe6b667292 -Revises: 74673f8651ca -Create Date: 2025-08-10 09:27:46.345244 - -""" -import sqlalchemy as sa -import sqlmodel.sql.sqltypes -from alembic import op - -# revision identifiers, used by Alembic. -revision = 'abbe6b667292' -down_revision = '74673f8651ca' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('censusdata', sa.Column('schl_id', sa.Uuid(), nullable=False)) - op.add_column('censusdata', sa.Column('academic_year', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('aggregation_level', sqlmodel.sql.sqltypes.AutoString(), nullable=False)) - op.add_column('censusdata', sa.Column('county_code', sqlmodel.sql.sqltypes.AutoString(), nullable=False)) - op.add_column('censusdata', sa.Column('district_code', sqlmodel.sql.sqltypes.AutoString(), nullable=False)) - op.add_column('censusdata', sa.Column('school_code', sqlmodel.sql.sqltypes.AutoString(), nullable=False)) - op.add_column('censusdata', sa.Column('county_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False)) - op.add_column('censusdata', - sa.Column('district_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False)) - op.add_column('censusdata', sa.Column('charter', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False)) - op.add_column('censusdata', - sa.Column('reporting_category', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False)) - op.add_column('censusdata', sa.Column('total_enr', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_tk', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_kn', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_1', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_2', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_3', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_4', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_5', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_6', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_7', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_8', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_9', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_10', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_11', sa.Integer(), nullable=False)) - op.add_column('censusdata', sa.Column('gr_12', sa.Integer(), nullable=False)) - op.create_index(op.f('ix_censusdata_academic_year'), 'censusdata', ['academic_year'], unique=False) - op.create_index(op.f('ix_censusdata_aggregation_level'), 'censusdata', ['aggregation_level'], unique=False) - op.create_index(op.f('ix_censusdata_county_code'), 'censusdata', ['county_code'], unique=False) - op.create_index(op.f('ix_censusdata_district_code'), 'censusdata', ['district_code'], unique=False) - op.create_index(op.f('ix_censusdata_school_code'), 'censusdata', ['school_code'], unique=False) - op.drop_column('censusdata', 'student_count') - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('censusdata', sa.Column('student_count', sa.INTEGER(), autoincrement=False, nullable=False)) - op.drop_index(op.f('ix_censusdata_school_code'), table_name='censusdata') - op.drop_index(op.f('ix_censusdata_district_code'), table_name='censusdata') - op.drop_index(op.f('ix_censusdata_county_code'), table_name='censusdata') - op.drop_index(op.f('ix_censusdata_aggregation_level'), table_name='censusdata') - op.drop_index(op.f('ix_censusdata_academic_year'), table_name='censusdata') - op.drop_column('censusdata', 'gr_12') - op.drop_column('censusdata', 'gr_11') - op.drop_column('censusdata', 'gr_10') - op.drop_column('censusdata', 'gr_9') - op.drop_column('censusdata', 'gr_8') - op.drop_column('censusdata', 'gr_7') - op.drop_column('censusdata', 'gr_6') - op.drop_column('censusdata', 'gr_5') - op.drop_column('censusdata', 'gr_4') - op.drop_column('censusdata', 'gr_3') - op.drop_column('censusdata', 'gr_2') - op.drop_column('censusdata', 'gr_1') - op.drop_column('censusdata', 'gr_kn') - op.drop_column('censusdata', 'gr_tk') - op.drop_column('censusdata', 'total_enr') - op.drop_column('censusdata', 'reporting_category') - op.drop_column('censusdata', 'charter') - op.drop_column('censusdata', 'district_name') - op.drop_column('censusdata', 'county_name') - op.drop_column('censusdata', 'school_code') - op.drop_column('censusdata', 'district_code') - op.drop_column('censusdata', 'county_code') - op.drop_column('censusdata', 'aggregation_level') - op.drop_column('censusdata', 'academic_year') - op.drop_column('censusdata', 'schl_id') - # ### end Alembic commands ### diff --git a/backend/app/alembic/versions/b19f9f4b7c12_add_force_password_reset_to_user.py b/backend/app/alembic/versions/b19f9f4b7c12_add_force_password_reset_to_user.py deleted file mode 100644 index 97ead15..0000000 --- a/backend/app/alembic/versions/b19f9f4b7c12_add_force_password_reset_to_user.py +++ /dev/null @@ -1,34 +0,0 @@ -"""Add force_password_reset flag to user - -Revision ID: b19f9f4b7c12 -Revises: a1b2c3d4e5f6 -Create Date: 2026-03-04 16:10:00.000000 - -""" - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = "b19f9f4b7c12" -down_revision = "a1b2c3d4e5f6" -branch_labels = None -depends_on = None - - -def upgrade(): - op.add_column( - "user", - sa.Column( - "force_password_reset", - sa.Boolean(), - nullable=False, - server_default=sa.false(), - ), - ) - op.alter_column("user", "force_password_reset", server_default=None) - - -def downgrade(): - op.drop_column("user", "force_password_reset") diff --git a/backend/app/alembic/versions/c1a2b3d4e5f7_normalize_chronic_indicator_value.py b/backend/app/alembic/versions/c1a2b3d4e5f7_normalize_chronic_indicator_value.py deleted file mode 100644 index f7ea4b5..0000000 --- a/backend/app/alembic/versions/c1a2b3d4e5f7_normalize_chronic_indicator_value.py +++ /dev/null @@ -1,38 +0,0 @@ -"""Normalize CHRO indicator value to CHRONIC - -Revision ID: c1a2b3d4e5f7 -Revises: f5a83e87d6ee -Create Date: 2026-03-04 23:24:00.000000 - -The CDE Excel files store the chronic absenteeism indicator as "CHRO" in the -``indicator`` column, while the canonical name used everywhere else in the -application is "CHRONIC". This migration normalises all existing rows so the -column contains a single consistent value. -""" - -# revision identifiers, used by Alembic. -revision = 'c1a2b3d4e5f7' -down_revision = ('f5a83e87d6ee', 'a1b2c3d4e5f6') -branch_labels = None -depends_on = None - -from alembic import op - - -def upgrade() -> None: - # Delete CHRO rows that would conflict with an existing CHRONIC row for the - # same natural key (cds, studentgroup, reportingyear), then rename the rest. - op.execute(""" - DELETE FROM academicindicator a - USING academicindicator b - WHERE a.indicator = 'CHRO' - AND b.indicator = 'CHRONIC' - AND a.cds = b.cds - AND a.studentgroup = b.studentgroup - AND a.reportingyear = b.reportingyear - """) - op.execute("UPDATE academicindicator SET indicator = 'CHRONIC' WHERE indicator = 'CHRO'") - - -def downgrade() -> None: - op.execute("UPDATE academicindicator SET indicator = 'CHRO' WHERE indicator = 'CHRONIC'") diff --git a/backend/app/alembic/versions/d3deb8989ec8_add_new_school_table.py b/backend/app/alembic/versions/d3deb8989ec8_add_new_school_table.py deleted file mode 100644 index f8e6b71..0000000 --- a/backend/app/alembic/versions/d3deb8989ec8_add_new_school_table.py +++ /dev/null @@ -1,78 +0,0 @@ -"""Add new school table - -Revision ID: d3deb8989ec8 -Revises: 8a38665e13e6 -Create Date: 2025-08-15 14:28:31.864299 - -""" -import sqlalchemy as sa -import sqlmodel.sql.sqltypes -from alembic import op - -# revision identifiers, used by Alembic. -revision = 'd3deb8989ec8' -down_revision = '8a38665e13e6' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('school', - sa.Column('cds_code', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), - sa.Column('nces_dist', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('nces_school', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('status_type', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('county', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('district', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('school', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('street', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('street_abr', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('city', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('zip', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('state', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('mail_street', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('mail_street_abr', sqlmodel.sql.sqltypes.AutoString(), nullable=True), - sa.Column('mail_city', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('mail_zip', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('mail_state', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('phone', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('ext', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('fax_number', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('website', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('open_date', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('closed_date', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('charter', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('charter_num', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('funding_type', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('doc', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('doc_type', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('soc', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('soc_type', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('edops_code', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('edops_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('eil_code', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('eil_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('gs_offered', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('gs_served', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('virtual', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('magnet', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('year_round_yn', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('federal_dfc_district_id', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('latitude', sa.Float(), nullable=True), - sa.Column('longitude', sa.Float(), nullable=True), - sa.Column('adm_fname', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('adm_lname', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('last_up_date', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('multilingual', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('id', sa.Uuid(), nullable=False), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('cds_code') - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('school') - # ### 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 37af1fa..0000000 --- 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 7529ea9..0000000 --- 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/eb18e3ec8487_check_schema_after_model_refactoring.py b/backend/app/alembic/versions/eb18e3ec8487_check_schema_after_model_refactoring.py deleted file mode 100644 index 24e3560..0000000 --- a/backend/app/alembic/versions/eb18e3ec8487_check_schema_after_model_refactoring.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Check schema after model refactoring - -Revision ID: eb18e3ec8487 -Revises: f5a83e87d6ee -Create Date: 2025-08-10 19:52:20.647288 - -""" - -# revision identifiers, used by Alembic. -revision = 'eb18e3ec8487' -down_revision = 'f5a83e87d6ee' -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/eb9bef92a74f_add_academicindicator_table.py b/backend/app/alembic/versions/eb9bef92a74f_add_academicindicator_table.py deleted file mode 100644 index 8768cb0..0000000 --- a/backend/app/alembic/versions/eb9bef92a74f_add_academicindicator_table.py +++ /dev/null @@ -1,74 +0,0 @@ -"""Add academicindicator table - -Revision ID: eb9bef92a74f -Revises: 92d9dd83e19d -Create Date: 2026-02-03 21:33:49.555298 - -""" -from alembic import op -import sqlalchemy as sa -import sqlmodel.sql.sqltypes - - -# revision identifiers, used by Alembic. -revision = 'eb9bef92a74f' -down_revision = '92d9dd83e19d' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('academicindicator', - sa.Column('cds', sqlmodel.sql.sqltypes.AutoString(length=14), nullable=False), - sa.Column('rtype', sqlmodel.sql.sqltypes.AutoString(length=1), nullable=False), - sa.Column('schoolname', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('districtname', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('countyname', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('charter_flag', sqlmodel.sql.sqltypes.AutoString(length=1), nullable=True), - sa.Column('coe_flag', sqlmodel.sql.sqltypes.AutoString(length=1), nullable=True), - sa.Column('dass_flag', sqlmodel.sql.sqltypes.AutoString(length=1), nullable=True), - sa.Column('studentgroup', sqlmodel.sql.sqltypes.AutoString(length=10), nullable=False), - sa.Column('currdenom', sa.Integer(), nullable=True), - sa.Column('currstatus', sa.Float(), nullable=True), - sa.Column('priordenom', sa.Integer(), nullable=True), - sa.Column('priorstatus', sa.Float(), nullable=True), - sa.Column('change', sa.Float(), nullable=True), - sa.Column('statuslevel', sa.Integer(), nullable=True), - sa.Column('changelevel', sa.Integer(), nullable=True), - sa.Column('color', sa.Integer(), nullable=True), - sa.Column('box', sa.Integer(), nullable=True), - sa.Column('currnsizemet', sqlmodel.sql.sqltypes.AutoString(length=10), nullable=True), - sa.Column('priornsizemet', sqlmodel.sql.sqltypes.AutoString(length=10), nullable=True), - sa.Column('accountabilitymet', sqlmodel.sql.sqltypes.AutoString(length=10), nullable=True), - sa.Column('hscutpoints', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('pairshare_method', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), - sa.Column('currprate_enrolled', sa.Integer(), nullable=True), - sa.Column('currprate_tested', sa.Integer(), nullable=True), - sa.Column('currprate', sa.Float(), nullable=True), - sa.Column('currnumprloss', sa.Integer(), nullable=True), - sa.Column('currdenom_withoutprloss', sa.Integer(), nullable=True), - sa.Column('currstatus_withoutprloss', sa.Float(), nullable=True), - sa.Column('priorprate_enrolled', sa.Integer(), nullable=True), - sa.Column('priorprate_tested', sa.Integer(), nullable=True), - sa.Column('priorprate', sa.Float(), nullable=True), - sa.Column('priornumprloss', sa.Integer(), nullable=True), - sa.Column('priordenom_withoutprloss', sa.Integer(), nullable=True), - sa.Column('priorstatus_withoutprloss', sa.Float(), nullable=True), - sa.Column('indicator', sqlmodel.sql.sqltypes.AutoString(length=10), nullable=False), - sa.Column('reportingyear', sqlmodel.sql.sqltypes.AutoString(length=10), nullable=False), - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('created_at', sa.DateTime(timezone=True), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.create_index(op.f('ix_academicindicator_cds'), 'academicindicator', ['cds'], unique=False) - op.create_index(op.f('ix_academicindicator_studentgroup'), 'academicindicator', ['studentgroup'], unique=False) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_academicindicator_studentgroup'), table_name='academicindicator') - op.drop_index(op.f('ix_academicindicator_cds'), table_name='academicindicator') - op.drop_table('academicindicator') - # ### end Alembic commands ### diff --git a/backend/app/alembic/versions/f5a83e87d6ee_check_for_schema_changes_with_new_models.py b/backend/app/alembic/versions/f5a83e87d6ee_check_for_schema_changes_with_new_models.py deleted file mode 100644 index a014274..0000000 --- a/backend/app/alembic/versions/f5a83e87d6ee_check_for_schema_changes_with_new_models.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Check for schema changes with new models - -Revision ID: f5a83e87d6ee -Revises: 1d53f36fa2de -Create Date: 2025-08-10 19:49:03.754078 - -""" - -# revision identifiers, used by Alembic. -revision = 'f5a83e87d6ee' -down_revision = '1d53f36fa2de' -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/fa601598b7df_initial_migration.py b/backend/app/alembic/versions/fa601598b7df_initial_migration.py new file mode 100644 index 0000000..87ec013 --- /dev/null +++ b/backend/app/alembic/versions/fa601598b7df_initial_migration.py @@ -0,0 +1,688 @@ +"""Initial migration + +Revision ID: fa601598b7df +Revises: +Create Date: 2026-04-06 11:32:16.430619 + +""" +from alembic import op +import sqlalchemy as sa +import sqlmodel.sql.sqltypes + + +# revision identifiers, used by Alembic. +revision = 'fa601598b7df' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('caaspp_student_groups', + sa.Column('demographic_id', sqlmodel.sql.sqltypes.AutoString(length=10), nullable=False), + sa.Column('demographic_id_num', sa.Integer(), nullable=True), + sa.Column('demographic_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('student_group', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.PrimaryKeyConstraint('demographic_id') + ) + op.create_table('caaspp_tests', + sa.Column('test_id', sa.Integer(), nullable=False), + sa.Column('test_id_num', sa.Integer(), nullable=True), + sa.Column('test_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.PrimaryKeyConstraint('test_id') + ) + op.create_table('census_data', + sa.Column('academic_year', sa.Integer(), nullable=False), + sa.Column('aggregation_level', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('cds_code', sqlmodel.sql.sqltypes.AutoString(length=14), nullable=False), + sa.Column('charter', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('reporting_category', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), + sa.Column('total_enr', sa.Integer(), nullable=False), + sa.Column('gr_tk', sa.Integer(), nullable=False), + sa.Column('gr_kn', sa.Integer(), nullable=False), + sa.Column('gr_1', sa.Integer(), nullable=False), + sa.Column('gr_2', sa.Integer(), nullable=False), + sa.Column('gr_3', sa.Integer(), nullable=False), + sa.Column('gr_4', sa.Integer(), nullable=False), + sa.Column('gr_5', sa.Integer(), nullable=False), + sa.Column('gr_6', sa.Integer(), nullable=False), + sa.Column('gr_7', sa.Integer(), nullable=False), + sa.Column('gr_8', sa.Integer(), nullable=False), + sa.Column('gr_9', sa.Integer(), nullable=False), + sa.Column('gr_10', sa.Integer(), nullable=False), + sa.Column('gr_11', sa.Integer(), nullable=False), + sa.Column('gr_12', sa.Integer(), nullable=False), + sa.Column('id', sa.Uuid(), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_census_data_academic_year'), 'census_data', ['academic_year'], unique=False) + op.create_index(op.f('ix_census_data_aggregation_level'), 'census_data', ['aggregation_level'], unique=False) + op.create_index(op.f('ix_census_data_cds_code'), 'census_data', ['cds_code'], unique=False) + op.create_table('elpac_student_groups', + sa.Column('student_group_id', sqlmodel.sql.sqltypes.AutoString(length=10), nullable=False), + sa.Column('student_group_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.PrimaryKeyConstraint('student_group_id') + ) + op.create_table('elpac_tests', + sa.Column('test_id', sa.Integer(), nullable=False), + sa.Column('test_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.PrimaryKeyConstraint('test_id') + ) + op.create_table('entities', + sa.Column('cds_code', sqlmodel.sql.sqltypes.AutoString(length=14), nullable=False), + sa.Column('county_name', sqlmodel.sql.sqltypes.AutoString(length=25), nullable=True), + sa.Column('district_name', sqlmodel.sql.sqltypes.AutoString(length=40), nullable=True), + sa.Column('school_name', sqlmodel.sql.sqltypes.AutoString(length=60), nullable=True), + sa.Column('filler', sqlmodel.sql.sqltypes.AutoString(length=4), nullable=True), + sa.Column('zip_code', sqlmodel.sql.sqltypes.AutoString(length=9), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('cds_code') + ) + op.create_table('schools', + sa.Column('cds_code', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), + sa.Column('nces_dist', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), + sa.Column('nces_school', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), + sa.Column('school_code', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), + sa.Column('status_type', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('county', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('district', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('school', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('street', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.Column('street_abr', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.Column('city', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('zip', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('state', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('mail_street', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.Column('mail_street_abr', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.Column('mail_city', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('mail_zip', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('mail_state', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('phone', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('ext', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('fax_number', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('website', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('open_date', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('closed_date', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('charter', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('charter_num', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('funding_type', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('doc', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('doc_type', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('soc', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('soc_type', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('edops_code', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('edops_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('eil_code', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('eil_name', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('gs_offered', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('gs_served', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('virtual', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('magnet', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('year_round_yn', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('federal_dfc_district_id', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('latitude', sa.Float(), nullable=True), + sa.Column('longitude', sa.Float(), nullable=True), + sa.Column('adm_fname', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('adm_lname', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('last_up_date', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('multilingual', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('id', sa.Uuid(), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_schools_cds_code'), 'schools', ['cds_code'], unique=True) + op.create_table('users', + sa.Column('email', sqlmodel.sql.sqltypes.AutoString(length=255), 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('hashed_password', sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('last_viewed_cds', sqlmodel.sql.sqltypes.AutoString(length=14), nullable=True), + sa.Column('force_password_reset', sa.Boolean(), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True) + op.create_table('altia_elpac_results', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('cds_code', sa.String(length=14), nullable=True), + sa.Column('test_year', sa.Integer(), nullable=True), + sa.Column('student_group_id', sa.String(), nullable=True), + sa.Column('test_id', sa.Integer(), nullable=True), + sa.Column('grade', sa.String(length=2), nullable=True), + sa.Column('filler', sa.String(length=4), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.Column('total_students_enrolled', sa.Integer(), nullable=True), + sa.Column('total_students_tested', sa.Integer(), nullable=True), + sa.Column('total_students_tested_with_scores', sa.Integer(), nullable=True), + sa.Column('overall_total', sa.Integer(), nullable=True), + sa.Column('OverallMeanScaleScore', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('OverallPerfLvl1Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OverallPerfLvl1Count', sa.Integer(), nullable=True), + sa.Column('OverallPerfLvl2Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OverallPerfLvl2Count', sa.Integer(), nullable=True), + sa.Column('OverallPerfLvl3Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OverallPerfLvl3Count', sa.Integer(), nullable=True), + sa.Column('OverallPerfLvl4Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OverallPerfLvl4Count', sa.Integer(), nullable=True), + sa.Column('OralLangMeanScaleScore', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('OralLangPerfLvl1Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OralLangPerfLvl1Count', sa.Integer(), nullable=True), + sa.Column('OralLangPerfLvl2Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OralLangPerfLvl2Count', sa.Integer(), nullable=True), + sa.Column('OralLangPerfLvl3Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OralLangPerfLvl3Count', sa.Integer(), nullable=True), + sa.Column('OralLangPerfLvl4Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OralLangPerfLvl4Count', sa.Integer(), nullable=True), + sa.Column('OralLangTotal', sa.Integer(), nullable=True), + sa.Column('WritLangMeanScaleScore', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('WritLangPerfLvl1Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('WritLangPerfLvl1Count', sa.Integer(), nullable=True), + sa.Column('WritLangPerfLvl2Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('WritLangPerfLvl2Count', sa.Integer(), nullable=True), + sa.Column('WritLangPerfLvl3Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('WritLangPerfLvl3Count', sa.Integer(), nullable=True), + sa.Column('WritLangPerfLvl4Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('WritLangPerfLvl4Count', sa.Integer(), nullable=True), + sa.Column('WritLangTotal', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['cds_code'], ['entities.cds_code'], ), + sa.ForeignKeyConstraint(['student_group_id'], ['elpac_student_groups.student_group_id'], ), + sa.ForeignKeyConstraint(['test_id'], ['elpac_tests.test_id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('cds_code', 'test_year', 'student_group_id', 'test_id', 'grade', name='ix_altia_elpac_results_natural_key') + ) + op.create_index('ix_altia_elpac_results_student_group', 'altia_elpac_results', ['student_group_id'], unique=False) + op.create_index('ix_altia_elpac_results_year_grade', 'altia_elpac_results', ['test_year', 'grade'], unique=False) + op.create_table('altsa_elpac_results', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('cds_code', sa.String(length=14), nullable=True), + sa.Column('test_year', sa.Integer(), nullable=True), + sa.Column('student_group_id', sa.String(), nullable=True), + sa.Column('test_id', sa.Integer(), nullable=True), + sa.Column('grade', sa.String(length=2), nullable=True), + sa.Column('filler', sa.String(length=4), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.Column('total_students_enrolled', sa.Integer(), nullable=True), + sa.Column('total_students_tested', sa.Integer(), nullable=True), + sa.Column('total_students_tested_with_scores', sa.Integer(), nullable=True), + sa.Column('overall_total', sa.Integer(), nullable=True), + sa.Column('OverallMeanScaleScore', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('OverallPerfLvl1Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OverallPerfLvl1Count', sa.Integer(), nullable=True), + sa.Column('OverallPerfLvl2Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OverallPerfLvl2Count', sa.Integer(), nullable=True), + sa.Column('OverallPerfLvl3Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OverallPerfLvl3Count', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['cds_code'], ['entities.cds_code'], ), + sa.ForeignKeyConstraint(['student_group_id'], ['elpac_student_groups.student_group_id'], ), + sa.ForeignKeyConstraint(['test_id'], ['elpac_tests.test_id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('cds_code', 'test_year', 'student_group_id', 'test_id', 'grade', name='ix_altsa_elpac_results_natural_key') + ) + op.create_index('ix_altsa_elpac_results_student_group', 'altsa_elpac_results', ['student_group_id'], unique=False) + op.create_index('ix_altsa_elpac_results_year_grade', 'altsa_elpac_results', ['test_year', 'grade'], unique=False) + op.create_table('caa_results', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('cds_code', sa.String(length=14), nullable=True), + sa.Column('test_year', sa.Integer(), nullable=True), + sa.Column('student_group_id', sa.String(), nullable=True), + sa.Column('test_id', sa.Integer(), nullable=True), + sa.Column('grade', sa.String(length=2), nullable=True), + sa.Column('filler', sa.String(length=4), nullable=True), + sa.Column('test_type', sa.String(length=1), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.Column('total_students_enrolled', sa.Integer(), nullable=True), + sa.Column('total_students_tested', sa.Integer(), nullable=True), + sa.Column('total_students_tested_with_scores', sa.Integer(), nullable=True), + sa.Column('overall_total', sa.Integer(), nullable=True), + sa.Column('Mean Scale Score', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('Count Level 1', sa.Integer(), nullable=True), + sa.Column('Count Level 2', sa.Integer(), nullable=True), + sa.Column('Count Level 3', sa.Integer(), nullable=True), + sa.Column('Percentage Level 1', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Level 2', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Level 3', sa.Numeric(precision=5, scale=2), nullable=True), + sa.ForeignKeyConstraint(['cds_code'], ['entities.cds_code'], ), + sa.ForeignKeyConstraint(['student_group_id'], ['caaspp_student_groups.demographic_id'], ), + sa.ForeignKeyConstraint(['test_id'], ['caaspp_tests.test_id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('cds_code', 'test_year', 'student_group_id', 'test_id', 'grade', name='ix_caa_results_natural_key') + ) + op.create_index('ix_caa_results_student_group', 'caa_results', ['student_group_id'], unique=False) + op.create_index('ix_caa_results_year_grade', 'caa_results', ['test_year', 'grade'], unique=False) + op.create_table('caas_results', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('cds_code', sa.String(length=14), nullable=True), + sa.Column('test_year', sa.Integer(), nullable=True), + sa.Column('student_group_id', sa.String(), nullable=True), + sa.Column('test_id', sa.Integer(), nullable=True), + sa.Column('grade', sa.String(length=2), nullable=True), + sa.Column('filler', sa.String(length=4), nullable=True), + sa.Column('test_type', sa.String(length=1), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.Column('total_students_enrolled', sa.Integer(), nullable=True), + sa.Column('total_students_tested', sa.Integer(), nullable=True), + sa.Column('total_students_tested_with_scores', sa.Integer(), nullable=True), + sa.Column('overall_total', sa.Integer(), nullable=True), + sa.Column('Mean Scale Score', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('Count Level 1', sa.Integer(), nullable=True), + sa.Column('Count Level 2', sa.Integer(), nullable=True), + sa.Column('Count Level 3', sa.Integer(), nullable=True), + sa.Column('Percentage Level 1', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Level 2', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Level 3', sa.Numeric(precision=5, scale=2), nullable=True), + sa.ForeignKeyConstraint(['cds_code'], ['entities.cds_code'], ), + sa.ForeignKeyConstraint(['student_group_id'], ['caaspp_student_groups.demographic_id'], ), + sa.ForeignKeyConstraint(['test_id'], ['caaspp_tests.test_id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('cds_code', 'test_year', 'student_group_id', 'test_id', 'grade', name='ix_caas_results_natural_key') + ) + op.create_index('ix_caas_results_student_group', 'caas_results', ['student_group_id'], unique=False) + op.create_index('ix_caas_results_year_grade', 'caas_results', ['test_year', 'grade'], unique=False) + op.create_table('cast_results', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('cds_code', sa.String(length=14), nullable=True), + sa.Column('test_year', sa.Integer(), nullable=True), + sa.Column('student_group_id', sa.String(), nullable=True), + sa.Column('test_id', sa.Integer(), nullable=True), + sa.Column('grade', sa.String(length=2), nullable=True), + sa.Column('filler', sa.String(length=4), nullable=True), + sa.Column('test_type', sa.String(length=1), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.Column('total_students_enrolled', sa.Integer(), nullable=True), + sa.Column('total_students_tested', sa.Integer(), nullable=True), + sa.Column('total_students_tested_with_scores', sa.Integer(), nullable=True), + sa.Column('overall_total', sa.Integer(), nullable=True), + sa.Column('Mean Scale Score', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('Count Standard Exceeded', sa.Integer(), nullable=True), + sa.Column('Count Standard Met', sa.Integer(), nullable=True), + sa.Column('Count Standard Met and Above', sa.Integer(), nullable=True), + sa.Column('Count Standard Nearly Met', sa.Integer(), nullable=True), + sa.Column('Count Standard Not Met', sa.Integer(), nullable=True), + sa.Column('Percentage Standard Exceeded', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Standard Met', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Standard Met and Above', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Standard Nearly Met', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Standard Not Met', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Earth and Space Sciences Domain Count Above Standard', sa.Integer(), nullable=True), + sa.Column('Earth and Space Sciences Domain Count Below Standard', sa.Integer(), nullable=True), + sa.Column('Earth and Space Sciences Domain Count Near Standard', sa.Integer(), nullable=True), + sa.Column('Earth and Space Sciences Domain Percent Above Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Earth and Space Sciences Domain Percent Below Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Earth and Space Sciences Domain Percent Near Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Earth and Space Sciences Domain Total', sa.Integer(), nullable=True), + sa.Column('Life Sciences Domain Count Above Standard', sa.Integer(), nullable=True), + sa.Column('Life Sciences Domain Count Below Standard', sa.Integer(), nullable=True), + sa.Column('Life Sciences Domain Count Near Standard', sa.Integer(), nullable=True), + sa.Column('Life Sciences Domain Percent Above Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Life Sciences Domain Percent Below Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Life Sciences Domain Percent Near Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Life Sciences Domain Total', sa.Integer(), nullable=True), + sa.Column('Physical Sciences Domain Count Above Standard', sa.Integer(), nullable=True), + sa.Column('Physical Sciences Domain Count Below Standard', sa.Integer(), nullable=True), + sa.Column('Physical Sciences Domain Count Near Standard', sa.Integer(), nullable=True), + sa.Column('Physical Sciences Domain Percent Above Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Physical Sciences Domain Percent Below Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Physical Sciences Domain Percent Near Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Physical Sciences Domain Total', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['cds_code'], ['entities.cds_code'], ), + sa.ForeignKeyConstraint(['student_group_id'], ['caaspp_student_groups.demographic_id'], ), + sa.ForeignKeyConstraint(['test_id'], ['caaspp_tests.test_id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('cds_code', 'test_year', 'student_group_id', 'test_id', 'grade', name='ix_cast_results_natural_key') + ) + op.create_index('ix_cast_results_student_group', 'cast_results', ['student_group_id'], unique=False) + op.create_index('ix_cast_results_year_grade', 'cast_results', ['test_year', 'grade'], unique=False) + op.create_table('csa_results', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('cds_code', sa.String(length=14), nullable=True), + sa.Column('test_year', sa.Integer(), nullable=True), + sa.Column('student_group_id', sa.String(), nullable=True), + sa.Column('test_id', sa.Integer(), nullable=True), + sa.Column('grade', sa.String(length=2), nullable=True), + sa.Column('filler', sa.String(length=4), nullable=True), + sa.Column('test_type', sa.String(length=1), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.Column('total_students_enrolled', sa.Integer(), nullable=True), + sa.Column('total_students_tested', sa.Integer(), nullable=True), + sa.Column('total_students_tested_with_scores', sa.Integer(), nullable=True), + sa.Column('overall_total', sa.Integer(), nullable=True), + sa.Column('Overall Mean Scale Score', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('Count Level 1', sa.Integer(), nullable=True), + sa.Column('Count Level 2', sa.Integer(), nullable=True), + sa.Column('Count Level 3', sa.Integer(), nullable=True), + sa.Column('Percent Level 1', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percent Level 2', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percent Level 3', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite 1 Count Level 1', sa.Integer(), nullable=True), + sa.Column('Composite 1 Count Level 2', sa.Integer(), nullable=True), + sa.Column('Composite 1 Count Level 3', sa.Integer(), nullable=True), + sa.Column('Composite 1 Mean Scale Score', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('Composite 1 Percent Level 1', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite 1 Percent Level 2', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite 1 Percent Level 3', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite 1 Total', sa.Integer(), nullable=True), + sa.Column('Composite 2 Count Level 1', sa.Integer(), nullable=True), + sa.Column('Composite 2 Count Level 2', sa.Integer(), nullable=True), + sa.Column('Composite 2 Count Level 3', sa.Integer(), nullable=True), + sa.Column('Composite 2 Mean Scale Score', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('Composite 2 Percent Level 1', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite 2 Percent Level 2', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite 2 Percent Level 3', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite 2 Total', sa.Integer(), nullable=True), + sa.Column('Listening Domain Count Level 1', sa.Integer(), nullable=True), + sa.Column('Listening Domain Count Level 2', sa.Integer(), nullable=True), + sa.Column('Listening Domain Count Level 3', sa.Integer(), nullable=True), + sa.Column('Listening Domain Percent Level 1', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Listening Domain Percent Level 2', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Listening Domain Percent Level 3', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Listening Domain Total', sa.Integer(), nullable=True), + sa.Column('Reading Domain Count Level 1', sa.Integer(), nullable=True), + sa.Column('Reading Domain Count Level 2', sa.Integer(), nullable=True), + sa.Column('Reading Domain Count Level 3', sa.Integer(), nullable=True), + sa.Column('Reading Domain Percent Level 1', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Reading Domain Percent Level 2', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Reading Domain Percent Level 3', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Reading Domain Total', sa.Integer(), nullable=True), + sa.Column('Speaking Domain Count Level 1', sa.Integer(), nullable=True), + sa.Column('Speaking Domain Count Level 2', sa.Integer(), nullable=True), + sa.Column('Speaking Domain Count Level 3', sa.Integer(), nullable=True), + sa.Column('Speaking Domain Percent Level 1', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Speaking Domain Percent Level 2', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Speaking Domain Percent Level 3', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Speaking Domain Total', sa.Integer(), nullable=True), + sa.Column('Writing Domain Count Level 1', sa.Integer(), nullable=True), + sa.Column('Writing Domain Count Level 2', sa.Integer(), nullable=True), + sa.Column('Writing Domain Count Level 3', sa.Integer(), nullable=True), + sa.Column('Writing Domain Percent Level 1', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Writing Domain Percent Level 2', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Writing Domain Percent Level 3', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Writing Domain Total', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['cds_code'], ['entities.cds_code'], ), + sa.ForeignKeyConstraint(['student_group_id'], ['caaspp_student_groups.demographic_id'], ), + sa.ForeignKeyConstraint(['test_id'], ['caaspp_tests.test_id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('cds_code', 'test_year', 'student_group_id', 'test_id', 'grade', name='ix_csa_results_natural_key') + ) + op.create_index('ix_csa_results_student_group', 'csa_results', ['student_group_id'], unique=False) + op.create_index('ix_csa_results_year_grade', 'csa_results', ['test_year', 'grade'], unique=False) + op.create_table('ia_elpac_results', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('cds_code', sa.String(length=14), nullable=True), + sa.Column('test_year', sa.Integer(), nullable=True), + sa.Column('student_group_id', sa.String(), nullable=True), + sa.Column('test_id', sa.Integer(), nullable=True), + sa.Column('grade', sa.String(length=2), nullable=True), + sa.Column('filler', sa.String(length=4), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.Column('total_students_enrolled', sa.Integer(), nullable=True), + sa.Column('total_students_tested', sa.Integer(), nullable=True), + sa.Column('total_students_tested_with_scores', sa.Integer(), nullable=True), + sa.Column('overall_total', sa.Integer(), nullable=True), + sa.Column('OverallMeanSclScr', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('NoviceELPerfLvlPcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('NoviceELPerfLvlCount', sa.Integer(), nullable=True), + sa.Column('IntermediateELPerfLvlPcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('IntermediateELPerfLvlCount', sa.Integer(), nullable=True), + sa.Column('IFEPPerfLvlPcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('IFEPPerfLvlCount', sa.Integer(), nullable=True), + sa.Column('OralLangMinimallyDevelopedPerfLvlPcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OralLangMinimallyDevelopedPerfLvlCount', sa.Integer(), nullable=True), + sa.Column('OralLangModeratelyDevelopedPerfLvlPcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OralLangModeratelyDevelopedPerfLvlCount', sa.Integer(), nullable=True), + sa.Column('OralLangWellDevelopedPerfLvlPcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OralLangWellDevelopedPerfLvlCount', sa.Integer(), nullable=True), + sa.Column('OralLangTotal', sa.Integer(), nullable=True), + sa.Column('WritLangMinimallyDevelopedPerfLvlPcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('WritLangMinimallyDevelopedPerfLvlCount', sa.Integer(), nullable=True), + sa.Column('WritLangModeratelyDevelopedPerfLvlPcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('WritLangModeratelyDevelopedPerfLvlCount', sa.Integer(), nullable=True), + sa.Column('WritLangWellDevelopedPerfLvlPcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('WritLangWellDevelopedPerfLvlCount', sa.Integer(), nullable=True), + sa.Column('WritLangTotal', sa.Integer(), nullable=True), + sa.Column('listening_domain_begin_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('listening_domain_begin_count', sa.Integer(), nullable=True), + sa.Column('listening_domain_moderate_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('listening_domain_moderate_count', sa.Integer(), nullable=True), + sa.Column('listening_domain_developed_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('listening_domain_developed_count', sa.Integer(), nullable=True), + sa.Column('listening_domain_total', sa.Integer(), nullable=True), + sa.Column('speaking_domain_begin_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('speaking_domain_begin_count', sa.Integer(), nullable=True), + sa.Column('speaking_domain_moderate_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('speaking_domain_moderate_count', sa.Integer(), nullable=True), + sa.Column('speaking_domain_developed_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('speaking_domain_developed_count', sa.Integer(), nullable=True), + sa.Column('speaking_domain_total', sa.Integer(), nullable=True), + sa.Column('reading_domain_begin_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('reading_domain_begin_count', sa.Integer(), nullable=True), + sa.Column('reading_domain_moderate_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('reading_domain_moderate_count', sa.Integer(), nullable=True), + sa.Column('reading_domain_developed_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('reading_domain_developed_count', sa.Integer(), nullable=True), + sa.Column('reading_domain_total', sa.Integer(), nullable=True), + sa.Column('writing_domain_begin_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('writing_domain_begin_count', sa.Integer(), nullable=True), + sa.Column('writing_domain_moderate_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('writing_domain_moderate_count', sa.Integer(), nullable=True), + sa.Column('writing_domain_developed_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('writing_domain_developed_count', sa.Integer(), nullable=True), + sa.Column('writing_domain_total', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['cds_code'], ['entities.cds_code'], ), + sa.ForeignKeyConstraint(['student_group_id'], ['elpac_student_groups.student_group_id'], ), + sa.ForeignKeyConstraint(['test_id'], ['elpac_tests.test_id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('cds_code', 'test_year', 'student_group_id', 'test_id', 'grade', name='ix_ia_elpac_results_natural_key') + ) + op.create_index('ix_ia_elpac_results_student_group', 'ia_elpac_results', ['student_group_id'], unique=False) + op.create_index('ix_ia_elpac_results_year_grade', 'ia_elpac_results', ['test_year', 'grade'], unique=False) + op.create_table('items', + sa.Column('title', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False), + sa.Column('description', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=True), + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('owner_id', sa.Uuid(), nullable=False), + sa.ForeignKeyConstraint(['owner_id'], ['users.id'], ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('sa_elpac_results', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('cds_code', sa.String(length=14), nullable=True), + sa.Column('test_year', sa.Integer(), nullable=True), + sa.Column('student_group_id', sa.String(), nullable=True), + sa.Column('test_id', sa.Integer(), nullable=True), + sa.Column('grade', sa.String(length=2), nullable=True), + sa.Column('filler', sa.String(length=4), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.Column('total_students_enrolled', sa.Integer(), nullable=True), + sa.Column('total_students_tested', sa.Integer(), nullable=True), + sa.Column('total_students_tested_with_scores', sa.Integer(), nullable=True), + sa.Column('overall_total', sa.Integer(), nullable=True), + sa.Column('OverallMeanScaleScore', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('OverallPerfLvl1Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OverallPerfLvl1Count', sa.Integer(), nullable=True), + sa.Column('OverallPerfLvl2Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OverallPerfLvl2Count', sa.Integer(), nullable=True), + sa.Column('OverallPerfLvl3Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OverallPerfLvl3Count', sa.Integer(), nullable=True), + sa.Column('OverallPerfLvl4Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OverallPerfLvl4Count', sa.Integer(), nullable=True), + sa.Column('OralLangMeanScaleScore', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('OralLangPerfLvl1Count', sa.Integer(), nullable=True), + sa.Column('OralLangPerfLvl1Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OralLangPerfLvl2Count', sa.Integer(), nullable=True), + sa.Column('OralLangPerfLvl2Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OralLangPerfLvl3Count', sa.Integer(), nullable=True), + sa.Column('OralLangPerfLvl3Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OralLangPerfLvl4Count', sa.Integer(), nullable=True), + sa.Column('OralLangPerfLvl4Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('OralLangTotal', sa.Integer(), nullable=True), + sa.Column('WritLangMeanScaleScore', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('WritLangPerfLvl1Count', sa.Integer(), nullable=True), + sa.Column('WritLangPerfLvl1Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('WritLangPerfLvl2Count', sa.Integer(), nullable=True), + sa.Column('WritLangPerfLvl2Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('WritLangPerfLvl3Count', sa.Integer(), nullable=True), + sa.Column('WritLangPerfLvl3Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('WritLangPerfLvl4Count', sa.Integer(), nullable=True), + sa.Column('WritLangPerfLvl4Pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('WritLangTotal', sa.Integer(), nullable=True), + sa.Column('listening_domain_begin_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('listening_domain_begin_count', sa.Integer(), nullable=True), + sa.Column('listening_domain_moderate_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('listening_domain_moderate_count', sa.Integer(), nullable=True), + sa.Column('listening_domain_developed_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('listening_domain_developed_count', sa.Integer(), nullable=True), + sa.Column('listening_domain_total', sa.Integer(), nullable=True), + sa.Column('speaking_domain_begin_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('speaking_domain_begin_count', sa.Integer(), nullable=True), + sa.Column('speaking_domain_moderate_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('speaking_domain_moderate_count', sa.Integer(), nullable=True), + sa.Column('speaking_domain_developed_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('speaking_domain_developed_count', sa.Integer(), nullable=True), + sa.Column('speaking_domain_total', sa.Integer(), nullable=True), + sa.Column('reading_domain_begin_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('reading_domain_begin_count', sa.Integer(), nullable=True), + sa.Column('reading_domain_moderate_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('reading_domain_moderate_count', sa.Integer(), nullable=True), + sa.Column('reading_domain_developed_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('reading_domain_developed_count', sa.Integer(), nullable=True), + sa.Column('reading_domain_total', sa.Integer(), nullable=True), + sa.Column('writing_domain_begin_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('writing_domain_begin_count', sa.Integer(), nullable=True), + sa.Column('writing_domain_moderate_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('writing_domain_moderate_count', sa.Integer(), nullable=True), + sa.Column('writing_domain_developed_pcnt', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('writing_domain_developed_count', sa.Integer(), nullable=True), + sa.Column('writing_domain_total', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['cds_code'], ['entities.cds_code'], ), + sa.ForeignKeyConstraint(['student_group_id'], ['elpac_student_groups.student_group_id'], ), + sa.ForeignKeyConstraint(['test_id'], ['elpac_tests.test_id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('cds_code', 'test_year', 'student_group_id', 'test_id', 'grade', name='ix_sa_elpac_results_natural_key') + ) + op.create_index('ix_sa_elpac_results_student_group', 'sa_elpac_results', ['student_group_id'], unique=False) + op.create_index('ix_sa_elpac_results_year_grade', 'sa_elpac_results', ['test_year', 'grade'], unique=False) + op.create_table('sb_results', + sa.Column('id', sa.Uuid(), nullable=False), + sa.Column('cds_code', sa.String(length=14), nullable=True), + sa.Column('test_year', sa.Integer(), nullable=True), + sa.Column('student_group_id', sa.String(), nullable=True), + sa.Column('test_id', sa.Integer(), nullable=True), + sa.Column('grade', sa.String(length=2), nullable=True), + sa.Column('filler', sa.String(length=4), nullable=True), + sa.Column('test_type', sa.String(length=1), nullable=True), + sa.Column('type_id', sa.Integer(), nullable=True), + sa.Column('total_students_enrolled', sa.Integer(), nullable=True), + sa.Column('total_students_tested', sa.Integer(), nullable=True), + sa.Column('total_students_tested_with_scores', sa.Integer(), nullable=True), + sa.Column('overall_total', sa.Integer(), nullable=True), + sa.Column('Mean Scale Score', sa.Numeric(precision=6, scale=1), nullable=True), + sa.Column('Count Standard Exceeded', sa.Integer(), nullable=True), + sa.Column('Count Standard Met', sa.Integer(), nullable=True), + sa.Column('Count Standard Met and Above', sa.Integer(), nullable=True), + sa.Column('Count Standard Nearly Met', sa.Integer(), nullable=True), + sa.Column('Count Standard Not Met', sa.Integer(), nullable=True), + sa.Column('Percentage Standard Exceeded', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Standard Met', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Standard Met and Above', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Standard Nearly Met', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Percentage Standard Not Met', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 1 Count Above Standard', sa.Integer(), nullable=True), + sa.Column('Area 1 Count Below Standard', sa.Integer(), nullable=True), + sa.Column('Area 1 Count Near Standard', sa.Integer(), nullable=True), + sa.Column('Area 1 Percentage Above Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 1 Percentage Below Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 1 Percentage Near Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 1 Total', sa.Integer(), nullable=True), + sa.Column('Area 2 Count Above Standard', sa.Integer(), nullable=True), + sa.Column('Area 2 Count Below Standard', sa.Integer(), nullable=True), + sa.Column('Area 2 Count Near Standard', sa.Integer(), nullable=True), + sa.Column('Area 2 Percentage Above Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 2 Percentage Below Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 2 Percentage Near Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 2 Total', sa.Integer(), nullable=True), + sa.Column('Area 3 Count Above Standard', sa.Integer(), nullable=True), + sa.Column('Area 3 Count Below Standard', sa.Integer(), nullable=True), + sa.Column('Area 3 Count Near Standard', sa.Integer(), nullable=True), + sa.Column('Area 3 Percentage Above Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 3 Percentage Below Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 3 Percentage Near Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 3 Total', sa.Integer(), nullable=True), + sa.Column('Area 4 Count Above Standard', sa.Integer(), nullable=True), + sa.Column('Area 4 Count Below Standard', sa.Integer(), nullable=True), + sa.Column('Area 4 Count Near Standard', sa.Integer(), nullable=True), + sa.Column('Area 4 Percentage Above Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 4 Percentage Below Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 4 Percentage Near Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Area 4 Total', sa.Integer(), nullable=True), + sa.Column('Composite Area 1 Count Above Standard', sa.Integer(), nullable=True), + sa.Column('Composite Area 1 Count Below Standard', sa.Integer(), nullable=True), + sa.Column('Composite Area 1 Count Near Standard', sa.Integer(), nullable=True), + sa.Column('Composite Area 1 Percentage Above Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite Area 1 Percentage Below Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite Area 1 Percentage Near Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite Area 1 Total', sa.Integer(), nullable=True), + sa.Column('Composite Area 2 Count Above Standard', sa.Integer(), nullable=True), + sa.Column('Composite Area 2 Count Below Standard', sa.Integer(), nullable=True), + sa.Column('Composite Area 2 Count Near Standard', sa.Integer(), nullable=True), + sa.Column('Composite Area 2 Percentage Above Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite Area 2 Percentage Below Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite Area 2 Percentage Near Standard', sa.Numeric(precision=5, scale=2), nullable=True), + sa.Column('Composite Area 2 Total', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['cds_code'], ['entities.cds_code'], ), + sa.ForeignKeyConstraint(['student_group_id'], ['caaspp_student_groups.demographic_id'], ), + sa.ForeignKeyConstraint(['test_id'], ['caaspp_tests.test_id'], ), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('cds_code', 'test_year', 'student_group_id', 'test_id', 'grade', name='ix_sb_results_natural_key') + ) + op.create_index('ix_sb_results_student_group', 'sb_results', ['student_group_id'], unique=False) + op.create_index('ix_sb_results_year_grade', 'sb_results', ['test_year', 'grade'], unique=False) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index('ix_sb_results_year_grade', table_name='sb_results') + op.drop_index('ix_sb_results_student_group', table_name='sb_results') + op.drop_table('sb_results') + op.drop_index('ix_sa_elpac_results_year_grade', table_name='sa_elpac_results') + op.drop_index('ix_sa_elpac_results_student_group', table_name='sa_elpac_results') + op.drop_table('sa_elpac_results') + op.drop_table('items') + op.drop_index('ix_ia_elpac_results_year_grade', table_name='ia_elpac_results') + op.drop_index('ix_ia_elpac_results_student_group', table_name='ia_elpac_results') + op.drop_table('ia_elpac_results') + op.drop_index('ix_csa_results_year_grade', table_name='csa_results') + op.drop_index('ix_csa_results_student_group', table_name='csa_results') + op.drop_table('csa_results') + op.drop_index('ix_cast_results_year_grade', table_name='cast_results') + op.drop_index('ix_cast_results_student_group', table_name='cast_results') + op.drop_table('cast_results') + op.drop_index('ix_caas_results_year_grade', table_name='caas_results') + op.drop_index('ix_caas_results_student_group', table_name='caas_results') + op.drop_table('caas_results') + op.drop_index('ix_caa_results_year_grade', table_name='caa_results') + op.drop_index('ix_caa_results_student_group', table_name='caa_results') + op.drop_table('caa_results') + op.drop_index('ix_altsa_elpac_results_year_grade', table_name='altsa_elpac_results') + op.drop_index('ix_altsa_elpac_results_student_group', table_name='altsa_elpac_results') + op.drop_table('altsa_elpac_results') + op.drop_index('ix_altia_elpac_results_year_grade', table_name='altia_elpac_results') + op.drop_index('ix_altia_elpac_results_student_group', table_name='altia_elpac_results') + op.drop_table('altia_elpac_results') + op.drop_index(op.f('ix_users_email'), table_name='users') + op.drop_table('users') + op.drop_index(op.f('ix_schools_cds_code'), table_name='schools') + op.drop_table('schools') + op.drop_table('entities') + op.drop_table('elpac_tests') + op.drop_table('elpac_student_groups') + op.drop_index(op.f('ix_census_data_cds_code'), table_name='census_data') + op.drop_index(op.f('ix_census_data_aggregation_level'), table_name='census_data') + op.drop_index(op.f('ix_census_data_academic_year'), table_name='census_data') + op.drop_table('census_data') + op.drop_table('caaspp_tests') + op.drop_table('caaspp_student_groups') + # ### end Alembic commands ### diff --git a/backend/app/alembic/versions/fe56fa70289e_add_created_at_to_user_and_item.py b/backend/app/alembic/versions/fe56fa70289e_add_created_at_to_user_and_item.py deleted file mode 100644 index 3e15754..0000000 --- a/backend/app/alembic/versions/fe56fa70289e_add_created_at_to_user_and_item.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Add created_at to User and Item - -Revision ID: fe56fa70289e -Revises: 1a31ce608336 -Create Date: 2026-01-23 15:50:37.171462 - -""" -from alembic import op -import sqlalchemy as sa -import sqlmodel.sql.sqltypes - - -# revision identifiers, used by Alembic. -revision = 'fe56fa70289e' -down_revision = '1a31ce608336' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('item', sa.Column('created_at', sa.DateTime(timezone=True), nullable=True)) - op.add_column('user', sa.Column('created_at', sa.DateTime(timezone=True), nullable=True)) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('user', 'created_at') - op.drop_column('item', 'created_at') - # ### end Alembic commands ### diff --git a/backend/app/api/deps.py b/backend/app/api/deps.py index 90a91dd..6a6fe22 100644 --- a/backend/app/api/deps.py +++ b/backend/app/api/deps.py @@ -11,7 +11,7 @@ from app.core import security from app.core.config import settings from app.core.database import engine -from app.model.models import TokenPayload +from app.model.other import TokenPayload from app.model.user import User reusable_oauth2 = OAuth2PasswordBearer( @@ -19,7 +19,7 @@ ) -def get_db() -> Generator[Session, None, None]: +def get_db() -> Generator[Session]: with Session(engine) as session: yield session @@ -34,7 +34,7 @@ def get_current_user(session: SessionDep, token: TokenDep) -> User: token, settings.SECRET_KEY, algorithms=[security.ALGORITHM] ) token_data = TokenPayload(**payload) - except (InvalidTokenError, ValidationError): + except InvalidTokenError, ValidationError: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Could not validate credentials", diff --git a/backend/app/api/main.py b/backend/app/api/main.py index 8f285bf..8cfd397 100644 --- a/backend/app/api/main.py +++ b/backend/app/api/main.py @@ -1,8 +1,8 @@ from fastapi import APIRouter from app.api.routes import ( - academic_indicators, censusdata, + dashboard, items, login, private, @@ -19,7 +19,7 @@ api_router.include_router(items.router) api_router.include_router(censusdata.router) api_router.include_router(schools.router, prefix="/schools", tags=["schools"]) -api_router.include_router(academic_indicators.router) +api_router.include_router(dashboard.router) if settings.ENVIRONMENT == "local": diff --git a/backend/app/api/routes/academic_indicators.py b/backend/app/api/routes/academic_indicators.py deleted file mode 100644 index 90d19f4..0000000 --- a/backend/app/api/routes/academic_indicators.py +++ /dev/null @@ -1,384 +0,0 @@ -import uuid -from typing import Any, cast - -from fastapi import APIRouter, HTTPException, Query -from sqlmodel import col, func, select - -from app.api.deps import CurrentUser, SessionDep -from app.model.academic_indicator import ( - AcademicIndicator, - AcademicIndicatorCreate, - AcademicIndicatorPublic, - AcademicIndicatorsPublic, - AcademicIndicatorUpdate, -) -from app.model.dashboard import ( - DashboardAggregation, - DashboardSummaryResponse, - EquityGroupSummary, - EquityReportResponse, - IndicatorSummary, -) -from app.model.models import ( - Message, -) -from app.model.user import UserPreferencesUpdate, UserPublic -from app.service.color_calculator import calculate_all - -router = APIRouter(prefix="/academic-indicators", tags=["academic-indicators"]) - - -@router.get("/", response_model=AcademicIndicatorsPublic) -def read_academic_indicators( - session: SessionDep, - skip: int = 0, - limit: int = 100, - cds: str | None = Query(default=None, description="Filter by CDS code"), - studentgroup: str | None = Query( - default=None, description="Filter by student group" - ), - reportingyear: str | None = Query( - default=None, description="Filter by reporting year" - ), -) -> Any: - """ - Retrieve academic indicators with optional filters. - """ - # Build base query - statement = select(AcademicIndicator) - count_statement = select(func.count()).select_from(AcademicIndicator) - - # Apply filters - if cds: - statement = statement.where(AcademicIndicator.cds == cds) - count_statement = count_statement.where(AcademicIndicator.cds == cds) - if studentgroup: - statement = statement.where(AcademicIndicator.studentgroup == studentgroup) - count_statement = count_statement.where( - AcademicIndicator.studentgroup == studentgroup - ) - if reportingyear: - statement = statement.where(AcademicIndicator.reportingyear == reportingyear) - count_statement = count_statement.where( - AcademicIndicator.reportingyear == reportingyear - ) - - count = session.exec(count_statement).one() - statement = ( - statement.order_by(col(AcademicIndicator.created_at).desc()) - .offset(skip) - .limit(limit) - ) - indicators = session.exec(statement).all() - - return AcademicIndicatorsPublic(data=indicators, count=count) - - -@router.get("/dashboard", response_model=DashboardAggregation) -def get_dashboard_data( - session: SessionDep, - q: str = Query(..., description="CDS code to query"), -) -> Any: - """ - Get aggregated dashboard data for a specific CDS code. - Returns the 'ALL' student group data for the most recent reporting year. - """ - # Query for the 'ALL' student group for the given CDS code - statement = ( - select(AcademicIndicator) - .where(AcademicIndicator.cds == q) - .where(AcademicIndicator.studentgroup == "ALL") - .order_by(col(AcademicIndicator.reportingyear).desc()) - .limit(1) - ) - indicator = session.exec(statement).first() - - if not indicator: - raise HTTPException( - status_code=404, - detail=f"No academic indicator data found for CDS code: {q}", - ) - - return DashboardAggregation( - cds=indicator.cds, - schoolname=indicator.schoolname, - districtname=indicator.districtname, - countyname=indicator.countyname, - studentgroup=indicator.studentgroup, - currstatus=_currstatus(indicator), - priorstatus=indicator.priorstatus, - change=indicator.change, - statuslevel=indicator.statuslevel, - changelevel=indicator.changelevel, - color=indicator.color, - indicator=indicator.indicator, - reportingyear=indicator.reportingyear, - ) - - -# List of all accountability indicators -ALL_INDICATORS = ["ELA", "MATH", "SCI", "CHRONIC", "SUSP", "GRAD", "ELPI", "CCI"] - -# Map color levels to color names -COLOR_NAMES = {1: "red", 2: "orange", 3: "yellow", 4: "green", 5: "blue", 0: "none"} - - -def _currstatus(indicator: AcademicIndicator) -> float | None: - return getattr(indicator, "currstatus", None) - - -def _currdenom(indicator: AcademicIndicator) -> int | None: - return getattr(indicator, "currdenom", None) - - -@router.get("/dashboard/summary", response_model=DashboardSummaryResponse) -def get_dashboard_summary( - session: SessionDep, - cds: str = Query( - ..., description="14-char CDS code or '00000000000000' for statewide" - ), - reportingyear: str = Query(default="2025", description="Reporting year"), - studentgroup: str = Query(default="ALL", description="Student group code"), -) -> Any: - """ - Get all indicator summaries for a school/district/state. - - Returns summary data for all 8 accountability indicators for the specified - CDS code, reporting year, and student group. - """ - # Query all indicators for the given cds, year, studentgroup - statement = ( - select(AcademicIndicator) - .where(AcademicIndicator.cds == cds) - .where(AcademicIndicator.reportingyear == reportingyear) - .where(AcademicIndicator.studentgroup == studentgroup) - ) - indicators = session.exec(statement).all() - - if not indicators: - raise HTTPException( - status_code=404, - detail=f"No indicator data found for CDS code: {cds}, year: {reportingyear}", - ) - - # Get basic info from the first indicator - first = indicators[0] - - # Build indicator summaries - indicator_summaries = [] - indicators_by_code = {ind.indicator: ind for ind in indicators} - - for code in ALL_INDICATORS: - ind = indicators_by_code.get(code) - if ind: - currstatus = _currstatus(ind) - currdenom = _currdenom(ind) - # Calculate colors on-the-fly if missing (for legacy/state data) - statuslevel = ind.statuslevel - changelevel = ind.changelevel - color = ind.color - change = ind.change - - if color is None and currstatus is not None: - # State assessment data has Mean Scale Score - convert to DFS - is_mean_scale = ( - code in ("ELA", "MATH") - and currstatus > 1000 # Mean scale scores are ~2400-2700 - ) - color_data = calculate_all( - indicator=code, - currstatus=currstatus, - priorstatus=ind.priorstatus, - is_mean_scale_score=is_mean_scale, - ) - statuslevel = cast(int | None, color_data["statuslevel"]) - changelevel = cast(int | None, color_data["changelevel"]) - color = cast(int | None, color_data["color"]) - change = cast(float | None, color_data["change"]) - - indicator_summaries.append( - IndicatorSummary( - indicator=code, - currstatus=currstatus, - priorstatus=ind.priorstatus, - change=change, - statuslevel=statuslevel, - changelevel=changelevel, - color=color, - currdenom=currdenom, - ) - ) - else: - # Return empty summary for missing indicators - indicator_summaries.append(IndicatorSummary(indicator=code)) - - return DashboardSummaryResponse( - cds=cds, - rtype=first.rtype, - schoolname=first.schoolname, - districtname=first.districtname, - countyname=first.countyname, - charter_flag=first.charter_flag, - reportingyear=reportingyear, - indicators=indicator_summaries, - ) - - -@router.get("/dashboard/equity", response_model=EquityReportResponse) -def get_equity_report( - session: SessionDep, - cds: str = Query(..., description="14-char CDS code"), - indicator: str = Query(..., description="Indicator code (ELA, MATH, etc.)"), - reportingyear: str = Query(default="2025", description="Reporting year"), -) -> Any: - """ - Get student group breakdown for an indicator. - - Returns color-coded performance data for all student groups within a - school/district/state for a specific indicator. - """ - # Query all studentgroups for given cds/indicator/year - statement = ( - select(AcademicIndicator) - .where(AcademicIndicator.cds == cds) - .where(AcademicIndicator.indicator == indicator) - .where(AcademicIndicator.reportingyear == reportingyear) - .where(AcademicIndicator.studentgroup != "ALL") # Exclude ALL group - ) - indicators = session.exec(statement).all() - - # Count groups by color level - color_counts = { - "red": 0, - "orange": 0, - "yellow": 0, - "green": 0, - "blue": 0, - "none": 0, - } - groups = [] - - for ind in indicators: - color_name = COLOR_NAMES.get(ind.color or 0, "none") - color_counts[color_name] += 1 - - groups.append( - EquityGroupSummary( - studentgroup=ind.studentgroup, - statuslevel=ind.statuslevel, - color=ind.color, - currdenom=_currdenom(ind), - ) - ) - - return EquityReportResponse( - cds=cds, - indicator=indicator, - reportingyear=reportingyear, - color_counts=color_counts, - groups=groups, - ) - - -@router.put("/users/me/preferences", response_model=UserPublic) -def update_user_preferences( - session: SessionDep, - current_user: CurrentUser, - preferences: UserPreferencesUpdate, -) -> Any: - """ - Update user preferences including last viewed school. - """ - if preferences.last_viewed_cds is not None: - current_user.last_viewed_cds = preferences.last_viewed_cds - - session.add(current_user) - session.commit() - session.refresh(current_user) - return current_user - - -@router.get("/users/me/preferences/last-viewed-cds") -def get_last_viewed_cds( - current_user: CurrentUser, -) -> dict[str, str | None]: - """ - Get the user's last viewed CDS code. - """ - return {"last_viewed_cds": current_user.last_viewed_cds} - - -@router.get("/{id}", response_model=AcademicIndicatorPublic) -def read_academic_indicator(session: SessionDep, id: uuid.UUID) -> Any: - """ - Get academic indicator by ID. - """ - indicator = session.get(AcademicIndicator, id) - if not indicator: - raise HTTPException(status_code=404, detail="Academic indicator not found") - return indicator - - -@router.post("/", response_model=AcademicIndicatorPublic) -def create_academic_indicator( - *, - session: SessionDep, - current_user: CurrentUser, - indicator_in: AcademicIndicatorCreate, -) -> Any: - """ - Create new academic indicator. Superuser only. - """ - if not current_user.is_superuser: - raise HTTPException(status_code=403, detail="Not enough permissions") - - indicator = AcademicIndicator.model_validate(indicator_in) - session.add(indicator) - session.commit() - session.refresh(indicator) - return indicator - - -@router.put("/{id}", response_model=AcademicIndicatorPublic) -def update_academic_indicator( - *, - session: SessionDep, - current_user: CurrentUser, - id: uuid.UUID, - indicator_in: AcademicIndicatorUpdate, -) -> Any: - """ - Update an academic indicator. Superuser only. - """ - if not current_user.is_superuser: - raise HTTPException(status_code=403, detail="Not enough permissions") - - indicator = session.get(AcademicIndicator, id) - if not indicator: - raise HTTPException(status_code=404, detail="Academic indicator not found") - - update_dict = indicator_in.model_dump(exclude_unset=True) - indicator.sqlmodel_update(update_dict) - session.add(indicator) - session.commit() - session.refresh(indicator) - return indicator - - -@router.delete("/{id}") -def delete_academic_indicator( - session: SessionDep, current_user: CurrentUser, id: uuid.UUID -) -> Message: - """ - Delete an academic indicator. Superuser only. - """ - if not current_user.is_superuser: - raise HTTPException(status_code=403, detail="Not enough permissions") - - indicator = session.get(AcademicIndicator, id) - if not indicator: - raise HTTPException(status_code=404, detail="Academic indicator not found") - - session.delete(indicator) - session.commit() - return Message(message="Academic indicator deleted successfully") diff --git a/backend/app/api/routes/censusdata.py b/backend/app/api/routes/censusdata.py index 578bc40..f58421c 100644 --- a/backend/app/api/routes/censusdata.py +++ b/backend/app/api/routes/censusdata.py @@ -6,7 +6,7 @@ from app.api.deps import CurrentUser, SessionDep from app.model.census_data import CensusData -from app.model.models import Message # noqa +from app.model.other import Message # noqa router = APIRouter(prefix="/censusdata", tags=["censusdata"]) @@ -55,7 +55,7 @@ def create_census_data( if not current_user.is_superuser: raise HTTPException(status_code=403, detail="Not enough permissions") - census_data = CensusData.from_orm(census_data_in) + census_data = CensusData.model_validate(census_data_in) session.add(census_data) session.commit() session.refresh(census_data) @@ -81,7 +81,7 @@ def update_census_data( if not census_data: raise HTTPException(status_code=404, detail="Census data not found") - new_census_data = CensusData.from_orm(census_data_in) + new_census_data = CensusData.model_validate(census_data_in) session.add(new_census_data) session.commit() session.refresh(new_census_data) diff --git a/backend/app/api/routes/dashboard.py b/backend/app/api/routes/dashboard.py new file mode 100644 index 0000000..feb1260 --- /dev/null +++ b/backend/app/api/routes/dashboard.py @@ -0,0 +1,309 @@ +from decimal import Decimal +from typing import Any + +from fastapi import APIRouter, Query +from sqlalchemy import case, func +from sqlmodel import or_, select + +from app.api.deps import SessionDep +from app.model.assessments import ( + CaasppStudentGroup, + CastResult, + ElpacStudentGroup, + IaElpacResult, + SbResult, +) +from app.model.dashboard import ( + DashboardSummaryResponse, + EquityGroupSummary, + EquityReportResponse, + IndicatorSummary, +) + +router = APIRouter(prefix="/dashboard", tags=["dashboard"]) + +STATEWIDE_CDS = "00000000000000" +ALL_STUDENTS_GROUPS = {"ALL", "1"} +ALL_STUDENTS_LABELS = {"all students", "all student"} + + +def _normalize_cds(cds: str) -> str: + normalized_cds = cds.strip() + return normalized_cds or STATEWIDE_CDS + + +def _normalize_student_group(student_group: str) -> str: + normalized_group = student_group.strip() + return "ALL" if normalized_group.upper() in ALL_STUDENTS_GROUPS else normalized_group + + +def _stringify_number(value: Decimal | int | None) -> str | None: + return None if value is None else str(value) + + +def _float_or_zero(value: Decimal | None) -> float: + return 0.0 if value is None else float(value) + + +def _resolve_caaspp_student_group_ids( + session: SessionDep, student_group: str +) -> list[str]: + normalized_group = _normalize_student_group(student_group) + if normalized_group != "ALL": + return [normalized_group] + + rows = session.exec( + select(CaasppStudentGroup.demographic_id).where( + func.lower(func.coalesce(CaasppStudentGroup.student_group, "")).in_( + ALL_STUDENTS_LABELS + ) + | func.lower(func.coalesce(CaasppStudentGroup.demographic_name, "")).in_( + ALL_STUDENTS_LABELS + ) + ) + ).all() + + candidate_ids = {row for row in rows if row} + candidate_ids.add("1") + return sorted(candidate_ids) + + +def _resolve_elpac_student_group_ids( + session: SessionDep, student_group: str +) -> list[str]: + normalized_group = _normalize_student_group(student_group) + if normalized_group != "ALL": + return [normalized_group] + + rows = session.exec( + select(ElpacStudentGroup.student_group_id).where( + func.lower(func.coalesce(ElpacStudentGroup.student_group_name, "")).in_( + ALL_STUDENTS_LABELS + ) + ) + ).all() + + candidate_ids = {row for row in rows if row} + candidate_ids.add("1") + return sorted(candidate_ids) + + +@router.get("/summary", response_model=DashboardSummaryResponse) +def get_dashboard_summary( + session: SessionDep, + cds: str, + reporting_year: str = Query("2025", alias="reportingYear"), + student_group: str = Query("ALL", alias="studentGroup"), +) -> Any: + """ + Get all test summaries for a CDS code within a specific reporting year and student group. + """ + indicators = [] + + # Standardize CDS code + cds_code = _normalize_cds(cds) + caaspp_student_group_ids = _resolve_caaspp_student_group_ids(session, student_group) + elpac_student_group_ids = _resolve_elpac_student_group_ids(session, student_group) + + # 1. Fetch Smarter Balanced (ELA/Math) + # Build the CDS filter condition + # If Statewide, also include records where cds_code is NULL (orphaned statewide data) + if cds_code == STATEWIDE_CDS: + cds_filter = or_(SbResult.cds_code == cds_code, SbResult.cds_code == None) + else: + cds_filter = SbResult.cds_code == cds_code + + # ELA (testId = 1), Math (testId = 2) + sb_results = session.exec( + select(SbResult).where( + cds_filter, + SbResult.test_year == int(reporting_year), + SbResult.student_group_id.in_(caaspp_student_group_ids), + ) + ).all() + for sb_row in sb_results: + ind = IndicatorSummary( + test_id=str(sb_row.test_id), + test_type=str(sb_row.test_type) if sb_row.test_type else "SB", + grade=str(sb_row.grade) if sb_row.grade is not None else "13", + students_enrolled=str(sb_row.total_students_enrolled or 0), + students_tested=str(sb_row.total_students_tested or 0), + overall_mean_scale_score=_stringify_number(sb_row.mean_scale_score), + overall_met_and_above_pct=_stringify_number( + sb_row.percentage_standard_met_and_above + ), + levels={ + "Standard Not Met (Level 1)": _float_or_zero( + sb_row.percentage_standard_not_met + ), + "Standard Nearly Met (Level 2)": _float_or_zero( + sb_row.percentage_standard_nearly_met + ), + "Standard Met (Level 3)": _float_or_zero(sb_row.percentage_standard_met), + "Standard Exceeded (Level 4)": _float_or_zero( + sb_row.percentage_standard_exceeded + ), + }, + ) + indicators.append(ind) + + # 2. Fetch Science (CAST) (usually testId = 3 or 4) + if cds_code == STATEWIDE_CDS: + cast_filter = or_(CastResult.cds_code == cds_code, CastResult.cds_code == None) + else: + cast_filter = CastResult.cds_code == cds_code + + cast_results = session.exec( + select(CastResult).where( + cast_filter, + CastResult.test_year == int(reporting_year), + CastResult.student_group_id.in_(caaspp_student_group_ids), + ) + ).all() + for cast_row in cast_results: + ind = IndicatorSummary( + test_id="3", # Usually 3 or 4 + test_type="CAST", + grade=str(cast_row.grade) if cast_row.grade is not None else "13", + students_enrolled=str(cast_row.total_students_enrolled or 0), + students_tested=str(cast_row.total_students_tested or 0), + overall_mean_scale_score=_stringify_number(cast_row.mean_scale_score), + overall_met_and_above_pct=_stringify_number( + cast_row.percentage_standard_met_and_above + ), + levels={ + "Standard Not Met (Level 1)": _float_or_zero( + cast_row.percentage_standard_not_met + ), + "Standard Nearly Met (Level 2)": _float_or_zero( + cast_row.percentage_standard_nearly_met + ), + "Standard Met (Level 3)": _float_or_zero(cast_row.percentage_standard_met), + "Standard Exceeded (Level 4)": _float_or_zero( + cast_row.percentage_standard_exceeded + ), + }, + ) + indicators.append(ind) + + # 3. Fetch Initial ELPAC + if cds_code == STATEWIDE_CDS: + elpac_filter = or_(IaElpacResult.cds_code == cds_code, IaElpacResult.cds_code == None) + else: + elpac_filter = IaElpacResult.cds_code == cds_code + + elpac_results = session.exec( + select(IaElpacResult).where( + elpac_filter, + IaElpacResult.test_year == int(reporting_year), + IaElpacResult.student_group_id.in_(elpac_student_group_ids), + ) + ).all() + for elpac_row in elpac_results: + ind = IndicatorSummary( + test_id="elpac_initial", + test_type="ELPAC", + grade=str(elpac_row.grade) if elpac_row.grade is not None else "13", + students_enrolled=str(elpac_row.total_students_enrolled or 0), + students_tested=str(elpac_row.total_students_tested or 0), + overall_mean_scale_score=_stringify_number( + elpac_row.overall_mean_scale_score + ), + overall_met_and_above_pct=None, + levels={ + "Novice English Learner": _float_or_zero( + elpac_row.novice_el_perf_lvl_pcnt + ), + "Intermediate English Learner": _float_or_zero( + elpac_row.intermediate_el_perf_lvl_pcnt + ), + "Initial Fluent English Proficient (IFEP)": _float_or_zero( + elpac_row.ifep_perf_lvl_pcnt + ), + }, + ) + indicators.append(ind) + + return {"cds": cds_code, "test_year": reporting_year, "indicators": indicators} + + +@router.get("/equity", response_model=EquityReportResponse) +def get_equity_report( + session: SessionDep, + cds: str, + test_id: str = Query(..., alias="testId"), + reporting_year: str = Query("2025", alias="reportingYear"), +) -> Any: + """ + Get student group breakdown for a specific test and CDS code. + """ + groups = [] + + # Map student group IDs to names + student_groups_map = { + row.demographic_id: row.student_group or row.demographic_name or row.demographic_id + for row in session.exec(select(CaasppStudentGroup)).all() + } + + # Standardize CDS code + cds_code = _normalize_cds(cds) + + # Build the CDS filter condition + if cds_code == STATEWIDE_CDS: + cds_filter = or_(SbResult.cds_code == cds_code, SbResult.cds_code == None) + else: + cds_filter = SbResult.cds_code == cds_code + + if test_id.isdigit(): + weighted_students = func.sum( + case( + ( + SbResult.percentage_standard_met_and_above.is_not(None), + func.coalesce(SbResult.total_students_tested, 0), + ), + else_=0, + ) + ) + weighted_pct = ( + func.sum( + func.coalesce(SbResult.percentage_standard_met_and_above, 0) + * func.coalesce(SbResult.total_students_tested, 0) + ) + / func.nullif(weighted_students, 0) + ) + + aggregated_results = session.exec( + select( + SbResult.student_group_id, + func.sum(func.coalesce(SbResult.total_students_tested, 0)).label( + "students_tested" + ), + weighted_pct.label("overall_met_and_above_pct"), + ).where( + cds_filter, + SbResult.test_id == int(test_id), + SbResult.test_year == int(reporting_year), + ).group_by(SbResult.student_group_id) + ).all() + + for student_group_id, students_tested, overall_met_and_above_pct in aggregated_results: + group_name = ( + student_groups_map.get(student_group_id) + or f"Group {student_group_id}" + ) + groups.append( + EquityGroupSummary( + student_group=group_name, + overall_met_and_above_pct=_stringify_number( + overall_met_and_above_pct + ), + students_tested=str(students_tested or 0), + ) + ) + + return { + "cds": cds_code, + "test_id": test_id, + "test_year": reporting_year, + "groups": groups, + } diff --git a/backend/app/api/routes/items.py b/backend/app/api/routes/items.py index 884213e..aec0244 100644 --- a/backend/app/api/routes/items.py +++ b/backend/app/api/routes/items.py @@ -6,7 +6,7 @@ from app.api.deps import CurrentUser, SessionDep from app.model.item import Item, ItemCreate, ItemPublic, ItemsPublic, ItemUpdate -from app.model.models import ( +from app.model.other import ( Message, ) @@ -44,7 +44,9 @@ def read_items( ) items = session.exec(statement).all() - return ItemsPublic(data=items, count=count) + return ItemsPublic( + data=[ItemPublic.model_validate(item) for item in items], count=count + ) @router.get("/{id}", response_model=ItemPublic) diff --git a/backend/app/api/routes/login.py b/backend/app/api/routes/login.py index 5b3e4f7..cda0289 100644 --- a/backend/app/api/routes/login.py +++ b/backend/app/api/routes/login.py @@ -15,7 +15,7 @@ send_email, verify_password_reset_token, ) -from app.model.models import Message, Token +from app.model.other import Message, Token from app.model.user import ( ForcePasswordResetRequest, NewPassword, @@ -33,15 +33,21 @@ def login_access_token( session: SessionDep, form_data: Annotated[OAuth2PasswordRequestForm, Depends()] ) -> Token: """ - OAuth2 compatible token login, get an access token for future requests + 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") + raise HTTPException( + status_code=400, + detail="The email or password provided is incorrect. Please double-check and try again.", + ) elif not user.is_active: - raise HTTPException(status_code=400, detail="Inactive user") + raise HTTPException( + status_code=400, + detail="This account is currently inactive. Please contact support for assistance.", + ) access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) return Token( access_token=security.create_access_token( @@ -53,7 +59,7 @@ def login_access_token( @router.post("/login/test-token", response_model=UserPublic) def test_token(current_user: CurrentUser) -> Any: """ - Test access token + Test access token. """ return current_user @@ -61,12 +67,9 @@ def test_token(current_user: CurrentUser) -> Any: @router.post("/password-recovery/{email}") def recover_password(email: str, session: SessionDep) -> Message: """ - Password Recovery + Password recovery. Always return the same response to prevent email enumeration attacks. Only send email if user actually exists. """ user = crud.get_user_by_email(session=session, email=email) - - # Always return the same response to prevent email enumeration attacks - # Only send email if user actually exists if user: password_reset_token = generate_password_reset_token(email=email) email_data = generate_reset_password_email( @@ -78,31 +81,47 @@ def recover_password(email: str, session: SessionDep) -> Message: html_content=email_data.html_content, ) return Message( - message="If that email is registered, we sent a password recovery link" + message="If an account exists for that email, a password recovery link has been sent. Please check your inbox and spam folder.", + success=True, + status="Success", + code=200, ) @router.post("/reset-password/") def reset_password(session: SessionDep, body: NewPassword) -> Message: """ - Reset password + Reset password. Don't reveal that the user doesn't exist - use same error as invalid token. """ email = verify_password_reset_token(token=body.token) if not email: - raise HTTPException(status_code=400, detail="Invalid token") + raise HTTPException( + status_code=400, + detail="The password reset token is invalid or has expired.", + ) user = crud.get_user_by_email(session=session, email=email) if not user: - # Don't reveal that the user doesn't exist - use same error as invalid token - raise HTTPException(status_code=400, detail="Invalid token") + raise HTTPException( + status_code=400, + detail="The password reset token is invalid or has expired.", + ) elif not user.is_active: - raise HTTPException(status_code=400, detail="Inactive user") + raise HTTPException( + status_code=400, + detail="This account is currently inactive. Please contact support for assistance.", + ) user_in_update = UserUpdate(password=body.new_password) crud.update_user( session=session, db_user=user, user_in=user_in_update, ) - return Message(message="Password updated successfully") + return Message( + message="Your password has been updated successfully. You can now log in.", + success=True, + status="Success", + code=200, + ) @router.post( @@ -112,20 +131,18 @@ def reset_password(session: SessionDep, body: NewPassword) -> Message: ) def recover_password_html_content(email: str, session: SessionDep) -> Any: """ - HTML Content for Password Recovery + 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.", + detail="We could not find a user with the provided email address in our 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} ) @@ -145,22 +162,19 @@ def force_password_reset_for_users( if not body.emails and not body.include_all_active_users: raise HTTPException( status_code=400, - detail="Provide emails or set include_all_active_users=true", + detail="Provide emails or set include_all_active_users=true.", ) - users_by_id: dict[str, User] = {} if body.include_all_active_users: active_users = session.exec( select(User).where(col(User.is_active).is_(True)) ).all() users_by_id.update({str(user.id): user for user in active_users}) - if body.emails: - targeted_users = session.exec( + targetedUsers = session.exec( select(User).where(col(User.email).in_(body.emails)) ).all() - users_by_id.update({str(user.id): user for user in targeted_users}) - + users_by_id.update({str(user.id): user for user in targetedUsers}) flagged_count = 0 for user in users_by_id.values(): if user.force_password_reset: @@ -168,8 +182,10 @@ def force_password_reset_for_users( user.force_password_reset = True session.add(user) flagged_count += 1 - session.commit() return Message( - message=f"Forced password reset for {flagged_count} user(s) out of {len(users_by_id)} targeted account(s)" + message=f"Successfully forced password reset for {flagged_count} user(s) out of {len(users_by_id)} targeted account(s).", + success=True, + status="Success", + code=200, ) diff --git a/backend/app/api/routes/schools.py b/backend/app/api/routes/schools.py index 4f57acc..f72fb2f 100644 --- a/backend/app/api/routes/schools.py +++ b/backend/app/api/routes/schools.py @@ -4,7 +4,13 @@ from sqlmodel import func, select from app.api.deps import SessionDep -from app.model.school import School, SchoolsPublic, SchoolsSummary +from app.model.school import ( + School, + SchoolPublic, + SchoolsPublic, + SchoolsSummary, + SchoolSummary, +) router = APIRouter() @@ -33,7 +39,9 @@ def read_schools( schools = session.exec(statement).all() count = len(schools) - return SchoolsPublic(data=schools, count=count) + return SchoolsPublic( + data=[SchoolPublic.model_validate(school) for school in schools], count=count + ) @router.get("/summary", response_model=SchoolsSummary) @@ -60,4 +68,6 @@ def read_schools_summary( schools = session.exec(statement).all() count = len(schools) - return SchoolsSummary(data=schools, count=count) + return SchoolsSummary( + data=[SchoolSummary.model_validate(school) for school in schools], count=count + ) diff --git a/backend/app/api/routes/users.py b/backend/app/api/routes/users.py index 0562396..df031ce 100644 --- a/backend/app/api/routes/users.py +++ b/backend/app/api/routes/users.py @@ -13,13 +13,14 @@ from app.core.security import get_password_hash, verify_password from app.core.utils import generate_new_account_email, send_email from app.model.item import Item -from app.model.models import ( +from app.model.other import ( Message, ) from app.model.user import ( UpdatePassword, User, UserCreate, + UserPreferencesUpdate, UserPublic, UserRegister, UsersPublic, @@ -48,8 +49,9 @@ def read_users(session: SessionDep, skip: int = 0, limit: int = 100) -> Any: select(User).order_by(col(User.created_at).desc()).offset(skip).limit(limit) ) users = session.exec(statement).all() - - return UsersPublic(data=users, count=count) + return UsersPublic( + data=[UserPublic.model_validate(user) for user in users], count=count + ) @router.post( @@ -68,13 +70,13 @@ def create_user(*, session: SessionDep, user_in: UserCreate) -> Any: user = crud.create_user(session=session, user_create=user_in) if settings.emails_enabled and user_in.email: - email_data = generate_new_account_email( + emailData = 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, + subject=emailData.subject, + html_content=emailData.html_content, ) return user @@ -93,8 +95,8 @@ def update_user_me( 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) + userData = user_in.model_dump(exclude_unset=True) + current_user.sqlmodel_update(userData) session.add(current_user) session.commit() session.refresh(current_user) @@ -145,6 +147,28 @@ def delete_user_me(session: SessionDep, current_user: CurrentUser) -> Any: return Message(message="User deleted successfully") +@router.get("/me/preferences", response_model=UserPreferencesUpdate) +def get_user_preferences(current_user: CurrentUser) -> Any: + """ + Get current user's preferences. + """ + return UserPreferencesUpdate(last_viewed_cds=current_user.last_viewed_cds) + + +@router.patch("/me/preferences", response_model=UserPublic) +def update_user_preferences( + *, session: SessionDep, user_in: UserPreferencesUpdate, current_user: CurrentUser +) -> Any: + """ + Update own user's preferences. + """ + current_user.last_viewed_cds = user_in.last_viewed_cds + session.add(current_user) + session.commit() + session.refresh(current_user) + return current_user + + @router.post("/signup", response_model=UserPublic) def register_user(session: SessionDep, user_in: UserRegister) -> Any: """ @@ -156,8 +180,8 @@ def register_user(session: SessionDep, user_in: UserRegister) -> Any: 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) + userCreate = UserCreate.model_validate(user_in) + user = crud.create_user(session=session, user_create=userCreate) return user @@ -196,21 +220,21 @@ def update_user( Update a user. """ - db_user = session.get(User, user_id) - if not db_user: + dbUser = session.get(User, user_id) + if not dbUser: 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: + existingUser = crud.get_user_by_email(session=session, email=user_in.email) + if existingUser and existingUser.id != user_id: raise HTTPException( status_code=409, detail="User with this email already exists" ) - db_user = crud.update_user(session=session, db_user=db_user, user_in=user_in) - return db_user + dbUser = crud.update_user(session=session, db_user=dbUser, user_in=user_in) + return dbUser @router.delete("/{user_id}", dependencies=[Depends(get_current_active_superuser)]) diff --git a/backend/app/api/routes/utils.py b/backend/app/api/routes/utils.py index fa5e5c9..860aa59 100644 --- a/backend/app/api/routes/utils.py +++ b/backend/app/api/routes/utils.py @@ -3,7 +3,7 @@ from app.api.deps import get_current_active_superuser from app.core.utils import generate_test_email, send_email -from app.model.models import Message +from app.model.other import Message router = APIRouter(prefix="/utils", tags=["utils"]) diff --git a/backend/app/core/config.py b/backend/app/core/config.py index a4a5443..0fdb735 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -2,7 +2,7 @@ import secrets import warnings from pathlib import Path -from typing import Annotated, Any, Literal +from typing import Annotated, Any, Literal, Self from urllib.parse import quote_plus from pydantic import ( @@ -14,7 +14,6 @@ model_validator, ) from pydantic_settings import BaseSettings, SettingsConfigDict -from typing_extensions import Self def parse_cors(v: Any) -> list[str] | str: @@ -27,8 +26,8 @@ def parse_cors(v: Any) -> list[str] | str: class Settings(BaseSettings): """ - Use the top level .env file (one level above ./backend/). - Access not expires in 60 minutes * 24 hours * 8 days = 8 days + Use the .env file in the root of the repository. + Access token expires in 8 days (60 seconds * 24 seconds * 8 seconds). """ model_config = SettingsConfigDict( @@ -46,7 +45,7 @@ class Settings(BaseSettings): list[AnyUrl] | str, BeforeValidator(parse_cors) ] = [] - @computed_field # type: ignore[prop-decorator] + @computed_field @property def all_cors_origins(self) -> list[str]: return [str(origin).rstrip("/") for origin in self.BACKEND_CORS_ORIGINS] + [ @@ -64,7 +63,7 @@ def all_cors_origins(self) -> list[str]: POSTGRES_DB: str | None = None CLOUD_SQL_INSTANCE_CONNECTION_NAME: str | None = None - @computed_field # type: ignore[prop-decorator] + @computed_field @property def SQLALCHEMY_DATABASE_URI(self) -> str: if not self.DATABASE_URL: @@ -88,7 +87,7 @@ def _set_default_emails_from(self) -> Self: EMAIL_RESET_TOKEN_EXPIRE_HOURS: int = 48 - @computed_field # type: ignore[prop-decorator] + @computed_field @property def emails_enabled(self) -> bool: return bool(self.SMTP_HOST and self.EMAILS_FROM_EMAIL) @@ -114,7 +113,9 @@ def _check_default_secret(self, var_name: str, value: str | None) -> None: @model_validator(mode="after") def _enforce_non_default_secrets(self) -> Self: self._check_default_secret("SECRET_KEY", self.SECRET_KEY) - self._check_default_secret("FIRST_SUPERUSER_PASSWORD", self.SECRET_KEY) + self._check_default_secret( + "FIRST_SUPERUSER_PASSWORD", self.FIRST_SUPERUSER_PASSWORD + ) return self @model_validator(mode="after") diff --git a/backend/app/core/security.py b/backend/app/core/security.py index 1e49ebc..6d31396 100644 --- a/backend/app/core/security.py +++ b/backend/app/core/security.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from typing import Any import jwt @@ -15,12 +15,11 @@ ) ) - ALGORITHM = "HS256" def create_access_token(subject: str | Any, expires_delta: timedelta) -> str: - expire = datetime.now(timezone.utc) + expires_delta + expire = datetime.now(UTC) + expires_delta to_encode = {"exp": expire, "sub": str(subject)} encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt diff --git a/backend/app/core/utils.py b/backend/app/core/utils.py index 5c4d40e..471b4de 100644 --- a/backend/app/core/utils.py +++ b/backend/app/core/utils.py @@ -7,11 +7,11 @@ import logging import os from dataclasses import dataclass -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from pathlib import Path -from typing import Any +from typing import Any, cast -import emails # type: ignore +import emails import jwt from jinja2 import Template from jwt.exceptions import InvalidTokenError @@ -118,7 +118,7 @@ def send_email( message = emails.Message( subject=subject, html=html_content, - mail_from=(settings.EMAILS_FROM_NAME, settings.EMAILS_FROM_EMAIL), + mail_from=(settings.EMAILS_FROM_NAME, cast(str, settings.EMAILS_FROM_EMAIL)), ) smtp_options: dict[str, Any] = { "host": settings.SMTP_HOST, @@ -227,7 +227,7 @@ def generate_password_reset_token(email: str) -> str: The encoded JWT string. """ delta = timedelta(hours=settings.EMAIL_RESET_TOKEN_EXPIRE_HOURS) - now = datetime.now(timezone.utc) + now = datetime.now(UTC) expires = now + delta exp = expires.timestamp() encoded_jwt = jwt.encode( @@ -268,4 +268,4 @@ def get_datetime_utc() -> datetime: Returns: A timezone-aware :class:`datetime.datetime` in UTC. """ - return datetime.now(timezone.utc) + return datetime.now(UTC) diff --git a/backend/app/data_import.py b/backend/app/data_import.py deleted file mode 100644 index 234c18a..0000000 --- a/backend/app/data_import.py +++ /dev/null @@ -1,237 +0,0 @@ -"""Startup data-import pipeline. - -Orchestrates syncing resources from Google Cloud Storage and importing -academic-indicator data (ELA scores, CDE indicators) into the database. -The pipeline is designed to run once on application startup, optionally -guarded by a PostgreSQL advisory lock to prevent concurrent imports -across multiple instances. -""" - -import os -import subprocess -import sys -import threading -from pathlib import Path - -import httpx -from sqlalchemy import func, text -from sqlmodel import Session, select - -from app.core.config import settings -from app.core.database import engine -from app.core.utils import env_bool, parse_csv_set -from app.model.academic_indicator import AcademicIndicator - -IMPORT_LOCK_KEY = 580083315 -"""PostgreSQL advisory-lock key used to serialise concurrent imports.""" - - -def sync_resources(gcs_uri: str, destination: Path) -> int: - """Download objects from a Google Cloud Storage URI to a local directory. - - The *destination* directory is created if it does not already exist. - Uses :mod:`app.scripts.gcp.sync_gcs_resources` for the actual GCS - interaction. - - Args: - gcs_uri: A ``gs://`` URI pointing to the source bucket/prefix. - destination: Local directory to write the downloaded objects into. - - Returns: - The number of objects downloaded. - """ - from app.scripts.gcp.sync_gcs_resources import ( - download_objects, - get_access_token, - list_objects, - parse_gs_uri, - ) - - destination.mkdir(parents=True, exist_ok=True) - bucket, prefix = parse_gs_uri(gcs_uri) - with httpx.Client(follow_redirects=True) as client: - token = get_access_token(client) - objects = list_objects(client, token, bucket, prefix) - return download_objects(client, token, bucket, prefix, destination, objects) - - -def academic_indicator_count() -> int: - """Return the number of rows currently in the ``academic_indicator`` table. - - Returns: - Row count as an integer (``0`` if the table is empty). - """ - with Session(engine) as session: - count = session.exec(select(func.count()).select_from(AcademicIndicator)).one() - return int(count or 0) - - -def run_data_import_pipeline() -> None: - """Execute the full data-import pipeline. - - Steps performed (in order): - - 1. Sync resources from GCS to a local directory. - 2. Skip remaining steps if the ``academic_indicator`` table is already - populated. - 3. Import ELA data from Excel files. - 4. Import CDE indicator data via a subprocess. - - The pipeline can be disabled entirely by setting the - ``RUN_DATA_IMPORTS`` environment variable to a falsy value. - """ - if not env_bool("RUN_DATA_IMPORTS", True): - print("RUN_DATA_IMPORTS is disabled; skipping startup data import pipeline") - return - - gcs_uri = os.getenv("IMPORT_GCS_URI", "") - resources_dir = Path(os.getenv("IMPORT_RESOURCES_LOCAL_PATH", "/tmp/resources")) - downloaded = sync_resources(gcs_uri, resources_dir) - print(f"Synced {downloaded} object(s) from {gcs_uri} to {resources_dir}") - - existing_count = academic_indicator_count() - if existing_count > 0: - print( - "academic_indicator already populated " - f"({existing_count} rows); skipping import steps" - ) - return - - _import_ela_data(resources_dir) - _import_indicators(resources_dir) - - -def _import_ela_data(resources_dir: Path) -> None: - """Import ELA data from one or more Excel files. - - File paths are resolved from the ``IMPORT_ELA_FILES`` or - ``IMPORT_ELA_DATA_FILE`` environment variables. Falls back to - ``/cde/eladownload2025.xlsx``. - - Args: - resources_dir: Base directory where synced resources are stored. - """ - from app.scripts.cde.import_ela_data import import_ela_data - - ela_batch_size = int(os.getenv("IMPORT_ELA_BATCH_SIZE", "5000")) - ela_files_env = os.getenv("IMPORT_ELA_FILES", "").strip() - if ela_files_env: - ela_files = [Path(p.strip()) for p in ela_files_env.split(",") if p.strip()] - else: - ela_file = Path( - os.getenv( - "IMPORT_ELA_DATA_FILE", - str(resources_dir / "cde" / "eladownload2025.xlsx"), - ) - ) - ela_files = [ela_file] - - for ela_path in ela_files: - if ela_path.exists(): - print(f"Importing ELA data from {ela_path}") - import_ela_data(str(ela_path), batch_size=ela_batch_size) - else: - print(f"ELA file not found at {ela_path}; skipping") - - -def _import_indicators(resources_dir: Path) -> None: - """Import CDE indicator data by invoking the import script as a subprocess. - - Configuration is read from environment variables prefixed with - ``IMPORT_INDICATORS_``. - - Args: - resources_dir: Base directory where synced resources are stored. - """ - source = os.getenv("IMPORT_INDICATORS_SOURCE", "cde").strip().lower() - indicators_path = Path( - os.getenv("IMPORT_INDICATORS_PATH", str(resources_dir / "cde")) - ).expanduser() - batch_size = int(os.getenv("IMPORT_INDICATORS_BATCH_SIZE", "5000")) - years_filter = parse_csv_set(os.getenv("IMPORT_INDICATORS_YEARS", "2024,2025")) - indicator = os.getenv("IMPORT_INDICATORS_INDICATOR", "").strip().upper() - indicators = [indicator] if indicator else None - - if not indicators_path.exists(): - print( - f"Indicators path not found at {indicators_path}; " - "skipping indicators import" - ) - return - - command = [ - sys.executable, - "app/scripts/cde/import_indicators.py", - "--source", - source, - "--path", - str(indicators_path), - "--batch-size", - str(batch_size), - "--all-files", - ] - if indicators: - command.extend(["--indicator", indicators[0]]) - if years_filter: - command.extend(["--years", ",".join(sorted(years_filter))]) - - subprocess.run(command, check=True) - print("Indicators import completed") - - -def run_data_import_pipeline_with_lock() -> None: - """Run the data-import pipeline with a PostgreSQL advisory lock. - - On non-PostgreSQL databases the pipeline is executed directly without - locking. On PostgreSQL, ``pg_try_advisory_lock`` is used so that - only one application instance performs the import at a time. - """ - db_uri = settings.SQLALCHEMY_DATABASE_URI.lower() - if not db_uri.startswith("postgresql"): - run_data_import_pipeline() - return - - with engine.connect() as conn: - acquired = bool( - conn.execute( - text("SELECT pg_try_advisory_lock(:lock_key)"), - {"lock_key": IMPORT_LOCK_KEY}, - ).scalar_one() - ) - if not acquired: - print("Another instance is running startup data import; skipping this run") - return - - try: - run_data_import_pipeline() - finally: - conn.execute( - text("SELECT pg_advisory_unlock(:lock_key)"), - {"lock_key": IMPORT_LOCK_KEY}, - ) - - -def startup_data_import() -> None: - """Entry point called from the application lifespan to trigger data imports. - - Behaviour is controlled by two environment variables: - - * ``RUN_STARTUP_DATA_IMPORTS`` — master switch (default ``False``). - * ``RUN_DATA_IMPORTS_BLOCKING`` — when ``True``, the import runs - synchronously on the main thread; otherwise it runs in a daemon - thread so the application can start accepting requests immediately. - """ - if not env_bool("RUN_STARTUP_DATA_IMPORTS", False): - print("RUN_STARTUP_DATA_IMPORTS is disabled; skipping startup data import") - return - - if env_bool("RUN_DATA_IMPORTS_BLOCKING", False): - run_data_import_pipeline_with_lock() - return - - thread = threading.Thread( - target=run_data_import_pipeline_with_lock, - name="startup-data-import", - daemon=True, - ) - thread.start() diff --git a/backend/app/main.py b/backend/app/main.py index 0176f79..dae564b 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -8,14 +8,13 @@ from collections.abc import AsyncGenerator from contextlib import asynccontextmanager -import sentry_sdk from fastapi import FastAPI from fastapi.routing import APIRoute from starlette.middleware.cors import CORSMiddleware from app.api.main import api_router from app.core.config import settings -from app.data_import import startup_data_import +from app.scripts.initial_data import main as init_data_main def custom_generate_unique_id(route: APIRoute) -> str: @@ -34,12 +33,12 @@ def custom_generate_unique_id(route: APIRoute) -> str: return f"{tag}-{route.name}" -if settings.SENTRY_DSN and settings.ENVIRONMENT != "local": - sentry_sdk.init(dsn=str(settings.SENTRY_DSN), enable_tracing=True) +# if settings.SENTRY_DSN and settings.ENVIRONMENT != "local": +# sentry_sdk.init(dsn=str(settings.SENTRY_DSN), enable_tracing=True) @asynccontextmanager -async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: # noqa: ARG001 +async def lifespan(app: FastAPI) -> AsyncGenerator[None]: # noqa: ARG001 """Manage application startup and shutdown events. On startup the data-import pipeline is triggered (subject to @@ -51,7 +50,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: # noqa: ARG001 Yields: Control to the running application between startup and shutdown. """ - startup_data_import() + init_data_main() yield diff --git a/backend/app/model/__init__.py b/backend/app/model/__init__.py index e69de29..a6b035b 100644 --- a/backend/app/model/__init__.py +++ b/backend/app/model/__init__.py @@ -0,0 +1,85 @@ +# new 2025 assessment models +from app.model.assessments import ( + AltiaElpacResult, + AltsaElpacResult, + CaaResult, + CaasppStudentGroup, + CaasppTest, + CaasResult, + CastResult, + CsaResult, + ElpacStudentGroup, + ElpacTest, + Entity, + IaElpacResult, + SaElpacResult, + SbResult, +) +from app.model.census_data import ( + CensusCreate, + CensusData, + CensusDataPublic, + CensusDataPublicList, + CensusUpdate, +) +from app.model.dashboard import ( + DashboardAggregation, + DashboardSummaryResponse, + IndicatorSummary, +) +from app.model.item import Item, ItemCreate, ItemPublic, ItemsPublic, ItemUpdate +from app.model.other import Message, Token, TokenPayload +from app.model.school import School, SchoolCreate, SchoolPublic, SchoolsPublic +from app.model.user import ( + UpdatePassword, + User, + UserCreate, + UserPublic, + UserRegister, + UsersPublic, + UserUpdate, +) + +__all__ = [ + "AltiaElpacResult", + "AltsaElpacResult", + "CaaResult", + "CaasppStudentGroup", + "CaasppTest", + "CaasResult", + "CastResult", + "CsaResult", + "ElpacStudentGroup", + "ElpacTest", + "Entity", + "IaElpacResult", + "SaElpacResult", + "SbResult", + "CensusCreate", + "CensusData", + "CensusDataPublic", + "CensusDataPublicList", + "CensusUpdate", + "DashboardAggregation", + "DashboardSummaryResponse", + "IndicatorSummary", + "Item", + "ItemCreate", + "ItemPublic", + "ItemsPublic", + "ItemUpdate", + "Message", + "Token", + "TokenPayload", + "School", + "SchoolCreate", + "SchoolPublic", + "SchoolsPublic", + "UpdatePassword", + "User", + "UserCreate", + "UserPublic", + "UserRegister", + "UsersPublic", + "UserUpdate", +] diff --git a/backend/app/model/academic_indicator.py b/backend/app/model/academic_indicator.py deleted file mode 100644 index 7d9a3b0..0000000 --- a/backend/app/model/academic_indicator.py +++ /dev/null @@ -1,264 +0,0 @@ -import uuid -from datetime import datetime -from typing import TYPE_CHECKING, Any - -from sqlalchemy import JSON, Column, DateTime, UniqueConstraint -from sqlmodel import Field, Relationship, SQLModel - -from app.core.utils import get_datetime_utc - -if TYPE_CHECKING: - pass - - -# ============================================================ -# ACADEMIC INDICATOR TABLE (Base) -# ============================================================ - - -class AcademicIndicatorBase(SQLModel): - """ - Shared properties for AcademicIndicator (California Dashboard data) - Current metrics have been moved to CurrentMetrics table. - """ - - # Identifiers - cds: str = Field(primary_key=True, max_length=14, index=True) # 14-char CDS code - rtype: str = Field(max_length=1, index=True) # S/D/X (School/District/State) - schoolname: str | None = Field(default=None, max_length=255, index=True) - districtname: str | None = Field(default=None, max_length=255, index=True) - countyname: str | None = Field(default=None, max_length=255, index=True) - - # Flags (Y or blank) - charter_flag: str | None = Field(default=None, max_length=1, index=True) - coe_flag: str | None = Field(default=None, max_length=1, index=True) - dass_flag: str | None = Field(default=None, max_length=1, index=True) - - # Demographics - studentgroup: str = Field(index=True, max_length=10) # ALL, AA, AI, AS, etc. - - # Prior metrics - priordenom: int | None = Field(default=None, index=True) - priorstatus: float | None = Field(default=None, index=True) - - # Performance - change: float | None = Field(default=None, index=True) - statuslevel: int | None = Field(default=None, index=True) # 1-5 or 0 - changelevel: int | None = Field(default=None, index=True) # 1-5 or 0 - color: int | None = Field(default=None, index=True) # 1-5 or 0 - box: int | None = Field(default=None, index=True) # 0-250 - - # Accountability - priornsizemet: str | None = Field(default=None, max_length=10, index=True) - accountabilitymet: str | None = Field(default=None, max_length=10, index=True) - hscutpoints: str | None = Field(default=None, max_length=255) - pairshare_method: str | None = Field(default=None, max_length=255) - - # Participation (prior) - priorprate_enrolled: int | None = Field(default=None, index=True) - priorprate_tested: int | None = Field(default=None, index=True) - priorprate: float | None = Field(default=None, index=True) - priornumprloss: int | None = Field(default=None) - priordenom_withoutprloss: int | None = Field(default=None) - priorstatus_withoutprloss: float | None = Field(default=None) - - # Metadata - indicator: str = Field(default="ELA", max_length=10, index=True) - reportingyear: str = Field(max_length=10, index=True) # e.g., "2025" - - # === Extended fields for all indicator types === - - # Common fields (Chronic, Suspension, Graduation, ELPI) - priornumer: int | None = Field(default=None, index=True) - smalldenom: str | None = Field(default=None, max_length=10, index=True) - priorcertifyflag: str | None = Field(default=None, max_length=10, index=True) - dataerrorflag: str | None = Field(default=None, max_length=10, index=True) - - # Suspension-specific - school_type: str | None = Field( - default=None, max_length=50, index=True - ) # 'type' column - - # Graduation-specific - fiveyrnumer: int | None = Field(default=None) - - # ELPI-specific (English Learner Progress) - Prior fields - priorprogressed: int | None = Field(default=None, index=True) - priormaintainpl4: int | None = Field(default=None) - priormaintainoth: int | None = Field(default=None) - priordeclined: int | None = Field(default=None) - priorprogressed_alternate: int | None = Field(default=None) - priormaintainpl3_alternate: int | None = Field(default=None) - priornotprognotmain_alternate: int | None = Field(default=None) - prior95: int | None = Field(default=None) - - # CCI studentgroup percentage - studentgroup_pct: float | None = Field(default=None, index=True) - - -class AcademicIndicator(AcademicIndicatorBase, table=True): - __table_args__ = ( - UniqueConstraint( - "cds", - "indicator", - "studentgroup", - "reportingyear", - name="uq_indicator_natural_key", - ), - ) - - id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) - created_at: datetime | None = Field( - default_factory=get_datetime_utc, - sa_type=DateTime(timezone=True), # type: ignore - index=True, - ) - # CCI-specific (stored as JSON to avoid 100+ columns) - cci_details: dict[str, Any] | None = Field(default=None, sa_column=Column(JSON)) - - # Relationship to CurrentMetrics (one-to-many) - current_metrics: list["CurrentMetrics"] = Relationship( - back_populates="academic_indicator" - ) - - -class AcademicIndicatorCreate(AcademicIndicatorBase): - pass - - -class AcademicIndicatorUpdate(SQLModel): - cds: str | None = Field(default=None, max_length=14) - rtype: str | None = Field(default=None, max_length=1) - schoolname: str | None = Field(default=None, max_length=255) - districtname: str | None = Field(default=None, max_length=255) - countyname: str | None = Field(default=None, max_length=255) - charter_flag: str | None = Field(default=None, max_length=1) - coe_flag: str | None = Field(default=None, max_length=1) - dass_flag: str | None = Field(default=None, max_length=1) - studentgroup: str | None = Field(default=None, max_length=10) - priordenom: int | None = Field(default=None) - priorstatus: float | None = Field(default=None) - change: float | None = Field(default=None) - statuslevel: int | None = Field(default=None) - changelevel: int | None = Field(default=None) - color: int | None = Field(default=None) - box: int | None = Field(default=None) - priornsizemet: str | None = Field(default=None, max_length=10) - accountabilitymet: str | None = Field(default=None, max_length=10) - hscutpoints: str | None = Field(default=None, max_length=255) - pairshare_method: str | None = Field(default=None, max_length=255) - priorprate_enrolled: int | None = Field(default=None) - priorprate_tested: int | None = Field(default=None) - priorprate: float | None = Field(default=None) - priornumprloss: int | None = Field(default=None) - priordenom_withoutprloss: int | None = Field(default=None) - priorstatus_withoutprloss: float | None = Field(default=None) - indicator: str | None = Field(default=None, max_length=10) - reportingyear: str | None = Field(default=None, max_length=10) - - -class AcademicIndicatorPublic(AcademicIndicatorBase): - id: uuid.UUID - created_at: datetime | None = None - - -class AcademicIndicatorsPublic(SQLModel): - data: list[AcademicIndicatorPublic] - count: int - - -# ============================================================ -# CURRENT METRICS TABLE (Separated for timestamp tracking) -# ============================================================ - - -class CurrentMetricsBase(SQLModel): - """ - Current metrics extracted into separate table for timestamp tracking. - Foreign key links to AcademicIndicator via cds. - """ - - # Foreign key to AcademicIndicator - cds: str = Field( - foreign_key="academicindicator.cds", - max_length=14, - index=True, - ) - - # Current metrics (basic) - currdenom: int | None = Field(default=None, index=True) - currstatus: float | None = Field(default=None, index=True) - - # Accountability (current) - currnsizemet: str | None = Field(default=None, max_length=10, index=True) - - # Participation (current) - currprate_enrolled: int | None = Field(default=None, index=True) - currprate_tested: int | None = Field(default=None, index=True) - currprate: float | None = Field(default=None, index=True) - currnumprloss: int | None = Field(default=None) - currdenom_withoutprloss: int | None = Field(default=None) - currstatus_withoutprloss: float | None = Field(default=None) - - # Common current fields (Chronic, Suspension, Graduation, ELPI) - currnumer: int | None = Field(default=None, index=True) - certifyflag: str | None = Field(default=None, max_length=10, index=True) - - # ELPI-specific current fields - currprogressed: int | None = Field(default=None, index=True) - currmaintainpl4: int | None = Field(default=None) - currmaintainoth: int | None = Field(default=None) - currdeclined: int | None = Field(default=None) - currprogressed_alternate: int | None = Field(default=None) - currmaintainpl3_alternate: int | None = Field(default=None) - currnotprognotmain_alternate: int | None = Field(default=None) - curr95: int | None = Field(default=None) - - -class CurrentMetrics(CurrentMetricsBase, table=True): - """ - Current metrics table with timestamp tracking. - """ - - id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) - updated_at: datetime | None = Field( - default_factory=get_datetime_utc, - sa_type=DateTime(timezone=True), # type: ignore - index=True, - ) - - # Relationship back to AcademicIndicator - academic_indicator: "AcademicIndicator" = Relationship( - back_populates="current_metrics" - ) - - -class CurrentMetricsCreate(CurrentMetricsBase): - pass - - -class CurrentMetricsUpdate(SQLModel): - currdenom: int | None = Field(default=None) - currstatus: float | None = Field(default=None) - currnsizemet: str | None = Field(default=None, max_length=10) - currprate_enrolled: int | None = Field(default=None) - currprate_tested: int | None = Field(default=None) - currprate: float | None = Field(default=None) - currnumprloss: int | None = Field(default=None) - currdenom_withoutprloss: int | None = Field(default=None) - currstatus_withoutprloss: float | None = Field(default=None) - currnumer: int | None = Field(default=None) - certifyflag: str | None = Field(default=None, max_length=10) - currprogressed: int | None = Field(default=None) - currmaintainpl4: int | None = Field(default=None) - currmaintainoth: int | None = Field(default=None) - currdeclined: int | None = Field(default=None) - currprogressed_alternate: int | None = Field(default=None) - currmaintainpl3_alternate: int | None = Field(default=None) - currnotprognotmain_alternate: int | None = Field(default=None) - curr95: int | None = Field(default=None) - - -class CurrentMetricsPublic(CurrentMetricsBase): - id: uuid.UUID - updated_at: datetime | None = None diff --git a/backend/app/model/assessments.py b/backend/app/model/assessments.py new file mode 100644 index 0000000..32d3001 --- /dev/null +++ b/backend/app/model/assessments.py @@ -0,0 +1,2117 @@ +import uuid +from decimal import Decimal + +from pydantic import ConfigDict +from pydantic.alias_generators import to_camel +from sqlalchemy import ( + Column, + ForeignKeyConstraint, + Index, + Integer, + Numeric, + String, + UniqueConstraint, +) +from sqlmodel import Field, Relationship, SQLModel + + +class CaasppBase(SQLModel): + """ + Base class for CAASPP / CAST / SBAC results (The "Spaces" Group). + Provides Pydantic configuration and common fields. + Specific database columns are defined in subclasses to avoid shared Column instance errors. + """ + + model_config = ConfigDict( + alias_generator=to_camel, populate_by_name=True, from_attributes=True + ) + + +class ElpacBase(SQLModel): + """ + Base class for ELPAC results (The "PascalCase" Group). + Provides Pydantic configuration and common fields. + Specific database columns are defined in subclasses to avoid shared Column instance errors. + """ + + model_config = ConfigDict( + alias_generator=to_camel, populate_by_name=True, from_attributes=True + ) + + +class CaasppTest(SQLModel, table=True): + """CAASPP test lookup: Test ID, Test ID Num, Test Name.""" + + __tablename__ = "caaspp_tests" + test_id: int = Field(primary_key=True) + test_id_num: int | None = Field(default=None) + test_name: str | None = Field(default=None, max_length=255) + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + + +class ElpacTest(SQLModel, table=True): + """ELPAC test lookup: Test ID, Test Name.""" + + __tablename__ = "elpac_tests" + test_id: int = Field(primary_key=True) + test_name: str | None = Field(default=None, max_length=255) + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + + +class CaasppStudentGroup(SQLModel, table=True): + """CAASPP student group lookup: Demographic ID, Demographic ID Num, Demographic Name, Student Group.""" + + __tablename__ = "caaspp_student_groups" + demographic_id: str = Field(primary_key=True, max_length=10) + demographic_id_num: int | None = Field(default=None) + demographic_name: str | None = Field(default=None, max_length=255) + student_group: str | None = Field(default=None, max_length=255) + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + + +class ElpacStudentGroup(SQLModel, table=True): + """ELPAC student group lookup: Student Group ID, Student Group Name.""" + + __tablename__ = "elpac_student_groups" + student_group_id: str = Field(primary_key=True, max_length=10) + student_group_name: str | None = Field(default=None, max_length=255) + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + + +class Entity(SQLModel, table=True): + __tablename__ = "entities" + + cds_code: str = Field(primary_key=True, max_length=14) + + county_name: str | None = Field(default=None, max_length=25) + district_name: str | None = Field(default=None, max_length=40) + school_name: str | None = Field(default=None, max_length=60) + + filler: str | None = Field(default=None, max_length=4) + zip_code: str | None = Field(default=None, max_length=9) + type_id: int | None = Field(default=None) + + # Relationships to result tables + caa_results: list[CaaResult] = Relationship(back_populates="entity") + caas_results: list[CaasResult] = Relationship(back_populates="entity") + cast_results: list[CastResult] = Relationship(back_populates="entity") + csa_results: list[CsaResult] = Relationship(back_populates="entity") + sb_results: list[SbResult] = Relationship(back_populates="entity") + ia_elpac_results: list[IaElpacResult] = Relationship(back_populates="entity") + altia_elpac_results: list[AltiaElpacResult] = Relationship(back_populates="entity") + sa_elpac_results: list[SaElpacResult] = Relationship(back_populates="entity") + altsa_elpac_results: list[AltsaElpacResult] = Relationship(back_populates="entity") + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + + +class CaaResult(CaasppBase, table=True): + __tablename__ = "caa_results" + + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + + # Composite natural key for unique constraint + cds_code: str = Field( + validation_alias="CDSCode", sa_column=Column("cds_code", String(14)) + ) + test_year: int = Field( + validation_alias="Test Year", sa_column=Column("test_year", Integer) + ) + student_group_id: str = Field( + validation_alias="Student Group ID", + sa_column=Column("student_group_id", String), + ) + test_id: int = Field( + validation_alias="Test ID", sa_column=Column("test_id", Integer) + ) + grade: str = Field(validation_alias="Grade", sa_column=Column("grade", String(2))) + + # Common result fields (normalized) + filler: str | None = Field( + default=None, validation_alias="Filler", sa_column=Column("filler", String(4)) + ) + test_type: str | None = Field( + default=None, + validation_alias="Test Type", + sa_column=Column("test_type", String(1)), + ) + type_id: int | None = Field( + default=None, validation_alias="Type ID", sa_column=Column("type_id", Integer) + ) + total_students_enrolled: int | None = Field( + default=None, + validation_alias="Total Students Enrolled", + sa_column=Column("total_students_enrolled", Integer), + ) + total_students_tested: int | None = Field( + default=None, + validation_alias="Total Students Tested", + sa_column=Column("total_students_tested", Integer), + ) + total_students_tested_with_scores: int | None = Field( + default=None, + validation_alias="Total Students Tested with Scores", + sa_column=Column("total_students_tested_with_scores", Integer), + ) + overall_total: int | None = Field( + default=None, + validation_alias="Overall Total", + sa_column=Column("overall_total", Integer), + ) + + __table_args__ = ( + UniqueConstraint( + "cds_code", + "test_year", + "student_group_id", + "test_id", + "grade", + name="ix_caa_results_natural_key", + ), + ForeignKeyConstraint(["cds_code"], ["entities.cds_code"]), + ForeignKeyConstraint( + ["student_group_id"], ["caaspp_student_groups.demographic_id"] + ), + ForeignKeyConstraint(["test_id"], ["caaspp_tests.test_id"]), + Index("ix_caa_results_year_grade", "test_year", "grade"), + Index("ix_caa_results_student_group", "student_group_id"), + ) + + entity: Entity = Relationship(back_populates="caa_results") + + mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="Mean Scale Score", + sa_column=Column("Mean Scale Score", Numeric(6, 1)), + ) + count_level_1: int | None = Field( + default=None, + validation_alias="Count Level 1", + sa_column=Column("Count Level 1", Integer), + ) + count_level_2: int | None = Field( + default=None, + validation_alias="Count Level 2", + sa_column=Column("Count Level 2", Integer), + ) + count_level_3: int | None = Field( + default=None, + validation_alias="Count Level 3", + sa_column=Column("Count Level 3", Integer), + ) + percentage_level_1: Decimal | None = Field( + default=None, + validation_alias="Percentage Level 1", + sa_column=Column("Percentage Level 1", Numeric(5, 2)), + ) + percentage_level_2: Decimal | None = Field( + default=None, + validation_alias="Percentage Level 2", + sa_column=Column("Percentage Level 2", Numeric(5, 2)), + ) + percentage_level_3: Decimal | None = Field( + default=None, + validation_alias="Percentage Level 3", + sa_column=Column("Percentage Level 3", Numeric(5, 2)), + ) + + model_config = ConfigDict( + alias_generator=to_camel, populate_by_name=True, from_attributes=True + ) + + +class CaasResult(CaasppBase, table=True): + __tablename__ = "caas_results" + + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + + # Composite natural key for unique constraint + cds_code: str = Field( + validation_alias="CDSCode", sa_column=Column("cds_code", String(14)) + ) + test_year: int = Field( + validation_alias="Test Year", sa_column=Column("test_year", Integer) + ) + student_group_id: str = Field( + validation_alias="Student Group ID", + sa_column=Column("student_group_id", String), + ) + test_id: int = Field( + validation_alias="Test ID", sa_column=Column("test_id", Integer) + ) + grade: str = Field(validation_alias="Grade", sa_column=Column("grade", String(2))) + + # Common result fields (normalized) + filler: str | None = Field( + default=None, validation_alias="Filler", sa_column=Column("filler", String(4)) + ) + test_type: str | None = Field( + default=None, + validation_alias="Test Type", + sa_column=Column("test_type", String(1)), + ) + type_id: int | None = Field( + default=None, validation_alias="Type ID", sa_column=Column("type_id", Integer) + ) + total_students_enrolled: int | None = Field( + default=None, + validation_alias="Total Students Enrolled", + sa_column=Column("total_students_enrolled", Integer), + ) + total_students_tested: int | None = Field( + default=None, + validation_alias="Total Students Tested", + sa_column=Column("total_students_tested", Integer), + ) + total_students_tested_with_scores: int | None = Field( + default=None, + validation_alias="Total Students Tested with Scores", + sa_column=Column("total_students_tested_with_scores", Integer), + ) + overall_total: int | None = Field( + default=None, + validation_alias="Overall Total", + sa_column=Column("overall_total", Integer), + ) + + __table_args__ = ( + UniqueConstraint( + "cds_code", + "test_year", + "student_group_id", + "test_id", + "grade", + name="ix_caas_results_natural_key", + ), + ForeignKeyConstraint(["cds_code"], ["entities.cds_code"]), + ForeignKeyConstraint( + ["student_group_id"], ["caaspp_student_groups.demographic_id"] + ), + ForeignKeyConstraint(["test_id"], ["caaspp_tests.test_id"]), + Index("ix_caas_results_year_grade", "test_year", "grade"), + Index("ix_caas_results_student_group", "student_group_id"), + ) + + entity: Entity = Relationship(back_populates="caas_results") + + mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="Mean Scale Score", + sa_column=Column("Mean Scale Score", Numeric(6, 1)), + ) + count_level_1: int | None = Field( + default=None, + validation_alias="Count Level 1", + sa_column=Column("Count Level 1", Integer), + ) + count_level_2: int | None = Field( + default=None, + validation_alias="Count Level 2", + sa_column=Column("Count Level 2", Integer), + ) + count_level_3: int | None = Field( + default=None, + validation_alias="Count Level 3", + sa_column=Column("Count Level 3", Integer), + ) + percentage_level_1: Decimal | None = Field( + default=None, + validation_alias="Percentage Level 1", + sa_column=Column("Percentage Level 1", Numeric(5, 2)), + ) + percentage_level_2: Decimal | None = Field( + default=None, + validation_alias="Percentage Level 2", + sa_column=Column("Percentage Level 2", Numeric(5, 2)), + ) + percentage_level_3: Decimal | None = Field( + default=None, + validation_alias="Percentage Level 3", + sa_column=Column("Percentage Level 3", Numeric(5, 2)), + ) + + model_config = ConfigDict( + alias_generator=to_camel, populate_by_name=True, from_attributes=True + ) + + +class CastResult(CaasppBase, table=True): + __tablename__ = "cast_results" + + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + + # Composite natural key for unique constraint + cds_code: str = Field( + validation_alias="CDSCode", sa_column=Column("cds_code", String(14)) + ) + test_year: int = Field( + validation_alias="Test Year", sa_column=Column("test_year", Integer) + ) + student_group_id: str = Field( + validation_alias="Student Group ID", + sa_column=Column("student_group_id", String), + ) + test_id: int = Field( + validation_alias="Test ID", sa_column=Column("test_id", Integer) + ) + grade: str = Field(validation_alias="Grade", sa_column=Column("grade", String(2))) + + # Common result fields (normalized) + filler: str | None = Field( + default=None, validation_alias="Filler", sa_column=Column("filler", String(4)) + ) + test_type: str | None = Field( + default=None, + validation_alias="Test Type", + sa_column=Column("test_type", String(1)), + ) + type_id: int | None = Field( + default=None, validation_alias="Type ID", sa_column=Column("type_id", Integer) + ) + total_students_enrolled: int | None = Field( + default=None, + validation_alias="Total Students Enrolled", + sa_column=Column("total_students_enrolled", Integer), + ) + total_students_tested: int | None = Field( + default=None, + validation_alias="Total Students Tested", + sa_column=Column("total_students_tested", Integer), + ) + total_students_tested_with_scores: int | None = Field( + default=None, + validation_alias="Total Students Tested with Scores", + sa_column=Column("total_students_tested_with_scores", Integer), + ) + overall_total: int | None = Field( + default=None, + validation_alias="Overall Total", + sa_column=Column("overall_total", Integer), + ) + + __table_args__ = ( + UniqueConstraint( + "cds_code", + "test_year", + "student_group_id", + "test_id", + "grade", + name="ix_cast_results_natural_key", + ), + ForeignKeyConstraint(["cds_code"], ["entities.cds_code"]), + ForeignKeyConstraint( + ["student_group_id"], ["caaspp_student_groups.demographic_id"] + ), + ForeignKeyConstraint(["test_id"], ["caaspp_tests.test_id"]), + Index("ix_cast_results_year_grade", "test_year", "grade"), + Index("ix_cast_results_student_group", "student_group_id"), + ) + + entity: Entity = Relationship(back_populates="cast_results") + + mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="Mean Scale Score", + sa_column=Column("Mean Scale Score", Numeric(6, 1)), + ) + count_standard_exceeded: int | None = Field( + default=None, + validation_alias="Count Standard Exceeded", + sa_column=Column("Count Standard Exceeded", Integer), + ) + count_standard_met: int | None = Field( + default=None, + validation_alias="Count Standard Met", + sa_column=Column("Count Standard Met", Integer), + ) + count_standard_met_and_above: int | None = Field( + default=None, + validation_alias="Count Standard Met and Above", + sa_column=Column("Count Standard Met and Above", Integer), + ) + count_standard_nearly_met: int | None = Field( + default=None, + validation_alias="Count Standard Nearly Met", + sa_column=Column("Count Standard Nearly Met", Integer), + ) + count_standard_not_met: int | None = Field( + default=None, + validation_alias="Count Standard Not Met", + sa_column=Column("Count Standard Not Met", Integer), + ) + percentage_standard_exceeded: Decimal | None = Field( + default=None, + validation_alias="Percentage Standard Exceeded", + sa_column=Column("Percentage Standard Exceeded", Numeric(5, 2)), + ) + percentage_standard_met: Decimal | None = Field( + default=None, + validation_alias="Percentage Standard Met", + sa_column=Column("Percentage Standard Met", Numeric(5, 2)), + ) + percentage_standard_met_and_above: Decimal | None = Field( + default=None, + validation_alias="Percentage Standard Met and Above", + sa_column=Column("Percentage Standard Met and Above", Numeric(5, 2)), + ) + percentage_standard_nearly_met: Decimal | None = Field( + default=None, + validation_alias="Percentage Standard Nearly Met", + sa_column=Column("Percentage Standard Nearly Met", Numeric(5, 2)), + ) + percentage_standard_not_met: Decimal | None = Field( + default=None, + validation_alias="Percentage Standard Not Met", + sa_column=Column("Percentage Standard Not Met", Numeric(5, 2)), + ) + + earth_and_space_sciences_domain_count_above_standard: int | None = Field( + default=None, + validation_alias="Earth and Space Sciences Domain Count Above Standard", + sa_column=Column( + "Earth and Space Sciences Domain Count Above Standard", Integer + ), + ) + earth_and_space_sciences_domain_count_below_standard: int | None = Field( + default=None, + validation_alias="Earth and Space Sciences Domain Count Below Standard", + sa_column=Column( + "Earth and Space Sciences Domain Count Below Standard", Integer + ), + ) + earth_and_space_sciences_domain_count_near_standard: int | None = Field( + default=None, + validation_alias="Earth and Space Sciences Domain Count Near Standard", + sa_column=Column( + "Earth and Space Sciences Domain Count Near Standard", Integer + ), + ) + earth_and_space_sciences_domain_percent_above_standard: Decimal | None = Field( + default=None, + validation_alias="Earth and Space Sciences Domain Percent Above Standard", + sa_column=Column( + "Earth and Space Sciences Domain Percent Above Standard", Numeric(5, 2) + ), + ) + earth_and_space_sciences_domain_percent_below_standard: Decimal | None = Field( + default=None, + validation_alias="Earth and Space Sciences Domain Percent Below Standard", + sa_column=Column( + "Earth and Space Sciences Domain Percent Below Standard", Numeric(5, 2) + ), + ) + earth_and_space_sciences_domain_percent_near_standard: Decimal | None = Field( + default=None, + validation_alias="Earth and Space Sciences Domain Percent Near Standard", + sa_column=Column( + "Earth and Space Sciences Domain Percent Near Standard", Numeric(5, 2) + ), + ) + earth_and_space_sciences_domain_total: int | None = Field( + default=None, + validation_alias="Earth and Space Sciences Domain Total", + sa_column=Column("Earth and Space Sciences Domain Total", Integer), + ) + + life_sciences_domain_count_above_standard: int | None = Field( + default=None, + validation_alias="Life Sciences Domain Count Above Standard", + sa_column=Column("Life Sciences Domain Count Above Standard", Integer), + ) + life_sciences_domain_count_below_standard: int | None = Field( + default=None, + validation_alias="Life Sciences Domain Count Below Standard", + sa_column=Column("Life Sciences Domain Count Below Standard", Integer), + ) + life_sciences_domain_count_near_standard: int | None = Field( + default=None, + validation_alias="Life Sciences Domain Count Near Standard", + sa_column=Column("Life Sciences Domain Count Near Standard", Integer), + ) + life_sciences_domain_percent_above_standard: Decimal | None = Field( + default=None, + validation_alias="Life Sciences Domain Percent Above Standard", + sa_column=Column("Life Sciences Domain Percent Above Standard", Numeric(5, 2)), + ) + life_sciences_domain_percent_below_standard: Decimal | None = Field( + default=None, + validation_alias="Life Sciences Domain Percent Below Standard", + sa_column=Column("Life Sciences Domain Percent Below Standard", Numeric(5, 2)), + ) + life_sciences_domain_percent_near_standard: Decimal | None = Field( + default=None, + validation_alias="Life Sciences Domain Percent Near Standard", + sa_column=Column("Life Sciences Domain Percent Near Standard", Numeric(5, 2)), + ) + life_sciences_domain_total: int | None = Field( + default=None, + validation_alias="Life Sciences Domain Total", + sa_column=Column("Life Sciences Domain Total", Integer), + ) + + physical_sciences_domain_count_above_standard: int | None = Field( + default=None, + validation_alias="Physical Sciences Domain Count Above Standard", + sa_column=Column("Physical Sciences Domain Count Above Standard", Integer), + ) + physical_sciences_domain_count_below_standard: int | None = Field( + default=None, + validation_alias="Physical Sciences Domain Count Below Standard", + sa_column=Column("Physical Sciences Domain Count Below Standard", Integer), + ) + physical_sciences_domain_count_near_standard: int | None = Field( + default=None, + validation_alias="Physical Sciences Domain Count Near Standard", + sa_column=Column("Physical Sciences Domain Count Near Standard", Integer), + ) + physical_sciences_domain_percent_above_standard: Decimal | None = Field( + default=None, + validation_alias="Physical Sciences Domain Percent Above Standard", + sa_column=Column( + "Physical Sciences Domain Percent Above Standard", Numeric(5, 2) + ), + ) + physical_sciences_domain_percent_below_standard: Decimal | None = Field( + default=None, + validation_alias="Physical Sciences Domain Percent Below Standard", + sa_column=Column( + "Physical Sciences Domain Percent Below Standard", Numeric(5, 2) + ), + ) + physical_sciences_domain_percent_near_standard: Decimal | None = Field( + default=None, + validation_alias="Physical Sciences Domain Percent Near Standard", + sa_column=Column( + "Physical Sciences Domain Percent Near Standard", Numeric(5, 2) + ), + ) + physical_sciences_domain_total: int | None = Field( + default=None, + validation_alias="Physical Sciences Domain Total", + sa_column=Column("Physical Sciences Domain Total", Integer), + ) + + model_config = ConfigDict( + alias_generator=to_camel, populate_by_name=True, from_attributes=True + ) + + +class CsaResult(CaasppBase, table=True): + __tablename__ = "csa_results" + + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + + # Composite natural key for unique constraint + cds_code: str = Field( + validation_alias="CDSCode", sa_column=Column("cds_code", String(14)) + ) + test_year: int = Field( + validation_alias="Test Year", sa_column=Column("test_year", Integer) + ) + student_group_id: str = Field( + validation_alias="Student Group ID", + sa_column=Column("student_group_id", String), + ) + test_id: int = Field( + validation_alias="Test ID", sa_column=Column("test_id", Integer) + ) + grade: str = Field(validation_alias="Grade", sa_column=Column("grade", String(2))) + + # Common result fields (normalized) + filler: str | None = Field( + default=None, validation_alias="Filler", sa_column=Column("filler", String(4)) + ) + test_type: str | None = Field( + default=None, + validation_alias="Test Type", + sa_column=Column("test_type", String(1)), + ) + type_id: int | None = Field( + default=None, validation_alias="Type ID", sa_column=Column("type_id", Integer) + ) + total_students_enrolled: int | None = Field( + default=None, + validation_alias="Total Students Enrolled", + sa_column=Column("total_students_enrolled", Integer), + ) + total_students_tested: int | None = Field( + default=None, + validation_alias="Total Students Tested", + sa_column=Column("total_students_tested", Integer), + ) + total_students_tested_with_scores: int | None = Field( + default=None, + validation_alias="Total Students Tested with Scores", + sa_column=Column("total_students_tested_with_scores", Integer), + ) + overall_total: int | None = Field( + default=None, + validation_alias="Overall Total", + sa_column=Column("overall_total", Integer), + ) + + __table_args__ = ( + UniqueConstraint( + "cds_code", + "test_year", + "student_group_id", + "test_id", + "grade", + name="ix_csa_results_natural_key", + ), + ForeignKeyConstraint(["cds_code"], ["entities.cds_code"]), + ForeignKeyConstraint( + ["student_group_id"], ["caaspp_student_groups.demographic_id"] + ), + ForeignKeyConstraint(["test_id"], ["caaspp_tests.test_id"]), + Index("ix_csa_results_year_grade", "test_year", "grade"), + Index("ix_csa_results_student_group", "student_group_id"), + ) + + entity: Entity = Relationship(back_populates="csa_results") + + overall_mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="Overall Mean Scale Score", + sa_column=Column("Overall Mean Scale Score", Numeric(6, 1)), + ) + count_level_1: int | None = Field( + default=None, + validation_alias="Count Level 1", + sa_column=Column("Count Level 1", Integer), + ) + count_level_2: int | None = Field( + default=None, + validation_alias="Count Level 2", + sa_column=Column("Count Level 2", Integer), + ) + count_level_3: int | None = Field( + default=None, + validation_alias="Count Level 3", + sa_column=Column("Count Level 3", Integer), + ) + percent_level_1: Decimal | None = Field( + default=None, + validation_alias="Percent Level 1", + sa_column=Column("Percent Level 1", Numeric(5, 2)), + ) + percent_level_2: Decimal | None = Field( + default=None, + validation_alias="Percent Level 2", + sa_column=Column("Percent Level 2", Numeric(5, 2)), + ) + percent_level_3: Decimal | None = Field( + default=None, + validation_alias="Percent Level 3", + sa_column=Column("Percent Level 3", Numeric(5, 2)), + ) + composite_1_count_level_1: int | None = Field( + default=None, + validation_alias="Composite 1 Count Level 1", + sa_column=Column("Composite 1 Count Level 1", Integer), + ) + composite_1_count_level_2: int | None = Field( + default=None, + validation_alias="Composite 1 Count Level 2", + sa_column=Column("Composite 1 Count Level 2", Integer), + ) + composite_1_count_level_3: int | None = Field( + default=None, + validation_alias="Composite 1 Count Level 3", + sa_column=Column("Composite 1 Count Level 3", Integer), + ) + composite_1_mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="Composite 1 Mean Scale Score", + sa_column=Column("Composite 1 Mean Scale Score", Numeric(6, 1)), + ) + composite_1_percent_level_1: Decimal | None = Field( + default=None, + validation_alias="Composite 1 Percent Level 1", + sa_column=Column("Composite 1 Percent Level 1", Numeric(5, 2)), + ) + composite_1_percent_level_2: Decimal | None = Field( + default=None, + validation_alias="Composite 1 Percent Level 2", + sa_column=Column("Composite 1 Percent Level 2", Numeric(5, 2)), + ) + composite_1_percent_level_3: Decimal | None = Field( + default=None, + validation_alias="Composite 1 Percent Level 3", + sa_column=Column("Composite 1 Percent Level 3", Numeric(5, 2)), + ) + composite_1_total: int | None = Field( + default=None, + validation_alias="Composite 1 Total", + sa_column=Column("Composite 1 Total", Integer), + ) + composite_2_count_level_1: int | None = Field( + default=None, + validation_alias="Composite 2 Count Level 1", + sa_column=Column("Composite 2 Count Level 1", Integer), + ) + composite_2_count_level_2: int | None = Field( + default=None, + validation_alias="Composite 2 Count Level 2", + sa_column=Column("Composite 2 Count Level 2", Integer), + ) + composite_2_count_level_3: int | None = Field( + default=None, + validation_alias="Composite 2 Count Level 3", + sa_column=Column("Composite 2 Count Level 3", Integer), + ) + composite_2_mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="Composite 2 Mean Scale Score", + sa_column=Column("Composite 2 Mean Scale Score", Numeric(6, 1)), + ) + composite_2_percent_level_1: Decimal | None = Field( + default=None, + validation_alias="Composite 2 Percent Level 1", + sa_column=Column("Composite 2 Percent Level 1", Numeric(5, 2)), + ) + composite_2_percent_level_2: Decimal | None = Field( + default=None, + validation_alias="Composite 2 Percent Level 2", + sa_column=Column("Composite 2 Percent Level 2", Numeric(5, 2)), + ) + composite_2_percent_level_3: Decimal | None = Field( + default=None, + validation_alias="Composite 2 Percent Level 3", + sa_column=Column("Composite 2 Percent Level 3", Numeric(5, 2)), + ) + composite_2_total: int | None = Field( + default=None, + validation_alias="Composite 2 Total", + sa_column=Column("Composite 2 Total", Integer), + ) + listening_domain_count_level_1: int | None = Field( + default=None, + validation_alias="Listening Domain Count Level 1", + sa_column=Column("Listening Domain Count Level 1", Integer), + ) + listening_domain_count_level_2: int | None = Field( + default=None, + validation_alias="Listening Domain Count Level 2", + sa_column=Column("Listening Domain Count Level 2", Integer), + ) + listening_domain_count_level_3: int | None = Field( + default=None, + validation_alias="Listening Domain Count Level 3", + sa_column=Column("Listening Domain Count Level 3", Integer), + ) + listening_domain_percent_level_1: Decimal | None = Field( + default=None, + validation_alias="Listening Domain Percent Level 1", + sa_column=Column("Listening Domain Percent Level 1", Numeric(5, 2)), + ) + listening_domain_percent_level_2: Decimal | None = Field( + default=None, + validation_alias="Listening Domain Percent Level 2", + sa_column=Column("Listening Domain Percent Level 2", Numeric(5, 2)), + ) + listening_domain_percent_level_3: Decimal | None = Field( + default=None, + validation_alias="Listening Domain Percent Level 3", + sa_column=Column("Listening Domain Percent Level 3", Numeric(5, 2)), + ) + listening_domain_total: int | None = Field( + default=None, + validation_alias="Listening Domain Total", + sa_column=Column("Listening Domain Total", Integer), + ) + reading_domain_count_level_1: int | None = Field( + default=None, + validation_alias="Reading Domain Count Level 1", + sa_column=Column("Reading Domain Count Level 1", Integer), + ) + reading_domain_count_level_2: int | None = Field( + default=None, + validation_alias="Reading Domain Count Level 2", + sa_column=Column("Reading Domain Count Level 2", Integer), + ) + reading_domain_count_level_3: int | None = Field( + default=None, + validation_alias="Reading Domain Count Level 3", + sa_column=Column("Reading Domain Count Level 3", Integer), + ) + reading_domain_percent_level_1: Decimal | None = Field( + default=None, + validation_alias="Reading Domain Percent Level 1", + sa_column=Column("Reading Domain Percent Level 1", Numeric(5, 2)), + ) + reading_domain_percent_level_2: Decimal | None = Field( + default=None, + validation_alias="Reading Domain Percent Level 2", + sa_column=Column("Reading Domain Percent Level 2", Numeric(5, 2)), + ) + reading_domain_percent_level_3: Decimal | None = Field( + default=None, + validation_alias="Reading Domain Percent Level 3", + sa_column=Column("Reading Domain Percent Level 3", Numeric(5, 2)), + ) + reading_domain_total: int | None = Field( + default=None, + validation_alias="Reading Domain Total", + sa_column=Column("Reading Domain Total", Integer), + ) + speaking_domain_count_level_1: int | None = Field( + default=None, + validation_alias="Speaking Domain Count Level 1", + sa_column=Column("Speaking Domain Count Level 1", Integer), + ) + speaking_domain_count_level_2: int | None = Field( + default=None, + validation_alias="Speaking Domain Count Level 2", + sa_column=Column("Speaking Domain Count Level 2", Integer), + ) + speaking_domain_count_level_3: int | None = Field( + default=None, + validation_alias="Speaking Domain Count Level 3", + sa_column=Column("Speaking Domain Count Level 3", Integer), + ) + speaking_domain_percent_level_1: Decimal | None = Field( + default=None, + validation_alias="Speaking Domain Percent Level 1", + sa_column=Column("Speaking Domain Percent Level 1", Numeric(5, 2)), + ) + speaking_domain_percent_level_2: Decimal | None = Field( + default=None, + validation_alias="Speaking Domain Percent Level 2", + sa_column=Column("Speaking Domain Percent Level 2", Numeric(5, 2)), + ) + speaking_domain_percent_level_3: Decimal | None = Field( + default=None, + validation_alias="Speaking Domain Percent Level 3", + sa_column=Column("Speaking Domain Percent Level 3", Numeric(5, 2)), + ) + speaking_domain_total: int | None = Field( + default=None, + validation_alias="Speaking Domain Total", + sa_column=Column("Speaking Domain Total", Integer), + ) + writing_domain_count_level_1: int | None = Field( + default=None, + validation_alias="Writing Domain Count Level 1", + sa_column=Column("Writing Domain Count Level 1", Integer), + ) + writing_domain_count_level_2: int | None = Field( + default=None, + validation_alias="Writing Domain Count Level 2", + sa_column=Column("Writing Domain Count Level 2", Integer), + ) + writing_domain_count_level_3: int | None = Field( + default=None, + validation_alias="Writing Domain Count Level 3", + sa_column=Column("Writing Domain Count Level 3", Integer), + ) + writing_domain_percent_level_1: Decimal | None = Field( + default=None, + validation_alias="Writing Domain Percent Level 1", + sa_column=Column("Writing Domain Percent Level 1", Numeric(5, 2)), + ) + writing_domain_percent_level_2: Decimal | None = Field( + default=None, + validation_alias="Writing Domain Percent Level 2", + sa_column=Column("Writing Domain Percent Level 2", Numeric(5, 2)), + ) + writing_domain_percent_level_3: Decimal | None = Field( + default=None, + validation_alias="Writing Domain Percent Level 3", + sa_column=Column("Writing Domain Percent Level 3", Numeric(5, 2)), + ) + writing_domain_total: int | None = Field( + default=None, + validation_alias="Writing Domain Total", + sa_column=Column("Writing Domain Total", Integer), + ) + + model_config = ConfigDict( + alias_generator=to_camel, populate_by_name=True, from_attributes=True + ) + + +class SbResult(CaasppBase, table=True): + __tablename__ = "sb_results" + + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + + # Composite natural key for unique constraint + cds_code: str = Field( + validation_alias="CDSCode", sa_column=Column("cds_code", String(14)) + ) + test_year: int = Field( + validation_alias="Test Year", sa_column=Column("test_year", Integer) + ) + student_group_id: str = Field( + validation_alias="Student Group ID", + sa_column=Column("student_group_id", String), + ) + test_id: int = Field( + validation_alias="Test ID", sa_column=Column("test_id", Integer) + ) + grade: str = Field(validation_alias="Grade", sa_column=Column("grade", String(2))) + + # Common result fields (normalized) + filler: str | None = Field( + default=None, validation_alias="Filler", sa_column=Column("filler", String(4)) + ) + test_type: str | None = Field( + default=None, + validation_alias="Test Type", + sa_column=Column("test_type", String(1)), + ) + type_id: int | None = Field( + default=None, validation_alias="Type ID", sa_column=Column("type_id", Integer) + ) + total_students_enrolled: int | None = Field( + default=None, + validation_alias="Total Students Enrolled", + sa_column=Column("total_students_enrolled", Integer), + ) + total_students_tested: int | None = Field( + default=None, + validation_alias="Total Students Tested", + sa_column=Column("total_students_tested", Integer), + ) + total_students_tested_with_scores: int | None = Field( + default=None, + validation_alias="Total Students Tested with Scores", + sa_column=Column("total_students_tested_with_scores", Integer), + ) + overall_total: int | None = Field( + default=None, + validation_alias="Overall Total", + sa_column=Column("overall_total", Integer), + ) + + __table_args__ = ( + UniqueConstraint( + "cds_code", + "test_year", + "student_group_id", + "test_id", + "grade", + name="ix_sb_results_natural_key", + ), + ForeignKeyConstraint(["cds_code"], ["entities.cds_code"]), + ForeignKeyConstraint( + ["student_group_id"], ["caaspp_student_groups.demographic_id"] + ), + ForeignKeyConstraint(["test_id"], ["caaspp_tests.test_id"]), + Index("ix_sb_results_year_grade", "test_year", "grade"), + Index("ix_sb_results_student_group", "student_group_id"), + ) + + entity: Entity = Relationship(back_populates="sb_results") + + mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="Mean Scale Score", + sa_column=Column("Mean Scale Score", Numeric(6, 1)), + ) + count_standard_exceeded: int | None = Field( + default=None, + validation_alias="Count Standard Exceeded", + sa_column=Column("Count Standard Exceeded", Integer), + ) + count_standard_met: int | None = Field( + default=None, + validation_alias="Count Standard Met", + sa_column=Column("Count Standard Met", Integer), + ) + count_standard_met_and_above: int | None = Field( + default=None, + validation_alias="Count Standard Met and Above", + sa_column=Column("Count Standard Met and Above", Integer), + ) + count_standard_nearly_met: int | None = Field( + default=None, + validation_alias="Count Standard Nearly Met", + sa_column=Column("Count Standard Nearly Met", Integer), + ) + count_standard_not_met: int | None = Field( + default=None, + validation_alias="Count Standard Not Met", + sa_column=Column("Count Standard Not Met", Integer), + ) + percentage_standard_exceeded: Decimal | None = Field( + default=None, + validation_alias="Percentage Standard Exceeded", + sa_column=Column("Percentage Standard Exceeded", Numeric(5, 2)), + ) + percentage_standard_met: Decimal | None = Field( + default=None, + validation_alias="Percentage Standard Met", + sa_column=Column("Percentage Standard Met", Numeric(5, 2)), + ) + percentage_standard_met_and_above: Decimal | None = Field( + default=None, + validation_alias="Percentage Standard Met and Above", + sa_column=Column("Percentage Standard Met and Above", Numeric(5, 2)), + ) + percentage_standard_nearly_met: Decimal | None = Field( + default=None, + validation_alias="Percentage Standard Nearly Met", + sa_column=Column("Percentage Standard Nearly Met", Numeric(5, 2)), + ) + percentage_standard_not_met: Decimal | None = Field( + default=None, + validation_alias="Percentage Standard Not Met", + sa_column=Column("Percentage Standard Not Met", Numeric(5, 2)), + ) + area_1_count_above_standard: int | None = Field( + default=None, + validation_alias="Area 1 Count Above Standard", + sa_column=Column("Area 1 Count Above Standard", Integer), + ) + area_1_count_below_standard: int | None = Field( + default=None, + validation_alias="Area 1 Count Below Standard", + sa_column=Column("Area 1 Count Below Standard", Integer), + ) + area_1_count_near_standard: int | None = Field( + default=None, + validation_alias="Area 1 Count Near Standard", + sa_column=Column("Area 1 Count Near Standard", Integer), + ) + area_1_percentage_above_standard: Decimal | None = Field( + default=None, + validation_alias="Area 1 Percentage Above Standard", + sa_column=Column("Area 1 Percentage Above Standard", Numeric(5, 2)), + ) + area_1_percentage_below_standard: Decimal | None = Field( + default=None, + validation_alias="Area 1 Percentage Below Standard", + sa_column=Column("Area 1 Percentage Below Standard", Numeric(5, 2)), + ) + area_1_percentage_near_standard: Decimal | None = Field( + default=None, + validation_alias="Area 1 Percentage Near Standard", + sa_column=Column("Area 1 Percentage Near Standard", Numeric(5, 2)), + ) + area_1_total: int | None = Field( + default=None, + validation_alias="Area 1 Total", + sa_column=Column("Area 1 Total", Integer), + ) + area_2_count_above_standard: int | None = Field( + default=None, + validation_alias="Area 2 Count Above Standard", + sa_column=Column("Area 2 Count Above Standard", Integer), + ) + area_2_count_below_standard: int | None = Field( + default=None, + validation_alias="Area 2 Count Below Standard", + sa_column=Column("Area 2 Count Below Standard", Integer), + ) + area_2_count_near_standard: int | None = Field( + default=None, + validation_alias="Area 2 Count Near Standard", + sa_column=Column("Area 2 Count Near Standard", Integer), + ) + area_2_percentage_above_standard: Decimal | None = Field( + default=None, + validation_alias="Area 2 Percentage Above Standard", + sa_column=Column("Area 2 Percentage Above Standard", Numeric(5, 2)), + ) + area_2_percentage_below_standard: Decimal | None = Field( + default=None, + validation_alias="Area 2 Percentage Below Standard", + sa_column=Column("Area 2 Percentage Below Standard", Numeric(5, 2)), + ) + area_2_percentage_near_standard: Decimal | None = Field( + default=None, + validation_alias="Area 2 Percentage Near Standard", + sa_column=Column("Area 2 Percentage Near Standard", Numeric(5, 2)), + ) + area_2_total: int | None = Field( + default=None, + validation_alias="Area 2 Total", + sa_column=Column("Area 2 Total", Integer), + ) + area_3_count_above_standard: int | None = Field( + default=None, + validation_alias="Area 3 Count Above Standard", + sa_column=Column("Area 3 Count Above Standard", Integer), + ) + area_3_count_below_standard: int | None = Field( + default=None, + validation_alias="Area 3 Count Below Standard", + sa_column=Column("Area 3 Count Below Standard", Integer), + ) + area_3_count_near_standard: int | None = Field( + default=None, + validation_alias="Area 3 Count Near Standard", + sa_column=Column("Area 3 Count Near Standard", Integer), + ) + area_3_percentage_above_standard: Decimal | None = Field( + default=None, + validation_alias="Area 3 Percentage Above Standard", + sa_column=Column("Area 3 Percentage Above Standard", Numeric(5, 2)), + ) + area_3_percentage_below_standard: Decimal | None = Field( + default=None, + validation_alias="Area 3 Percentage Below Standard", + sa_column=Column("Area 3 Percentage Below Standard", Numeric(5, 2)), + ) + area_3_percentage_near_standard: Decimal | None = Field( + default=None, + validation_alias="Area 3 Percentage Near Standard", + sa_column=Column("Area 3 Percentage Near Standard", Numeric(5, 2)), + ) + area_3_total: int | None = Field( + default=None, + validation_alias="Area 3 Total", + sa_column=Column("Area 3 Total", Integer), + ) + area_4_count_above_standard: int | None = Field( + default=None, + validation_alias="Area 4 Count Above Standard", + sa_column=Column("Area 4 Count Above Standard", Integer), + ) + area_4_count_below_standard: int | None = Field( + default=None, + validation_alias="Area 4 Count Below Standard", + sa_column=Column("Area 4 Count Below Standard", Integer), + ) + area_4_count_near_standard: int | None = Field( + default=None, + validation_alias="Area 4 Count Near Standard", + sa_column=Column("Area 4 Count Near Standard", Integer), + ) + area_4_percentage_above_standard: Decimal | None = Field( + default=None, + validation_alias="Area 4 Percentage Above Standard", + sa_column=Column("Area 4 Percentage Above Standard", Numeric(5, 2)), + ) + area_4_percentage_below_standard: Decimal | None = Field( + default=None, + validation_alias="Area 4 Percentage Below Standard", + sa_column=Column("Area 4 Percentage Below Standard", Numeric(5, 2)), + ) + area_4_percentage_near_standard: Decimal | None = Field( + default=None, + validation_alias="Area 4 Percentage Near Standard", + sa_column=Column("Area 4 Percentage Near Standard", Numeric(5, 2)), + ) + area_4_total: int | None = Field( + default=None, + validation_alias="Area 4 Total", + sa_column=Column("Area 4 Total", Integer), + ) + composite_area_1_count_above_standard: int | None = Field( + default=None, + validation_alias="Composite Area 1 Count Above Standard", + sa_column=Column("Composite Area 1 Count Above Standard", Integer), + ) + composite_area_1_count_below_standard: int | None = Field( + default=None, + validation_alias="Composite Area 1 Count Below Standard", + sa_column=Column("Composite Area 1 Count Below Standard", Integer), + ) + composite_area_1_count_near_standard: int | None = Field( + default=None, + validation_alias="Composite Area 1 Count Near Standard", + sa_column=Column("Composite Area 1 Count Near Standard", Integer), + ) + composite_area_1_percentage_above_standard: Decimal | None = Field( + default=None, + validation_alias="Composite Area 1 Percentage Above Standard", + sa_column=Column("Composite Area 1 Percentage Above Standard", Numeric(5, 2)), + ) + composite_area_1_percentage_below_standard: Decimal | None = Field( + default=None, + validation_alias="Composite Area 1 Percentage Below Standard", + sa_column=Column("Composite Area 1 Percentage Below Standard", Numeric(5, 2)), + ) + composite_area_1_percentage_near_standard: Decimal | None = Field( + default=None, + validation_alias="Composite Area 1 Percentage Near Standard", + sa_column=Column("Composite Area 1 Percentage Near Standard", Numeric(5, 2)), + ) + composite_area_1_total: int | None = Field( + default=None, + validation_alias="Composite Area 1 Total", + sa_column=Column("Composite Area 1 Total", Integer), + ) + composite_area_2_count_above_standard: int | None = Field( + default=None, + validation_alias="Composite Area 2 Count Above Standard", + sa_column=Column("Composite Area 2 Count Above Standard", Integer), + ) + composite_area_2_count_below_standard: int | None = Field( + default=None, + validation_alias="Composite Area 2 Count Below Standard", + sa_column=Column("Composite Area 2 Count Below Standard", Integer), + ) + composite_area_2_count_near_standard: int | None = Field( + default=None, + validation_alias="Composite Area 2 Count Near Standard", + sa_column=Column("Composite Area 2 Count Near Standard", Integer), + ) + composite_area_2_percentage_above_standard: Decimal | None = Field( + default=None, + validation_alias="Composite Area 2 Percentage Above Standard", + sa_column=Column("Composite Area 2 Percentage Above Standard", Numeric(5, 2)), + ) + composite_area_2_percentage_below_standard: Decimal | None = Field( + default=None, + validation_alias="Composite Area 2 Percentage Below Standard", + sa_column=Column("Composite Area 2 Percentage Below Standard", Numeric(5, 2)), + ) + composite_area_2_percentage_near_standard: Decimal | None = Field( + default=None, + validation_alias="Composite Area 2 Percentage Near Standard", + sa_column=Column("Composite Area 2 Percentage Near Standard", Numeric(5, 2)), + ) + composite_area_2_total: int | None = Field( + default=None, + validation_alias="Composite Area 2 Total", + sa_column=Column("Composite Area 2 Total", Integer), + ) + + model_config = ConfigDict( + alias_generator=to_camel, populate_by_name=True, from_attributes=True + ) + + +class IaElpacResult(ElpacBase, table=True): + __tablename__ = "ia_elpac_results" + + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + + # Composite natural key for unique constraint + cds_code: str = Field( + validation_alias="CDSCode", sa_column=Column("cds_code", String(14)) + ) + test_year: int = Field( + validation_alias="TestYear", sa_column=Column("test_year", Integer) + ) + student_group_id: str = Field( + validation_alias="StudentGroupID", sa_column=Column("student_group_id", String) + ) + test_id: int = Field( + validation_alias="TestID", sa_column=Column("test_id", Integer) + ) + grade: str = Field(validation_alias="Grade", sa_column=Column("grade", String(2))) + + # Common result fields (normalized) + filler: str | None = Field( + default=None, validation_alias="Filler", sa_column=Column("filler", String(4)) + ) + type_id: int | None = Field( + default=None, validation_alias="TypeID", sa_column=Column("type_id", Integer) + ) + total_students_enrolled: int | None = Field( + default=None, + validation_alias="TotalStudentsEnrolled", + sa_column=Column("total_students_enrolled", Integer), + ) + total_students_tested: int | None = Field( + default=None, + validation_alias="TotalStudentsTested", + sa_column=Column("total_students_tested", Integer), + ) + total_students_tested_with_scores: int | None = Field( + default=None, + validation_alias="TotalStudentsTestedWithScores", + sa_column=Column("total_students_tested_with_scores", Integer), + ) + overall_total: int | None = Field( + default=None, + validation_alias="OverallTotal", + sa_column=Column("overall_total", Integer), + ) + + __table_args__ = ( + UniqueConstraint( + "cds_code", + "test_year", + "student_group_id", + "test_id", + "grade", + name="ix_ia_elpac_results_natural_key", + ), + ForeignKeyConstraint(["cds_code"], ["entities.cds_code"]), + ForeignKeyConstraint( + ["student_group_id"], ["elpac_student_groups.student_group_id"] + ), + ForeignKeyConstraint(["test_id"], ["elpac_tests.test_id"]), + Index("ix_ia_elpac_results_year_grade", "test_year", "grade"), + Index("ix_ia_elpac_results_student_group", "student_group_id"), + ) + + entity: Entity = Relationship(back_populates="ia_elpac_results") + + overall_mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="OverallMeanSclScr", + sa_column=Column("OverallMeanSclScr", Numeric(6, 1)), + ) + novice_el_perf_lvl_pcnt: Decimal | None = Field( + default=None, + validation_alias="NoviceELPerfLvlPcnt", + sa_column=Column("NoviceELPerfLvlPcnt", Numeric(5, 2)), + ) + novice_el_perf_lvl_count: int | None = Field( + default=None, + validation_alias="NoviceELPerfLvlCount", + sa_column=Column("NoviceELPerfLvlCount", Integer), + ) + intermediate_el_perf_lvl_pcnt: Decimal | None = Field( + default=None, + validation_alias="IntermediateELPerfLvlPcnt", + sa_column=Column("IntermediateELPerfLvlPcnt", Numeric(5, 2)), + ) + intermediate_el_perf_lvl_count: int | None = Field( + default=None, + validation_alias="IntermediateELPerfLvlCount", + sa_column=Column("IntermediateELPerfLvlCount", Integer), + ) + ifep_perf_lvl_pcnt: Decimal | None = Field( + default=None, + validation_alias="IFEPPerfLvlPcnt", + sa_column=Column("IFEPPerfLvlPcnt", Numeric(5, 2)), + ) + ifep_perf_lvl_count: int | None = Field( + default=None, + validation_alias="IFEPPerfLvlCount", + sa_column=Column("IFEPPerfLvlCount", Integer), + ) + overall_total: int | None = Field(default=None) + oral_lang_minimally_developed_perf_lvl_pcnt: Decimal | None = Field( + default=None, + validation_alias="OralLangMinimallyDevelopedPerfLvlPcnt", + sa_column=Column("OralLangMinimallyDevelopedPerfLvlPcnt", Numeric(5, 2)), + ) + oral_lang_minimally_developed_perf_lvl_count: int | None = Field( + default=None, + validation_alias="OralLangMinimallyDevelopedPerfLvlCount", + sa_column=Column("OralLangMinimallyDevelopedPerfLvlCount", Integer), + ) + oral_lang_moderately_developed_perf_lvl_pcnt: Decimal | None = Field( + default=None, + validation_alias="OralLangModeratelyDevelopedPerfLvlPcnt", + sa_column=Column("OralLangModeratelyDevelopedPerfLvlPcnt", Numeric(5, 2)), + ) + oral_lang_moderately_developed_perf_lvl_count: int | None = Field( + default=None, + validation_alias="OralLangModeratelyDevelopedPerfLvlCount", + sa_column=Column("OralLangModeratelyDevelopedPerfLvlCount", Integer), + ) + oral_lang_well_developed_perf_lvl_pcnt: Decimal | None = Field( + default=None, + validation_alias="OralLangWellDevelopedPerfLvlPcnt", + sa_column=Column("OralLangWellDevelopedPerfLvlPcnt", Numeric(5, 2)), + ) + oral_lang_well_developed_perf_lvl_count: int | None = Field( + default=None, + validation_alias="OralLangWellDevelopedPerfLvlCount", + sa_column=Column("OralLangWellDevelopedPerfLvlCount", Integer), + ) + oral_lang_total: int | None = Field( + default=None, + validation_alias="OralLangTotal", + sa_column=Column("OralLangTotal", Integer), + ) + writ_lang_minimally_developed_perf_lvl_pcnt: Decimal | None = Field( + default=None, + validation_alias="WritLangMinimallyDevelopedPerfLvlPcnt", + sa_column=Column("WritLangMinimallyDevelopedPerfLvlPcnt", Numeric(5, 2)), + ) + writ_lang_minimally_developed_perf_lvl_count: int | None = Field( + default=None, + validation_alias="WritLangMinimallyDevelopedPerfLvlCount", + sa_column=Column("WritLangMinimallyDevelopedPerfLvlCount", Integer), + ) + writ_lang_moderately_developed_perf_lvl_pcnt: Decimal | None = Field( + default=None, + validation_alias="WritLangModeratelyDevelopedPerfLvlPcnt", + sa_column=Column("WritLangModeratelyDevelopedPerfLvlPcnt", Numeric(5, 2)), + ) + writ_lang_moderately_developed_perf_lvl_count: int | None = Field( + default=None, + validation_alias="WritLangModeratelyDevelopedPerfLvlCount", + sa_column=Column("WritLangModeratelyDevelopedPerfLvlCount", Integer), + ) + writ_lang_well_developed_perf_lvl_pcnt: Decimal | None = Field( + default=None, + validation_alias="WritLangWellDevelopedPerfLvlPcnt", + sa_column=Column("WritLangWellDevelopedPerfLvlPcnt", Numeric(5, 2)), + ) + writ_lang_well_developed_perf_lvl_count: int | None = Field( + default=None, + validation_alias="WritLangWellDevelopedPerfLvlCount", + sa_column=Column("WritLangWellDevelopedPerfLvlCount", Integer), + ) + writ_lang_total: int | None = Field( + default=None, + validation_alias="WritLangTotal", + sa_column=Column("WritLangTotal", Integer), + ) + listening_domain_begin_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + listening_domain_begin_count: int | None = Field(default=None) + listening_domain_moderate_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + listening_domain_moderate_count: int | None = Field(default=None) + listening_domain_developed_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + listening_domain_developed_count: int | None = Field(default=None) + listening_domain_total: int | None = Field(default=None) + speaking_domain_begin_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + speaking_domain_begin_count: int | None = Field(default=None) + speaking_domain_moderate_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + speaking_domain_moderate_count: int | None = Field(default=None) + speaking_domain_developed_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + speaking_domain_developed_count: int | None = Field(default=None) + speaking_domain_total: int | None = Field(default=None) + reading_domain_begin_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + reading_domain_begin_count: int | None = Field(default=None) + reading_domain_moderate_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + reading_domain_moderate_count: int | None = Field(default=None) + reading_domain_developed_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + reading_domain_developed_count: int | None = Field(default=None) + reading_domain_total: int | None = Field(default=None) + writing_domain_begin_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + writing_domain_begin_count: int | None = Field(default=None) + writing_domain_moderate_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + writing_domain_moderate_count: int | None = Field(default=None) + writing_domain_developed_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + writing_domain_developed_count: int | None = Field(default=None) + writing_domain_total: int | None = Field(default=None) + + model_config = ConfigDict( + alias_generator=to_camel, populate_by_name=True, from_attributes=True + ) + + +class AltiaElpacResult(ElpacBase, table=True): + __tablename__ = "altia_elpac_results" + + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + + # Composite natural key for unique constraint + cds_code: str = Field( + validation_alias="CDSCode", sa_column=Column("cds_code", String(14)) + ) + test_year: int = Field( + validation_alias="TestYear", sa_column=Column("test_year", Integer) + ) + student_group_id: str = Field( + validation_alias="StudentGroupID", sa_column=Column("student_group_id", String) + ) + test_id: int = Field( + validation_alias="TestID", sa_column=Column("test_id", Integer) + ) + grade: str = Field(validation_alias="Grade", sa_column=Column("grade", String(2))) + + # Common result fields (normalized) + filler: str | None = Field( + default=None, validation_alias="Filler", sa_column=Column("filler", String(4)) + ) + type_id: int | None = Field( + default=None, validation_alias="TypeID", sa_column=Column("type_id", Integer) + ) + total_students_enrolled: int | None = Field( + default=None, + validation_alias="TotalStudentsEnrolled", + sa_column=Column("total_students_enrolled", Integer), + ) + total_students_tested: int | None = Field( + default=None, + validation_alias="TotalStudentsTested", + sa_column=Column("total_students_tested", Integer), + ) + total_students_tested_with_scores: int | None = Field( + default=None, + validation_alias="TotalStudentsTestedWithScores", + sa_column=Column("total_students_tested_with_scores", Integer), + ) + overall_total: int | None = Field( + default=None, + validation_alias="OverallTotal", + sa_column=Column("overall_total", Integer), + ) + + __table_args__ = ( + UniqueConstraint( + "cds_code", + "test_year", + "student_group_id", + "test_id", + "grade", + name="ix_altia_elpac_results_natural_key", + ), + ForeignKeyConstraint(["cds_code"], ["entities.cds_code"]), + ForeignKeyConstraint( + ["student_group_id"], ["elpac_student_groups.student_group_id"] + ), + ForeignKeyConstraint(["test_id"], ["elpac_tests.test_id"]), + Index("ix_altia_elpac_results_year_grade", "test_year", "grade"), + Index("ix_altia_elpac_results_student_group", "student_group_id"), + ) + + entity: Entity = Relationship(back_populates="altia_elpac_results") + + overall_mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="OverallMeanScaleScore", + sa_column=Column("OverallMeanScaleScore", Numeric(6, 1)), + ) + overall_perf_lvl_pcnt_1: Decimal | None = Field( + default=None, + validation_alias="OverallPerfLvl1Pcnt", + sa_column=Column("OverallPerfLvl1Pcnt", Numeric(5, 2)), + ) + overall_perf_lvl_count_1: int | None = Field( + default=None, + validation_alias="OverallPerfLvl1Count", + sa_column=Column("OverallPerfLvl1Count", Integer), + ) + overall_perf_lvl_pcnt_2: Decimal | None = Field( + default=None, + validation_alias="OverallPerfLvl2Pcnt", + sa_column=Column("OverallPerfLvl2Pcnt", Numeric(5, 2)), + ) + overall_perf_lvl_count_2: int | None = Field( + default=None, + validation_alias="OverallPerfLvl2Count", + sa_column=Column("OverallPerfLvl2Count", Integer), + ) + overall_perf_lvl_pcnt_3: Decimal | None = Field( + default=None, + validation_alias="OverallPerfLvl3Pcnt", + sa_column=Column("OverallPerfLvl3Pcnt", Numeric(5, 2)), + ) + overall_perf_lvl_count_3: int | None = Field( + default=None, + validation_alias="OverallPerfLvl3Count", + sa_column=Column("OverallPerfLvl3Count", Integer), + ) + overall_perf_lvl_pcnt_4: Decimal | None = Field( + default=None, + validation_alias="OverallPerfLvl4Pcnt", + sa_column=Column("OverallPerfLvl4Pcnt", Numeric(5, 2)), + ) + overall_perf_lvl_count_4: int | None = Field( + default=None, + validation_alias="OverallPerfLvl4Count", + sa_column=Column("OverallPerfLvl4Count", Integer), + ) + overall_total: int | None = Field(default=None) + + oral_lang_mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="OralLangMeanScaleScore", + sa_column=Column("OralLangMeanScaleScore", Numeric(6, 1)), + ) + oral_lang_perf_lvl_pcnt_1: Decimal | None = Field( + default=None, + validation_alias="OralLangPerfLvl1Pcnt", + sa_column=Column("OralLangPerfLvl1Pcnt", Numeric(5, 2)), + ) + oral_lang_perf_lvl_count_1: int | None = Field( + default=None, + validation_alias="OralLangPerfLvl1Count", + sa_column=Column("OralLangPerfLvl1Count", Integer), + ) + oral_lang_perf_lvl_pcnt_2: Decimal | None = Field( + default=None, + validation_alias="OralLangPerfLvl2Pcnt", + sa_column=Column("OralLangPerfLvl2Pcnt", Numeric(5, 2)), + ) + oral_lang_perf_lvl_count_2: int | None = Field( + default=None, + validation_alias="OralLangPerfLvl2Count", + sa_column=Column("OralLangPerfLvl2Count", Integer), + ) + oral_lang_perf_lvl_pcnt_3: Decimal | None = Field( + default=None, + validation_alias="OralLangPerfLvl3Pcnt", + sa_column=Column("OralLangPerfLvl3Pcnt", Numeric(5, 2)), + ) + oral_lang_perf_lvl_count_3: int | None = Field( + default=None, + validation_alias="OralLangPerfLvl3Count", + sa_column=Column("OralLangPerfLvl3Count", Integer), + ) + oral_lang_perf_lvl_pcnt_4: Decimal | None = Field( + default=None, + validation_alias="OralLangPerfLvl4Pcnt", + sa_column=Column("OralLangPerfLvl4Pcnt", Numeric(5, 2)), + ) + oral_lang_perf_lvl_count_4: int | None = Field( + default=None, + validation_alias="OralLangPerfLvl4Count", + sa_column=Column("OralLangPerfLvl4Count", Integer), + ) + oral_lang_total: int | None = Field( + default=None, + validation_alias="OralLangTotal", + sa_column=Column("OralLangTotal", Integer), + ) + + writ_lang_mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="WritLangMeanScaleScore", + sa_column=Column("WritLangMeanScaleScore", Numeric(6, 1)), + ) + writ_lang_perf_lvl_pcnt_1: Decimal | None = Field( + default=None, + validation_alias="WritLangPerfLvl1Pcnt", + sa_column=Column("WritLangPerfLvl1Pcnt", Numeric(5, 2)), + ) + writ_lang_perf_lvl_count_1: int | None = Field( + default=None, + validation_alias="WritLangPerfLvl1Count", + sa_column=Column("WritLangPerfLvl1Count", Integer), + ) + writ_lang_perf_lvl_pcnt_2: Decimal | None = Field( + default=None, + validation_alias="WritLangPerfLvl2Pcnt", + sa_column=Column("WritLangPerfLvl2Pcnt", Numeric(5, 2)), + ) + writ_lang_perf_lvl_count_2: int | None = Field( + default=None, + validation_alias="WritLangPerfLvl2Count", + sa_column=Column("WritLangPerfLvl2Count", Integer), + ) + writ_lang_perf_lvl_pcnt_3: Decimal | None = Field( + default=None, + validation_alias="WritLangPerfLvl3Pcnt", + sa_column=Column("WritLangPerfLvl3Pcnt", Numeric(5, 2)), + ) + writ_lang_perf_lvl_count_3: int | None = Field( + default=None, + validation_alias="WritLangPerfLvl3Count", + sa_column=Column("WritLangPerfLvl3Count", Integer), + ) + writ_lang_perf_lvl_pcnt_4: Decimal | None = Field( + default=None, + validation_alias="WritLangPerfLvl4Pcnt", + sa_column=Column("WritLangPerfLvl4Pcnt", Numeric(5, 2)), + ) + writ_lang_perf_lvl_count_4: int | None = Field( + default=None, + validation_alias="WritLangPerfLvl4Count", + sa_column=Column("WritLangPerfLvl4Count", Integer), + ) + writ_lang_total: int | None = Field( + default=None, + validation_alias="WritLangTotal", + sa_column=Column("WritLangTotal", Integer), + ) + + model_config = ConfigDict( + alias_generator=to_camel, populate_by_name=True, from_attributes=True + ) + + +class SaElpacResult(ElpacBase, table=True): + __tablename__ = "sa_elpac_results" + + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + + # Composite natural key for unique constraint + cds_code: str = Field( + validation_alias="CDSCode", sa_column=Column("cds_code", String(14)) + ) + test_year: int = Field( + validation_alias="TestYear", sa_column=Column("test_year", Integer) + ) + student_group_id: str = Field( + validation_alias="StudentGroupID", sa_column=Column("student_group_id", String) + ) + test_id: int = Field( + validation_alias="TestID", sa_column=Column("test_id", Integer) + ) + grade: str = Field(validation_alias="Grade", sa_column=Column("grade", String(2))) + + # Common result fields (normalized) + filler: str | None = Field( + default=None, validation_alias="Filler", sa_column=Column("filler", String(4)) + ) + type_id: int | None = Field( + default=None, validation_alias="TypeID", sa_column=Column("type_id", Integer) + ) + total_students_enrolled: int | None = Field( + default=None, + validation_alias="TotalStudentsEnrolled", + sa_column=Column("total_students_enrolled", Integer), + ) + total_students_tested: int | None = Field( + default=None, + validation_alias="TotalStudentsTested", + sa_column=Column("total_students_tested", Integer), + ) + total_students_tested_with_scores: int | None = Field( + default=None, + validation_alias="TotalStudentsTestedWithScores", + sa_column=Column("total_students_tested_with_scores", Integer), + ) + overall_total: int | None = Field( + default=None, + validation_alias="OverallTotal", + sa_column=Column("overall_total", Integer), + ) + + __table_args__ = ( + UniqueConstraint( + "cds_code", + "test_year", + "student_group_id", + "test_id", + "grade", + name="ix_sa_elpac_results_natural_key", + ), + ForeignKeyConstraint(["cds_code"], ["entities.cds_code"]), + ForeignKeyConstraint( + ["student_group_id"], ["elpac_student_groups.student_group_id"] + ), + ForeignKeyConstraint(["test_id"], ["elpac_tests.test_id"]), + Index("ix_sa_elpac_results_year_grade", "test_year", "grade"), + Index("ix_sa_elpac_results_student_group", "student_group_id"), + ) + + entity: Entity = Relationship(back_populates="sa_elpac_results") + + overall_mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="OverallMeanScaleScore", + sa_column=Column("OverallMeanScaleScore", Numeric(6, 1)), + ) + overall_perf_lvl_pcnt_1: Decimal | None = Field( + default=None, + validation_alias="OverallPerfLvl1Pcnt", + sa_column=Column("OverallPerfLvl1Pcnt", Numeric(5, 2)), + ) + overall_perf_lvl_count_1: int | None = Field( + default=None, + validation_alias="OverallPerfLvl1Count", + sa_column=Column("OverallPerfLvl1Count", Integer), + ) + overall_perf_lvl_pcnt_2: Decimal | None = Field( + default=None, + validation_alias="OverallPerfLvl2Pcnt", + sa_column=Column("OverallPerfLvl2Pcnt", Numeric(5, 2)), + ) + overall_perf_lvl_count_2: int | None = Field( + default=None, + validation_alias="OverallPerfLvl2Count", + sa_column=Column("OverallPerfLvl2Count", Integer), + ) + overall_perf_lvl_pcnt_3: Decimal | None = Field( + default=None, + validation_alias="OverallPerfLvl3Pcnt", + sa_column=Column("OverallPerfLvl3Pcnt", Numeric(5, 2)), + ) + overall_perf_lvl_count_3: int | None = Field( + default=None, + validation_alias="OverallPerfLvl3Count", + sa_column=Column("OverallPerfLvl3Count", Integer), + ) + overall_perf_lvl_pcnt_4: Decimal | None = Field( + default=None, + validation_alias="OverallPerfLvl4Pcnt", + sa_column=Column("OverallPerfLvl4Pcnt", Numeric(5, 2)), + ) + overall_perf_lvl_count_4: int | None = Field( + default=None, + validation_alias="OverallPerfLvl4Count", + sa_column=Column("OverallPerfLvl4Count", Integer), + ) + + oral_lang_mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="OralLangMeanScaleScore", + sa_column=Column("OralLangMeanScaleScore", Numeric(6, 1)), + ) + oral_lang_perf_lvl_count_1: int | None = Field( + default=None, + validation_alias="OralLangPerfLvl1Count", + sa_column=Column("OralLangPerfLvl1Count", Integer), + ) + oral_lang_perf_lvl_pcnt_1: Decimal | None = Field( + default=None, + validation_alias="OralLangPerfLvl1Pcnt", + sa_column=Column("OralLangPerfLvl1Pcnt", Numeric(5, 2)), + ) + oral_lang_perf_lvl_count_2: int | None = Field( + default=None, + validation_alias="OralLangPerfLvl2Count", + sa_column=Column("OralLangPerfLvl2Count", Integer), + ) + oral_lang_perf_lvl_pcnt_2: Decimal | None = Field( + default=None, + validation_alias="OralLangPerfLvl2Pcnt", + sa_column=Column("OralLangPerfLvl2Pcnt", Numeric(5, 2)), + ) + oral_lang_perf_lvl_count_3: int | None = Field( + default=None, + validation_alias="OralLangPerfLvl3Count", + sa_column=Column("OralLangPerfLvl3Count", Integer), + ) + oral_lang_perf_lvl_pcnt_3: Decimal | None = Field( + default=None, + validation_alias="OralLangPerfLvl3Pcnt", + sa_column=Column("OralLangPerfLvl3Pcnt", Numeric(5, 2)), + ) + oral_lang_perf_lvl_count_4: int | None = Field( + default=None, + validation_alias="OralLangPerfLvl4Count", + sa_column=Column("OralLangPerfLvl4Count", Integer), + ) + oral_lang_perf_lvl_pcnt_4: Decimal | None = Field( + default=None, + validation_alias="OralLangPerfLvl4Pcnt", + sa_column=Column("OralLangPerfLvl4Pcnt", Numeric(5, 2)), + ) + oral_lang_total: int | None = Field( + default=None, + validation_alias="OralLangTotal", + sa_column=Column("OralLangTotal", Integer), + ) + + writ_lang_mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="WritLangMeanScaleScore", + sa_column=Column("WritLangMeanScaleScore", Numeric(6, 1)), + ) + writ_lang_perf_lvl_count_1: int | None = Field( + default=None, + validation_alias="WritLangPerfLvl1Count", + sa_column=Column("WritLangPerfLvl1Count", Integer), + ) + writ_lang_perf_lvl_pcnt_1: Decimal | None = Field( + default=None, + validation_alias="WritLangPerfLvl1Pcnt", + sa_column=Column("WritLangPerfLvl1Pcnt", Numeric(5, 2)), + ) + writ_lang_perf_lvl_count_2: int | None = Field( + default=None, + validation_alias="WritLangPerfLvl2Count", + sa_column=Column("WritLangPerfLvl2Count", Integer), + ) + writ_lang_perf_lvl_pcnt_2: Decimal | None = Field( + default=None, + validation_alias="WritLangPerfLvl2Pcnt", + sa_column=Column("WritLangPerfLvl2Pcnt", Numeric(5, 2)), + ) + writ_lang_perf_lvl_count_3: int | None = Field( + default=None, + validation_alias="WritLangPerfLvl3Count", + sa_column=Column("WritLangPerfLvl3Count", Integer), + ) + writ_lang_perf_lvl_pcnt_3: Decimal | None = Field( + default=None, + validation_alias="WritLangPerfLvl3Pcnt", + sa_column=Column("WritLangPerfLvl3Pcnt", Numeric(5, 2)), + ) + writ_lang_perf_lvl_count_4: int | None = Field( + default=None, + validation_alias="WritLangPerfLvl4Count", + sa_column=Column("WritLangPerfLvl4Count", Integer), + ) + writ_lang_perf_lvl_pcnt_4: Decimal | None = Field( + default=None, + validation_alias="WritLangPerfLvl4Pcnt", + sa_column=Column("WritLangPerfLvl4Pcnt", Numeric(5, 2)), + ) + writ_lang_total: int | None = Field( + default=None, + validation_alias="WritLangTotal", + sa_column=Column("WritLangTotal", Integer), + ) + + model_config = ConfigDict( + alias_generator=to_camel, populate_by_name=True, from_attributes=True + ) + listening_domain_begin_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + listening_domain_begin_count: int | None = Field(default=None) + listening_domain_moderate_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + listening_domain_moderate_count: int | None = Field(default=None) + listening_domain_developed_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + listening_domain_developed_count: int | None = Field(default=None) + listening_domain_total: int | None = Field(default=None) + speaking_domain_begin_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + speaking_domain_begin_count: int | None = Field(default=None) + speaking_domain_moderate_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + speaking_domain_moderate_count: int | None = Field(default=None) + speaking_domain_developed_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + speaking_domain_developed_count: int | None = Field(default=None) + speaking_domain_total: int | None = Field(default=None) + reading_domain_begin_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + reading_domain_begin_count: int | None = Field(default=None) + reading_domain_moderate_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + reading_domain_moderate_count: int | None = Field(default=None) + reading_domain_developed_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + reading_domain_developed_count: int | None = Field(default=None) + reading_domain_total: int | None = Field(default=None) + writing_domain_begin_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + writing_domain_begin_count: int | None = Field(default=None) + writing_domain_moderate_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + writing_domain_moderate_count: int | None = Field(default=None) + writing_domain_developed_pcnt: Decimal | None = Field( + default=None, max_digits=5, decimal_places=2 + ) + writing_domain_developed_count: int | None = Field(default=None) + writing_domain_total: int | None = Field(default=None) + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + + +class AltsaElpacResult(ElpacBase, table=True): + __tablename__ = "altsa_elpac_results" + + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + + # Composite natural key for unique constraint + cds_code: str = Field( + validation_alias="CDSCode", sa_column=Column("cds_code", String(14)) + ) + test_year: int = Field( + validation_alias="TestYear", sa_column=Column("test_year", Integer) + ) + student_group_id: str = Field( + validation_alias="StudentGroupID", sa_column=Column("student_group_id", String) + ) + test_id: int = Field( + validation_alias="TestID", sa_column=Column("test_id", Integer) + ) + grade: str = Field(validation_alias="Grade", sa_column=Column("grade", String(2))) + + # Common result fields (normalized) + filler: str | None = Field( + default=None, validation_alias="Filler", sa_column=Column("filler", String(4)) + ) + type_id: int | None = Field( + default=None, validation_alias="TypeID", sa_column=Column("type_id", Integer) + ) + total_students_enrolled: int | None = Field( + default=None, + validation_alias="TotalStudentsEnrolled", + sa_column=Column("total_students_enrolled", Integer), + ) + total_students_tested: int | None = Field( + default=None, + validation_alias="TotalStudentsTested", + sa_column=Column("total_students_tested", Integer), + ) + total_students_tested_with_scores: int | None = Field( + default=None, + validation_alias="TotalStudentsTestedWithScores", + sa_column=Column("total_students_tested_with_scores", Integer), + ) + overall_total: int | None = Field( + default=None, + validation_alias="OverallTotal", + sa_column=Column("overall_total", Integer), + ) + + __table_args__ = ( + UniqueConstraint( + "cds_code", + "test_year", + "student_group_id", + "test_id", + "grade", + name="ix_altsa_elpac_results_natural_key", + ), + ForeignKeyConstraint(["cds_code"], ["entities.cds_code"]), + ForeignKeyConstraint( + ["student_group_id"], ["elpac_student_groups.student_group_id"] + ), + ForeignKeyConstraint(["test_id"], ["elpac_tests.test_id"]), + Index("ix_altsa_elpac_results_year_grade", "test_year", "grade"), + Index("ix_altsa_elpac_results_student_group", "student_group_id"), + ) + + entity: Entity = Relationship(back_populates="altsa_elpac_results") + overall_mean_scale_score: Decimal | None = Field( + default=None, + validation_alias="OverallMeanScaleScore", + sa_column=Column("OverallMeanScaleScore", Numeric(6, 1)), + ) + overall_perf_lvl_pcnt_1: Decimal | None = Field( + default=None, + validation_alias="OverallPerfLvl1Pcnt", + sa_column=Column("OverallPerfLvl1Pcnt", Numeric(5, 2)), + ) + count_level_1: int | None = Field( + default=None, + validation_alias="OverallPerfLvl1Count", + sa_column=Column("OverallPerfLvl1Count", Integer), + ) + overall_perf_lvl_pcnt_2: Decimal | None = Field( + default=None, + validation_alias="OverallPerfLvl2Pcnt", + sa_column=Column("OverallPerfLvl2Pcnt", Numeric(5, 2)), + ) + count_level_2: int | None = Field( + default=None, + validation_alias="OverallPerfLvl2Count", + sa_column=Column("OverallPerfLvl2Count", Integer), + ) + overall_perf_lvl_pcnt_3: Decimal | None = Field( + default=None, + validation_alias="OverallPerfLvl3Pcnt", + sa_column=Column("OverallPerfLvl3Pcnt", Numeric(5, 2)), + ) + count_level_3: int | None = Field( + default=None, + validation_alias="OverallPerfLvl3Count", + sa_column=Column("OverallPerfLvl3Count", Integer), + ) + + model_config = ConfigDict( + alias_generator=to_camel, populate_by_name=True, from_attributes=True + ) diff --git a/backend/app/model/census_data.py b/backend/app/model/census_data.py index 9c9050f..008e4c4 100644 --- a/backend/app/model/census_data.py +++ b/backend/app/model/census_data.py @@ -1,22 +1,19 @@ import uuid -from sqlmodel import Field, Session, SQLModel, col +from pydantic import ConfigDict +from pydantic.alias_generators import to_camel +from sqlmodel import Field, Session, SQLModel, col, select class CensusDataBase(SQLModel): """ - Shared properties for CensusData + Shared properties for CensusData (Normalized) """ academic_year: int = Field(index=True) aggregation_level: str = Field(index=True) - county_code: str = Field(index=True) - district_code: str = Field(index=True) - school_code: str = Field(index=True) - county_name: str = Field(max_length=255) - district_name: str = Field(max_length=255) - school_name: str = Field(max_length=255) - charter: str = Field(max_length=255) + cds_code: str = Field(index=True, max_length=14) + charter: str | None = Field(default=None, max_length=255) reporting_category: str = Field(max_length=255) total_enr: int = Field(default=0) gr_tk: int = Field(default=0) @@ -34,15 +31,13 @@ class CensusDataBase(SQLModel): gr_11: int = Field(default=0) gr_12: int = Field(default=0) + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + class CensusData(CensusDataBase, table=True): - """ - A simple CensusData model following the same pattern as User. - """ + __tablename__ = "census_data" - census_data_id: uuid.UUID = Field( - default_factory=uuid.uuid4, primary_key=True - ) # need to add timestamp + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) @classmethod def get_total_students_in_school( @@ -50,14 +45,13 @@ def get_total_students_in_school( ) -> dict[str, int | None]: """ Return a dictionary with key 'total-students' that is either row.total_enr or None. - 0 is a valid value. - If no row is found, return {'total-students': None}. """ - query = session.query(cls).filter( - col(cls.school_code) == school_code, - col(cls.reporting_category) == reporting_category, - ) - row = query.first() + row = session.exec( + select(cls).where( + col(cls.cds_code) == school_code, + col(cls.reporting_category) == reporting_category, + ) + ).first() if row: return {"total-students": row.total_enr} else: @@ -69,16 +63,13 @@ def get_total_students_in_school_by_grade( ) -> dict[str, list[int]]: """ Return a dictionary with key 'total_students_by_grade' and value as a list of student counts for grades TK through 12 for this row. - If no row is found, return {'total_students_by_grade': []}. """ - found_row = ( - session.query(cls) - .filter( - col(cls.school_code) == school_code, + found_row = session.exec( + select(cls).where( + col(cls.cds_code) == school_code, col(cls.reporting_category) == reporting_category, ) - .first() - ) + ).first() if not found_row: return {"total_students_by_grade": []} @@ -110,14 +101,12 @@ def get_total_students_in_district( 0 is a valid value. If no row is found, return {'total-students': None}. """ - row = ( - session.query(cls) - .filter( - col(cls.district_code) == district_code, + row = session.exec( + select(cls).where( + col(cls.cds_code) == district_code, col(cls.reporting_category) == reporting_category, ) - .first() - ) + ).first() if row: return {"total-students": row.total_enr} else: @@ -131,14 +120,12 @@ def get_total_students_in_district_by_grade( Return a dictionary with key 'total_students_by_grade' and value as a list of student counts for grades TK through 12 for this district. If no row is found, return {'total_students_by_grade': []}. """ - found_row = ( - session.query(cls) - .filter( - col(cls.district_code) == district_code, + found_row = session.exec( + select(cls).where( + col(cls.cds_code) == district_code, col(cls.reporting_category) == reporting_category, ) - .first() - ) + ).first() if not found_row: return {"total_students_by_grade": []} @@ -170,14 +157,12 @@ def get_total_students_in_county( 0 is a valid value. If no row is found, return {'total-students': None}. """ - row = ( - session.query(cls) - .filter( - col(cls.county_code) == county_code, + row = session.exec( + select(cls).where( + col(cls.cds_code) == county_code, col(cls.reporting_category) == reporting_category, ) - .first() - ) + ).first() if row: return {"total-students": row.total_enr} else: @@ -191,14 +176,12 @@ def get_total_students_in_county_by_grade( Return a dictionary with key 'total_students_by_grade' and value as a list of student counts for grades TK through 12 for this county. If no row is found, return {'total_students_by_grade': []}. """ - found_row = ( - session.query(cls) - .filter( - col(cls.county_code) == county_code, + found_row = session.exec( + select(cls).where( + col(cls.cds_code) == county_code, col(cls.reporting_category) == reporting_category, ) - .first() - ) + ).first() if not found_row: return {"total_students_by_grade": []} @@ -243,9 +226,11 @@ class CensusDataPublic(CensusDataBase): Properties to return via API, id is always required """ - census_data_id: uuid.UUID + id: uuid.UUID class CensusDataPublicList(SQLModel): data: list[CensusDataPublic] count: int + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) diff --git a/backend/app/model/dashboard.py b/backend/app/model/dashboard.py index 1f2070c..cf99105 100644 --- a/backend/app/model/dashboard.py +++ b/backend/app/model/dashboard.py @@ -1,69 +1,65 @@ +from pydantic import ConfigDict +from pydantic.alias_generators import to_camel from sqlmodel import SQLModel class DashboardAggregation(SQLModel): """ - Dashboard aggregation response model (legacy single-indicator) + Aggegrated test data for a CDS code. """ cds: str - schoolname: str | None = None - districtname: str | None = None - countyname: str | None = None - studentgroup: str - currstatus: float | None = None - priorstatus: float | None = None - change: float | None = None - statuslevel: int | None = None # 0-5, used for gauge display - changelevel: int | None = None - color: int | None = None - indicator: str - reportingyear: str + student_group_id: str + test_year: str + overall_met_and_above_pct: str | None = None + overall_mean_scale_score: str | None = None + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) class IndicatorSummary(SQLModel): """ - New dashboard summary response models - Summary of a single indicator for the dashboard. + Summary of a specific CAASPP/ELPAC test result. """ - indicator: str - currstatus: float | None = None - priorstatus: float | None = None - change: float | None = None - statuslevel: int | None = None - changelevel: int | None = None - color: int | None = None - currdenom: int | None = None + test_id: str + test_type: str + grade: str + students_enrolled: str + students_tested: str + overall_mean_scale_score: str | None = None + overall_met_and_above_pct: str | None = None + levels: dict[str, float] | None = None + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) class DashboardSummaryResponse(SQLModel): - """Response containing all indicators for a school/district/state.""" + """Response containing multiple tests for a school/district/county.""" cds: str - rtype: str - schoolname: str | None = None - districtname: str | None = None - countyname: str | None = None - charter_flag: str | None = None - reportingyear: str + test_year: str indicators: list[IndicatorSummary] + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + class EquityGroupSummary(SQLModel): """Summary of a student group for the equity report.""" - studentgroup: str - statuslevel: int | None = None - color: int | None = None - currdenom: int | None = None + student_group: str + overall_met_and_above_pct: str | None = None + students_tested: str | None = None + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) class EquityReportResponse(SQLModel): - """Response containing student group breakdown for an indicator.""" + """Response containing student group breakdown for a test.""" cds: str - indicator: str - reportingyear: str - color_counts: dict[str, int] # {"red": 1, "orange": 2, ...} + test_id: str + test_year: str groups: list[EquityGroupSummary] + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) diff --git a/backend/app/model/item.py b/backend/app/model/item.py index cbba9c1..4bc31b7 100644 --- a/backend/app/model/item.py +++ b/backend/app/model/item.py @@ -1,64 +1,59 @@ import uuid from datetime import datetime +from typing import Annotated, Any, cast +from pydantic import ConfigDict +from pydantic.alias_generators import to_camel from sqlalchemy import DateTime from sqlmodel import Field, Relationship, SQLModel from app.core.utils import get_datetime_utc from app.model.user import User +sa_datetime_type = cast(Any, DateTime(timezone=True)) + +Timestamp = Annotated[ + datetime | None, + Field(default_factory=get_datetime_utc, sa_type=sa_datetime_type), +] -class ItemBase(SQLModel): - """ - Shared item properties. - """ +class ItemBase(SQLModel): title: str = Field(min_length=1, max_length=255) description: str | None = Field(default=None, max_length=255) + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) class ItemCreate(ItemBase): - """ - Properties to receive on item creation - """ - pass class ItemUpdate(ItemBase): - """ - Properties to receive on item update - """ - - title: str | None = Field(default=None, min_length=1, max_length=255) # type: ignore + title: str | None = Field(default=None, min_length=1, max_length=255) class Item(ItemBase, table=True): """ - Database model, database table inferred from class name + An item that is owned by a user. """ + __tablename__ = "items" + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) - created_at: datetime | None = Field( - default_factory=get_datetime_utc, - sa_type=DateTime(timezone=True), # type: ignore - ) + created_at: Timestamp = Field(default_factory=get_datetime_utc) owner_id: uuid.UUID = Field( - foreign_key="user.id", nullable=False, ondelete="CASCADE" + foreign_key="users.id", nullable=False, ondelete="CASCADE" ) owner: User = Relationship(back_populates="items") class ItemPublic(ItemBase): - """ - Properties to return via API, id is always required - """ - id: uuid.UUID owner_id: uuid.UUID - created_at: datetime | None = None + created_at: Timestamp = Field(default_factory=get_datetime_utc) class ItemsPublic(SQLModel): data: list[ItemPublic] count: int + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) diff --git a/backend/app/model/models.py b/backend/app/model/models.py deleted file mode 100644 index 3fbe848..0000000 --- a/backend/app/model/models.py +++ /dev/null @@ -1,26 +0,0 @@ -from sqlmodel import SQLModel - - -class Message(SQLModel): - """ - Generic message - """ - - message: str - - -class Token(SQLModel): - """ - A JSON payload containing the access token. - """ - - access_token: str - token_type: str = "bearer" - - -class TokenPayload(SQLModel): - """ - The contents of the JWT token. - """ - - sub: str | None = None diff --git a/backend/app/model/other.py b/backend/app/model/other.py new file mode 100644 index 0000000..ae26f1c --- /dev/null +++ b/backend/app/model/other.py @@ -0,0 +1,32 @@ +from pydantic import ConfigDict +from pydantic.alias_generators import to_camel +from sqlmodel import SQLModel + + +class Message(SQLModel): + """ + A message for an API response. + """ + + message: str + success: bool = True + status: str | None = None + code: str | int | None = None + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + + +class Token(SQLModel): + """ + A JSON payload containing the access token. The names follow the JWT spec (RFC 7519). + """ + + access_token: str + token_type: str = "bearer" + + +class TokenPayload(SQLModel): + """ + The contents of the JWT token with a subject claim. The names follow the JWT spec (RFC 7519). + """ + + sub: str | None = None diff --git a/backend/app/model/school.py b/backend/app/model/school.py index c6109af..7264151 100644 --- a/backend/app/model/school.py +++ b/backend/app/model/school.py @@ -1,18 +1,18 @@ import uuid +from pydantic import ConfigDict +from pydantic.alias_generators import to_camel from sqlmodel import Field, SQLModel class SchoolBase(SQLModel): """ - SQLModel base class for a school entry. - - Contains all the fields from the provided data, with a separate - field for each part of the physical and mailing address. + A school. + Use a separate field for each part of the physical and mailing address. """ # Unique identifier - cds_code: str = Field(max_length=255, primary_key=True, index=True) + cds_code: str = Field(max_length=255, unique=True, index=True) nces_dist: str = Field(max_length=255) nces_school: str = Field(max_length=255) school_code: str = Field(max_length=255) @@ -80,32 +80,20 @@ class SchoolBase(SQLModel): last_up_date: str | None = Field(default=None, max_length=255) multilingual: str | None = Field(default=None, max_length=255) + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) -class School(SchoolBase, table=True): - """ - SQLModel database table class for a school entry. - Inherits all fields from `SchoolBase` and adds the primary key. - """ +class School(SchoolBase, table=True): + __tablename__ = "schools" id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) - # id: int | None = Field(default=None, primary_key=True) class SchoolCreate(SchoolBase): - """ - A Pydantic model for creating new school entries. It uses the base model but - doesn't require the ID, which will be generated by the database. - """ - pass class SchoolPublic(SchoolBase): - """ - Properties to return via API, id is always required - """ - id: uuid.UUID @@ -113,12 +101,10 @@ class SchoolsPublic(SQLModel): data: list[SchoolPublic] count: int + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) -class SchoolSummary(SQLModel): - """ - Properties for a refined school view. - """ +class SchoolSummary(SQLModel): id: uuid.UUID school: str | None = None city: str | None = None @@ -126,7 +112,11 @@ class SchoolSummary(SQLModel): cds_code: str | None = None school_code: str | None = None + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + class SchoolsSummary(SQLModel): data: list[SchoolSummary] count: int + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) diff --git a/backend/app/model/user.py b/backend/app/model/user.py index 7c369c2..c99833d 100644 --- a/backend/app/model/user.py +++ b/backend/app/model/user.py @@ -1,8 +1,9 @@ import uuid from datetime import datetime -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated, Any, cast -from pydantic import EmailStr +from pydantic import ConfigDict, EmailStr +from pydantic.alias_generators import to_camel from sqlalchemy import DateTime from sqlmodel import Field, Relationship, SQLModel @@ -11,6 +12,13 @@ if TYPE_CHECKING: from app.model.item import Item +sa_datetime_type = cast(Any, DateTime(timezone=True)) + +Timestamp = Annotated[ + datetime | None, + Field(default_factory=get_datetime_utc, sa_type=sa_datetime_type), +] + class UserBase(SQLModel): email: EmailStr = Field(unique=True, index=True, max_length=255) @@ -18,6 +26,8 @@ class UserBase(SQLModel): is_superuser: bool = False full_name: str | None = Field(default=None, max_length=255) + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + class UserCreate(UserBase): password: str = Field(min_length=8, max_length=128) @@ -28,9 +38,11 @@ class UserRegister(SQLModel): password: str = Field(min_length=8, max_length=128) full_name: str | None = Field(default=None, max_length=255) + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + class UserUpdate(UserBase): - email: EmailStr | None = Field(default=None, max_length=255) # type: ignore + email: EmailStr | None = Field(default=None, max_length=255) password: str | None = Field(default=None, min_length=8, max_length=128) force_password_reset: bool | None = None @@ -38,30 +50,32 @@ class UserUpdate(UserBase): class UserUpdateMe(SQLModel): full_name: str | None = Field(default=None, max_length=255) email: EmailStr | None = Field(default=None, max_length=255) + last_viewed_cds: str | None = Field(default=None, max_length=14) + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) class UpdatePassword(SQLModel): current_password: str = Field(min_length=8, max_length=128) new_password: str = Field(min_length=8, max_length=128) + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + class User(UserBase, table=True): + __tablename__ = "users" id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) hashed_password: str - created_at: datetime | None = Field( - default_factory=get_datetime_utc, - sa_type=DateTime(timezone=True), # type: ignore - ) - items: list["Item"] = Relationship(back_populates="owner", cascade_delete=True) - # User preferences + created_at: Timestamp = Field(default_factory=get_datetime_utc) + items: list[Item] = Relationship(back_populates="owner", cascade_delete=True) last_viewed_cds: str | None = Field(default=None, max_length=14) force_password_reset: bool = Field(default=False) class UserPublic(UserBase): id: uuid.UUID - created_at: datetime | None = None - force_password_reset: bool = False + created_at: Timestamp = Field(default_factory=get_datetime_utc) + force_password_reset: bool = Field(default=False) class UsersPublic(SQLModel): @@ -70,16 +84,20 @@ class UsersPublic(SQLModel): class UserPreferencesUpdate(SQLModel): - """Request model for updating user preferences.""" - last_viewed_cds: str | None = Field(default=None, max_length=14) + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + class NewPassword(SQLModel): token: str new_password: str = Field(min_length=8, max_length=128) + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + class ForcePasswordResetRequest(SQLModel): emails: list[EmailStr] = Field(default_factory=list) include_all_active_users: bool = False + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) diff --git a/backend/app/scripts/backend_pre_start.py b/backend/app/scripts/backend_pre_start.py index a03abd6..35d2cfb 100644 --- a/backend/app/scripts/backend_pre_start.py +++ b/backend/app/scripts/backend_pre_start.py @@ -5,7 +5,7 @@ from tenacity import after_log, before_log, retry, stop_after_attempt, wait_fixed from app.core.database import engine -from app.scripts.gcp.gcp_utils import load_repo_env_if_present +from app.scripts.gcp_utils import load_repo_env_if_present load_repo_env_if_present(__file__, scope="backend_pre_start") diff --git a/backend/app/scripts/cde/__init__.py b/backend/app/scripts/cde/__init__.py deleted file mode 100644 index 7a9002e..0000000 --- a/backend/app/scripts/cde/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -""" -Indicator data cde for California School Dashboard. - -This package provides parsers for importing accountability indicator data -from various sources: -- CDE Excel files (eladownload2025.xlsx, etc.) -- State assessment TXT files (caret-delimited) -""" - -from .base import BaseIndicatorParser -from .cde_parser import CDEParser -from .state_parser import StateParser - -__all__ = ["BaseIndicatorParser", "CDEParser", "StateParser"] diff --git a/backend/app/scripts/cde/base.py b/backend/app/scripts/cde/base.py deleted file mode 100644 index 35b6bb5..0000000 --- a/backend/app/scripts/cde/base.py +++ /dev/null @@ -1,317 +0,0 @@ -""" -Base class for indicator data parsers. - -Provides common functionality for parsing and importing California Dashboard -accountability indicator data. -""" - -import sys -from abc import ABC, abstractmethod -from collections.abc import Generator -from pathlib import Path -from typing import Any - -import pandas as pd # type: ignore[import-untyped] -from sqlmodel import Session - -# Add the parent directory to the path so we can import app modules -sys.path.insert(0, str(Path(__file__).parent.parent.parent)) - -from app.model.academic_indicator import AcademicIndicator - - -class BaseIndicatorParser(ABC): - """Abstract base class for indicator parsers.""" - - INDICATOR: str = "" - BATCH_SIZE: int = 1000 - - # Maps raw indicator values from source files to canonical names. - INDICATOR_NORMALIZE: dict[str, str] = { - "CHRO": "CHRONIC", - } - - # Common fields across all indicators - COMMON_MAPPING = { - "cds": "cds", - "rtype": "rtype", - "schoolname": "schoolname", - "districtname": "districtname", - "countyname": "countyname", - "charter_flag": "charter_flag", - "coe_flag": "coe_flag", - "dass_flag": "dass_flag", - "studentgroup": "studentgroup", - "currdenom": "currdenom", - "currstatus": "currstatus", - "priordenom": "priordenom", - "priorstatus": "priorstatus", - "change": "change", - "statuslevel": "statuslevel", - "changelevel": "changelevel", - "color": "color", - "box": "box", - "currnsizemet": "currnsizemet", - "priornsizemet": "priornsizemet", - "accountabilitymet": "accountabilitymet", - "hscutpoints": "hscutpoints", - "pairshare_method": "pairshare_method", - "currprate_enrolled": "currprate_enrolled", - "currprate_tested": "currprate_tested", - "currprate": "currprate", - "currnumprloss": "currnumprloss", - "currdenom_withoutprloss": "currdenom_withoutprloss", - "currstatus_withoutprloss": "currstatus_withoutprloss", - "priorprate_enrolled": "priorprate_enrolled", - "priorprate_tested": "priorprate_tested", - "priorprate": "priorprate", - "priornumprloss": "priornumprloss", - "priordenom_withoutprloss": "priordenom_withoutprloss", - "priorstatus_withoutprloss": "priorstatus_withoutprloss", - "indicator": "indicator", - "reportingyear": "reportingyear", - } - - # Integer fields - INT_FIELDS = { - "currdenom", - "priordenom", - "statuslevel", - "changelevel", - "color", - "box", - "currprate_enrolled", - "currprate_tested", - "currnumprloss", - "currdenom_withoutprloss", - "priorprate_enrolled", - "priorprate_tested", - "priornumprloss", - "priordenom_withoutprloss", - "currnumer", - "priornumer", - "fiveyrnumer", - "currprogressed", - "currmaintainpl4", - "currmaintainoth", - "currdeclined", - "currprogressed_alternate", - "currmaintainpl3_alternate", - "currnotprognotmain_alternate", - "curr95", - "priorprogressed", - "priormaintainpl4", - "priormaintainoth", - "priordeclined", - "priorprogressed_alternate", - "priormaintainpl3_alternate", - "priornotprognotmain_alternate", - "prior95", - } - - # Float fields - FLOAT_FIELDS = { - "currstatus", - "priorstatus", - "change", - "currprate", - "currstatus_withoutprloss", - "priorprate", - "priorstatus_withoutprloss", - "studentgroup_pct", - } - - @abstractmethod - def get_extra_fields(self) -> dict[str, str]: - """Return indicator-specific field mappings. - - Returns: - dict mapping source column names to model field names - """ - pass - - def get_all_fields(self) -> dict[str, str]: - """Get combined common and extra field mappings.""" - return {**self.COMMON_MAPPING, **self.get_extra_fields()} - - @staticmethod - def clean_value(value: Any, field_type: str = "str") -> Any: - """Clean a value for database insertion. - - Args: - value: The value to clean - field_type: One of 'str', 'int', or 'float' - - Returns: - Cleaned value or None if invalid - """ - if pd.isna(value) or value == "" or value == "*": - return None - - if field_type == "int": - try: - return int(float(value)) - except (ValueError, TypeError): - return None - elif field_type == "float": - try: - return float(value) - except (ValueError, TypeError): - return None - else: - return str(value).strip() if value else None - - def parse_row(self, row: pd.Series, columns: list[str]) -> dict[str, Any] | None: - """Parse a single row into a model data dictionary. - - Args: - row: pandas Series representing a row - columns: list of column names in the DataFrame - - Returns: - dict suitable for AcademicIndicator model or None if invalid - """ - record_data = {} - field_mapping = self.get_all_fields() - - for source_col, model_field in field_mapping.items(): - source_col_lower = source_col.lower() - if source_col_lower in columns: - if model_field in self.INT_FIELDS: - record_data[model_field] = self.clean_value( - row[source_col_lower], "int" - ) - elif model_field in self.FLOAT_FIELDS: - record_data[model_field] = self.clean_value( - row[source_col_lower], "float" - ) - else: - record_data[model_field] = self.clean_value( - row[source_col_lower], "str" - ) - - # Ensure CDS code is padded to 14 characters - # Handle statewide aggregate (rtype = 'X') where CDS might be missing/empty in Excel - if not record_data.get("cds") and record_data.get("rtype") == "X": - record_data["cds"] = "00000000000000" - - if record_data.get("cds"): - cds = str(record_data["cds"]).strip() - # Remove any decimal points (e.g., "0.0" -> "0") - if "." in cds: - cds = cds.split(".")[0] - record_data["cds"] = cds.zfill(14) - - # Ensure required fields are present - if not record_data.get("cds") or not record_data.get("studentgroup"): - return None - - # Set defaults for required fields - if not record_data.get("rtype"): - record_data["rtype"] = "S" - if not record_data.get("indicator"): - record_data["indicator"] = self.INDICATOR - else: - record_data["indicator"] = self.INDICATOR_NORMALIZE.get( - record_data["indicator"], record_data["indicator"] - ) - if not record_data.get("reportingyear"): - record_data["reportingyear"] = "2025" - - return record_data - - def parse_cci_details( - self, row: pd.Series, columns: list[str] - ) -> dict[str, Any] | None: - """Parse CCI-specific breakdown fields into a JSON object. - - Args: - row: pandas Series representing a row - columns: list of column names in the DataFrame - - Returns: - dict containing CCI detail fields - """ - cci_details = {} - # CCI fields start with curr_prep_, curr_aprep_, prior_prep_, prior_aprep_ - cci_prefixes = ("curr_prep_", "curr_aprep_", "prior_prep_", "prior_aprep_") - - for col in columns: - col_lower = col.lower() - if any(col_lower.startswith(prefix) for prefix in cci_prefixes): - value = self.clean_value(row[col_lower], "int") - if value is not None: - cci_details[col_lower] = value - - return cci_details if cci_details else None - - def parse_dataframe( - self, df: pd.DataFrame - ) -> Generator[AcademicIndicator, None, None]: - """Parse a DataFrame into AcademicIndicator records. - - Args: - df: pandas DataFrame with indicator data - - Yields: - AcademicIndicator instances - """ - # Normalize column names to lowercase - df.columns = df.columns.str.lower() - columns = list(df.columns) - - for idx, row in df.iterrows(): - try: - record_data = self.parse_row(row, columns) - if record_data is None: - continue - - # Handle CCI-specific JSON details - if self.INDICATOR == "CCI": - cci_details = self.parse_cci_details(row, columns) - if cci_details: - record_data["cci_details"] = cci_details - - yield AcademicIndicator(**record_data) - - except Exception as e: - print(f"Error processing row {idx}: {e}") - continue - - def import_to_session( - self, - session: Session, - records: Generator[AcademicIndicator, None, None], - batch_size: int | None = None, - ) -> int: - """Import records to the database in batches. - - Args: - session: SQLModel Session - records: Generator of AcademicIndicator instances - batch_size: Override default batch size - - Returns: - Number of records imported - """ - batch_size = batch_size or self.BATCH_SIZE - batch = [] - total_inserted = 0 - - for record in records: - batch.append(record) - if len(batch) >= batch_size: - session.add_all(batch) - session.commit() - total_inserted += len(batch) - print(f"Inserted batch: {total_inserted} records") - batch = [] - - # Insert remaining records - if batch: - session.add_all(batch) - session.commit() - total_inserted += len(batch) - print(f"Inserted final batch: {total_inserted} records") - - return total_inserted diff --git a/backend/app/scripts/cde/cde_parser.py b/backend/app/scripts/cde/cde_parser.py deleted file mode 100644 index e1e8a50..0000000 --- a/backend/app/scripts/cde/cde_parser.py +++ /dev/null @@ -1,186 +0,0 @@ -""" -CDE Excel file parser for California Dashboard indicator data. - -Parses Excel files downloaded from the California Department of Education -Dashboard download site. -""" - -import sys -from collections.abc import Generator -from pathlib import Path - -import pandas as pd # type: ignore[import-untyped] -from sqlmodel import Session - -from .base import BaseIndicatorParser - -sys.path.insert(0, str(Path(__file__).parent.parent.parent)) - -from app.model.academic_indicator import AcademicIndicator - - -class CDEParser(BaseIndicatorParser): - """Parser for CDE Excel download files.""" - - def __init__(self, indicator: str) -> None: - """Initialize parser for a specific indicator. - - Args: - indicator: One of ELA, MATH, SCI, CHRONIC, SUSP, GRAD, ELPI, CCI - """ - self.INDICATOR = indicator.upper() - - def get_extra_fields(self) -> dict[str, str]: - """Return indicator-specific field mappings.""" - extra = {} - - if self.INDICATOR in ("CHRONIC", "SUSP", "GRAD", "ELPI"): - # Common extended fields - extra.update( - { - "currnumer": "currnumer", - "priornumer": "priornumer", - "smalldenom": "smalldenom", - "certifyflag": "certifyflag", - "priorcertifyflag": "priorcertifyflag", - "dataerrorflag": "dataerrorflag", - } - ) - - if self.INDICATOR == "SUSP": - # Suspension has a 'type' column - extra["type"] = "school_type" - - if self.INDICATOR == "GRAD": - extra["fiveyrnumer"] = "fiveyrnumer" - - if self.INDICATOR == "ELPI": - # ELPI-specific fields - extra.update( - { - "currprogressed": "currprogressed", - "currmaintainpl4": "currmaintainpl4", - "currmaintainoth": "currmaintainoth", - "currdeclined": "currdeclined", - "currprogressed_alternate": "currprogressed_alternate", - "currmaintainpl3_alternate": "currmaintainpl3_alternate", - "currnotprognotmain_alternate": "currnotprognotmain_alternate", - "curr95": "curr95", - "priorprogressed": "priorprogressed", - "priormaintainpl4": "priormaintainpl4", - "priormaintainoth": "priormaintainoth", - "priordeclined": "priordeclined", - "priorprogressed_alternate": "priorprogressed_alternate", - "priormaintainpl3_alternate": "priormaintainpl3_alternate", - "priornotprognotmain_alternate": "priornotprognotmain_alternate", - "prior95": "prior95", - } - ) - - if self.INDICATOR == "CCI": - extra["studentgroup_pct"] = "studentgroup_pct" - # Note: CCI has many additional fields stored in cci_details JSON - - return extra - - def parse_excel( - self, file_path: str | Path - ) -> Generator[AcademicIndicator, None, None]: - """Parse an Excel file and yield AcademicIndicator records. - - Args: - file_path: Path to the Excel file - - Yields: - AcademicIndicator instances - """ - file_path = Path(file_path) - print(f"Reading Excel file: {file_path}") - - df = pd.read_excel(file_path) - print(f"Found {len(df)} rows in Excel file") - print(f"Columns: {list(df.columns)}") - - yield from self.parse_dataframe(df) - - def import_file( - self, session: Session, file_path: str | Path, batch_size: int | None = None - ) -> int: - """Import an Excel file to the database. - - Args: - session: SQLModel Session - file_path: Path to the Excel file - batch_size: Override default batch size - - Returns: - Number of records imported - """ - records = self.parse_excel(file_path) - return self.import_to_session(session, records, batch_size) - - -# Indicator-specific parser classes for convenience -class ELAParser(CDEParser): - def __init__(self) -> None: - super().__init__("ELA") - - -class MATHParser(CDEParser): - def __init__(self) -> None: - super().__init__("MATH") - - -class SCIParser(CDEParser): - def __init__(self) -> None: - super().__init__("SCI") - - -class CHRONICParser(CDEParser): - def __init__(self) -> None: - super().__init__("CHRONIC") - - -class SUSPParser(CDEParser): - def __init__(self) -> None: - super().__init__("SUSP") - - -class GRADParser(CDEParser): - def __init__(self) -> None: - super().__init__("GRAD") - - -class ELPIParser(CDEParser): - def __init__(self) -> None: - super().__init__("ELPI") - - -class CCIParser(CDEParser): - def __init__(self) -> None: - super().__init__("CCI") - - -# Mapping of indicator codes to file patterns -INDICATOR_FILES = { - "ELA": "eladownload*.xlsx", - "MATH": "mathdownload*.xlsx", - "SCI": "sciencedownload*.xlsx", - "CHRONIC": "chronicdownload*.xlsx", - "SUSP": "suspdownload*.xlsx", - "GRAD": "graddownload*.xlsx", - "ELPI": "elpidownload*.xlsx", - "CCI": "ccidownload*.xlsx", -} - - -def get_parser(indicator: str) -> CDEParser: - """Get the appropriate parser for an indicator. - - Args: - indicator: Indicator code (ELA, MATH, etc.) - - Returns: - CDEParser instance configured for the indicator - """ - return CDEParser(indicator) diff --git a/backend/app/scripts/cde/import_ela_data.py b/backend/app/scripts/cde/import_ela_data.py deleted file mode 100644 index e1f8dac..0000000 --- a/backend/app/scripts/cde/import_ela_data.py +++ /dev/null @@ -1,312 +0,0 @@ -#!/usr/bin/env python3 -""" -Import California Dashboard ELA Academic Indicator data from Excel file. - -Usage: - cd backend - source ../.venv/bin/activate - python scripts/import_ela_data.py ~/Downloads/resources/eladownload2025.xlsx -""" - -import argparse -import sys -from pathlib import Path -from typing import Any - -import pandas as pd # type: ignore[import-untyped] -from sqlmodel import Session - -# Add the parent directory to the path so we can import app modules -sys.path.insert(0, str(Path(__file__).parent.parent)) - -from app.core.database import engine -from app.model.academic_indicator import AcademicIndicator -from app.scripts.cde.import_plan import ( - ImportCategory, - count_existing_rows, - delete_category_rows, - detect_reporting_year, - render_ascii_table, -) -from app.scripts.gcp.gcp_utils import load_repo_env_if_present - -load_repo_env_if_present(__file__, scope="import_ela_data") - -# Column mapping from Excel to model fields (lowercase) -COLUMN_MAPPING = { - "cds": "cds", - "rtype": "rtype", - "schoolname": "schoolname", - "districtname": "districtname", - "countyname": "countyname", - "charter_flag": "charter_flag", - "coe_flag": "coe_flag", - "dass_flag": "dass_flag", - "studentgroup": "studentgroup", - "currdenom": "currdenom", - "currstatus": "currstatus", - "priordenom": "priordenom", - "priorstatus": "priorstatus", - "change": "change", - "statuslevel": "statuslevel", - "changelevel": "changelevel", - "color": "color", - "box": "box", - "currnsizemet": "currnsizemet", - "priornsizemet": "priornsizemet", - "accountabilitymet": "accountabilitymet", - "hscutpoints": "hscutpoints", - "pairshare_method": "pairshare_method", - "currprate_enrolled": "currprate_enrolled", - "currprate_tested": "currprate_tested", - "currprate": "currprate", - "currnumprloss": "currnumprloss", - "currdenom_withoutprloss": "currdenom_withoutprloss", - "currstatus_withoutprloss": "currstatus_withoutprloss", - "priorprate_enrolled": "priorprate_enrolled", - "priorprate_tested": "priorprate_tested", - "priorprate": "priorprate", - "priornumprloss": "priornumprloss", - "priordenom_withoutprloss": "priordenom_withoutprloss", - "priorstatus_withoutprloss": "priorstatus_withoutprloss", - "indicator": "indicator", - "reportingyear": "reportingyear", -} - - -def clean_value(value: Any, field_type: str = "str") -> Any: - """Clean a value for database insertion.""" - if pd.isna(value) or value == "" or value == "*": - return None - - if field_type == "int": - try: - return int(float(value)) - except (ValueError, TypeError): - return None - elif field_type == "float": - try: - return float(value) - except (ValueError, TypeError): - return None - else: - return str(value).strip() if value else None - - -def _print_report(title: str, category: ImportCategory) -> None: - rows = [ - [ - category.source, - category.indicator, - category.reporting_year, - str(category.existing_rows), - category.action, - category.status, - str(category.imported_rows), - str(category.deleted_rows), - category.message, - category.path, - ] - ] - print(f"\n{title}") - print( - render_ascii_table( - [ - "source", - "indicator", - "year", - "existing_rows", - "action", - "status", - "imported_rows", - "deleted_rows", - "message", - "path", - ], - rows, - ) - ) - - -def import_ela_data( - file_path: str, - batch_size: int = 1000, - *, - overwrite: bool = False, - reporting_year: str | None = None, -) -> int: - """Import ELA data from Excel file into the database.""" - resolved_path = Path(file_path).expanduser().resolve() - if reporting_year: - year = reporting_year - else: - year = detect_reporting_year(resolved_path) - - category = ImportCategory( - source="cde", - indicator="ELA", - reporting_year=year, - path=str(resolved_path), - ) - - with Session(engine) as session: - category.existing_rows = count_existing_rows( - session, - indicator=category.indicator, - reporting_year=category.reporting_year, - ) - - category.action = ( - "overwrite" - if (category.existing_rows > 0 and overwrite) - else ("skip_existing" if category.existing_rows > 0 else "import") - ) - _print_report("ELA Import Plan", category) - - if category.existing_rows > 0 and not overwrite: - category.status = "skipped" - category.message = "existing data found; rerun with --overwrite" - _print_report("ELA Import Result", category) - return 0 - - print(f"Reading Excel file: {resolved_path}") - df = pd.read_excel(resolved_path) - - # Normalize column names to lowercase - df.columns = df.columns.str.lower() - - print(f"Found {len(df)} rows in Excel file") - print(f"Columns: {list(df.columns)}") - - # Define field types - int_fields = { - "currdenom", - "priordenom", - "statuslevel", - "changelevel", - "color", - "box", - "currprate_enrolled", - "currprate_tested", - "currnumprloss", - "currdenom_withoutprloss", - "priorprate_enrolled", - "priorprate_tested", - "priornumprloss", - "priordenom_withoutprloss", - } - float_fields = { - "currstatus", - "priorstatus", - "change", - "currprate", - "currstatus_withoutprloss", - "priorprate", - "priorstatus_withoutprloss", - } - - records = [] - skipped = 0 - - for idx, row in df.iterrows(): - try: - record_data = {} - - for excel_col, model_field in COLUMN_MAPPING.items(): - if excel_col in df.columns: - if model_field in int_fields: - record_data[model_field] = clean_value(row[excel_col], "int") - elif model_field in float_fields: - record_data[model_field] = clean_value(row[excel_col], "float") - else: - record_data[model_field] = clean_value(row[excel_col], "str") - - # Ensure required fields are present - # Handle statewide aggregate (rtype = 'X') where CDS might be missing/empty in Excel - if not record_data.get("cds") and record_data.get("rtype") == "X": - record_data["cds"] = "00000000000000" - - if not record_data.get("cds") or not record_data.get("studentgroup"): - skipped += 1 - continue - - # Set defaults for required fields - if not record_data.get("rtype"): - record_data["rtype"] = "S" - if not record_data.get("indicator"): - record_data["indicator"] = "ELA" - if not record_data.get("reportingyear"): - record_data["reportingyear"] = category.reporting_year - - records.append(AcademicIndicator(**record_data)) - - except Exception as e: - print(f"Error processing row {idx}: {e}") - skipped += 1 - continue - - print(f"Prepared {len(records)} records for insertion ({skipped} skipped)") - - # Insert in batches - with Session(engine) as session: - if category.existing_rows > 0 and overwrite: - category.deleted_rows = delete_category_rows( - session, - indicator=category.indicator, - reporting_year=category.reporting_year, - ) - - total_inserted = 0 - for i in range(0, len(records), batch_size): - batch = records[i : i + batch_size] - session.add_all(batch) - session.commit() - total_inserted += len(batch) - print( - f"Inserted batch {i // batch_size + 1}: {total_inserted} / {len(records)}" - ) - - category.imported_rows = total_inserted - category.status = "imported" - category.message = "completed" - _print_report("ELA Import Result", category) - print(f"Successfully imported {total_inserted} records") - return total_inserted - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Import ELA indicator data") - parser.add_argument("path", type=Path, help="Path to ELA Excel file") - parser.add_argument( - "--batch-size", - type=int, - default=1000, - help="Records per batch (default: 1000)", - ) - parser.add_argument( - "--overwrite", - action="store_true", - help="Overwrite existing ELA rows for the target reporting year.", - ) - parser.add_argument( - "--reporting-year", - default=None, - help="Optional reporting year override. Defaults to year in filename/folder.", - ) - args = parser.parse_args() - - if args.batch_size <= 0: - print("Error: --batch-size must be > 0") - sys.exit(1) - - file_path = args.path.expanduser().resolve() - if not file_path.exists(): - print(f"Error: File not found: {file_path}") - sys.exit(1) - - import_ela_data( - str(file_path), - batch_size=args.batch_size, - overwrite=args.overwrite, - reporting_year=args.reporting_year, - ) diff --git a/backend/app/scripts/cde/import_indicators.py b/backend/app/scripts/cde/import_indicators.py deleted file mode 100644 index d447f34..0000000 --- a/backend/app/scripts/cde/import_indicators.py +++ /dev/null @@ -1,490 +0,0 @@ -#!/usr/bin/env python3 -""" -Import California Dashboard indicator data from various sources. - -Supports both CDE Excel files and state assessment TXT files. - -Usage: - # Import a single indicator from CDE Excel file - python app/scripts/cde/import_indicators.py --indicator ELA --path ~/Downloads/resources/cde/eladownload2025.xlsx - - # Import all indicators from a CDE directory - python app/scripts/cde/import_indicators.py --source cde --path ~/Downloads/resources/cde/ - - # Import from state assessment files - python app/scripts/cde/import_indicators.py --source state --indicator ELA --path ~/Desktop/resources/california-state/sb_ca2025_all_csv_ela_v1.txt - - # List available indicators - python app/scripts/cde/import_indicators.py --list -""" - -import argparse -import fnmatch -import sys -from concurrent.futures import ThreadPoolExecutor, as_completed -from pathlib import Path - -# Add the parent directory to the path so we can import app modules -sys.path.insert(0, str(Path(__file__).parent.parent)) - -from sqlmodel import Session - -from app.core.database import engine -from app.scripts.cde.base import BaseIndicatorParser -from app.scripts.cde.cde_parser import INDICATOR_FILES, CDEParser -from app.scripts.cde.import_plan import ( - ImportCategory, - count_existing_rows, - delete_category_rows, - detect_reporting_year, - render_ascii_table, -) -from app.scripts.cde.state_parser import STATE_FILES, StateParser -from app.scripts.gcp.gcp_utils import load_repo_env_if_present - -load_repo_env_if_present(__file__, scope="import_indicators") - - -INDICATORS = ["ELA", "MATH", "SCI", "CHRONIC", "SUSP", "GRAD", "ELPI", "CCI"] - - -def _matches_year_filter(file_path: Path, years: set[str] | None) -> bool: - if not years: - return True - name = file_path.name.lower() - return any(year in name for year in years) - - -def _resolve_indicator_from_name(file_path: Path, source: str) -> str | None: - file_name = file_path.name.lower() - patterns = INDICATOR_FILES if source == "cde" else STATE_FILES - for indicator, pattern in patterns.items(): - if fnmatch.fnmatch(file_name, pattern.lower()): - return indicator - return None - - -def _collect_categories( - *, - path: Path, - source: str, - indicator: str | None, - all_files: bool, - years: set[str] | None, -) -> list[ImportCategory]: - categories: list[ImportCategory] = [] - - def _append(file_path: Path, resolved_indicator: str) -> None: - year = detect_reporting_year(file_path) - categories.append( - ImportCategory( - source=source, - indicator=resolved_indicator, - reporting_year=year, - path=str(file_path), - ) - ) - - if path.is_file(): - if not indicator: - raise ValueError("--indicator is required when importing a single file") - _append(path, indicator) - return categories - - if source == "cde": - selected_indicators = [indicator] if indicator else list(INDICATOR_FILES.keys()) - for indicator_code in selected_indicators: - pattern = INDICATOR_FILES[indicator_code] - files = sorted(path.glob(pattern)) - files = [f for f in files if _matches_year_filter(f, years)] - if not files: - continue - selected_files = files if all_files else [files[-1]] - for file_path in selected_files: - _append(file_path, indicator_code) - return categories - - selected_indicators = [indicator] if indicator else list(STATE_FILES.keys()) - for indicator_code in selected_indicators: - pattern = STATE_FILES[indicator_code] - files = sorted(path.glob(pattern)) - files = [f for f in files if _matches_year_filter(f, years)] - if not files: - continue - selected_files = files if all_files else [files[-1]] - for file_path in selected_files: - _append(file_path, indicator_code) - - return categories - - -def _print_categories_report(title: str, categories: list[ImportCategory]) -> None: - rows = [ - [ - c.source, - c.indicator, - c.reporting_year, - str(c.existing_rows), - c.action, - c.status, - str(c.imported_rows), - str(c.deleted_rows), - c.message, - c.path, - ] - for c in categories - ] - print(f"\n{title}") - if not rows: - print("No matching files/categories found.") - return - print( - render_ascii_table( - [ - "source", - "indicator", - "year", - "existing_rows", - "action", - "status", - "imported_rows", - "deleted_rows", - "message", - "path", - ], - rows, - ) - ) - - -def import_single_file( - file_path: Path, indicator: str, source: str = "cde", batch_size: int = 5000 -) -> int: - """Import a single file. - - Args: - file_path: Path to the file - indicator: Indicator code - source: 'cde' or 'state' - batch_size: Records per batch - - Returns: - Number of records imported - """ - parser: BaseIndicatorParser - if source == "cde": - parser = CDEParser(indicator) - parse_method = parser.parse_excel - else: - parser = StateParser(indicator) - parse_method = parser.parse_txt - - print(f"\nImporting {indicator} from {file_path}") - print(f"Source: {source.upper()}") - - with Session(engine) as session: - records = parse_method(file_path) - count = parser.import_to_session(session, records, batch_size) - - print(f"Successfully imported {count} records for {indicator}") - return int(count) - - -def import_cde_directory( - dir_path: Path, - batch_size: int = 1000, - workers: int = 4, - *, - all_files: bool = False, - years: set[str] | None = None, -) -> dict[str, int]: - """Import all CDE files from a directory. - - Args: - dir_path: Directory containing CDE Excel files - batch_size: Records per batch - - Returns: - dict mapping indicator to record count - """ - results: dict[str, int] = {} - - jobs: list[tuple[str, Path]] = [] - for indicator, pattern in INDICATOR_FILES.items(): - # Find matching files - files = sorted(dir_path.glob(pattern)) - files = [f for f in files if _matches_year_filter(f, years)] - if not files: - print(f"\nNo files found for {indicator} (pattern: {pattern})") - continue - - selected_files = files if all_files else [files[-1]] - for file_path in selected_files: - jobs.append((indicator, file_path)) - - if not jobs: - return results - - imported_totals = dict.fromkeys(INDICATOR_FILES, 0) - with ThreadPoolExecutor(max_workers=max(1, workers)) as executor: - future_to_job = { - executor.submit( - import_single_file, file_path, indicator, "cde", batch_size - ): (indicator, file_path) - for indicator, file_path in jobs - } - for future in as_completed(future_to_job): - indicator, file_path = future_to_job[future] - try: - count = future.result() - imported_totals[indicator] = imported_totals.get(indicator, 0) + count - except Exception as e: - print(f"Error importing {indicator} from {file_path.name}: {e}") - - results.update({k: v for k, v in imported_totals.items() if v > 0}) - - return results - - -def import_state_directory( - dir_path: Path, - indicators: list[str] | None = None, - batch_size: int = 1000, - workers: int = 4, -) -> dict[str, int]: - """Import state assessment files from a directory. - - Args: - dir_path: Directory containing state TXT files - indicators: List of indicators to import (default: all) - batch_size: Records per batch - - Returns: - dict mapping indicator to record count - """ - results: dict[str, int] = {} - indicators = indicators or list(STATE_FILES.keys()) - - jobs: list[tuple[str, Path]] = [] - for indicator in indicators: - if indicator not in STATE_FILES: - print(f"\nNo state file pattern for {indicator}") - continue - - pattern = STATE_FILES[indicator] - files = list(dir_path.glob(pattern)) - if not files: - print(f"\nNo files found for {indicator} (pattern: {pattern})") - continue - - # Use the most recent file if multiple exist - file_path = sorted(files)[-1] - jobs.append((indicator, file_path)) - - with ThreadPoolExecutor(max_workers=max(1, workers)) as executor: - future_to_indicator = { - executor.submit( - import_single_file, file_path, indicator, "state", batch_size - ): indicator - for indicator, file_path in jobs - } - for future in as_completed(future_to_indicator): - indicator = future_to_indicator[future] - try: - results[indicator] = future.result() - except Exception as e: - print(f"Error importing {indicator}: {e}") - results[indicator] = 0 - - return results - - -def main() -> None: - parser = argparse.ArgumentParser( - description="Import California Dashboard indicator data", - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=__doc__, - ) - - parser.add_argument( - "--indicator", - "-i", - choices=INDICATORS, - help="Specific indicator to import", - ) - parser.add_argument( - "--source", - "-s", - choices=["cde", "state"], - default="cde", - help="Data source type (default: cde)", - ) - parser.add_argument( - "--path", - "-p", - type=Path, - help="Path to file or directory", - ) - parser.add_argument( - "--batch-size", - "-b", - type=int, - default=5000, - help="Records per batch (default: 5000)", - ) - parser.add_argument( - "--workers", - type=int, - default=4, - help="Thread workers for parallel file imports (default: 4).", - ) - parser.add_argument( - "--list", - "-l", - action="store_true", - help="List available indicators", - ) - parser.add_argument( - "--all-files", - action="store_true", - help="Import all matching files in a directory (default imports only latest).", - ) - parser.add_argument( - "--years", - help="Comma-separated year filters for file names, e.g. 2024,2025.", - ) - parser.add_argument( - "--overwrite", - action="store_true", - help="Overwrite existing rows for each category (indicator + reporting year).", - ) - - args = parser.parse_args() - - if args.list: - print("Available indicators:") - print("\nCDE Excel files (--source cde):") - for ind, pattern in INDICATOR_FILES.items(): - print(f" {ind}: {pattern}") - print("\nState assessment files (--source state):") - for ind, pattern in STATE_FILES.items(): - print(f" {ind}: {pattern}") - return - - if not args.path: - parser.error("--path is required") - - path = args.path.expanduser().resolve() - if not path.exists(): - print(f"Error: Path not found: {path}") - sys.exit(1) - - years_filter: set[str] | None = None - if args.years: - years_filter = {y.strip() for y in args.years.split(",") if y.strip()} - - if not path.is_file() and not path.is_dir(): - print(f"Error: Invalid path: {path}") - sys.exit(1) - - try: - categories = _collect_categories( - path=path, - source=args.source, - indicator=args.indicator, - all_files=args.all_files, - years=years_filter, - ) - except ValueError as exc: - parser.error(str(exc)) - - if not categories and path.is_file(): - # Fallback for explicit file names that do not match known glob patterns. - resolved_indicator = args.indicator or _resolve_indicator_from_name( - path, args.source - ) - if not resolved_indicator: - parser.error( - "--indicator is required when indicator cannot be inferred from filename" - ) - categories = [ - ImportCategory( - source=args.source, - indicator=resolved_indicator, - reporting_year=detect_reporting_year(path), - path=str(path), - ) - ] - - with Session(engine) as session: - for category in categories: - category.existing_rows = count_existing_rows( - session, - indicator=category.indicator, - reporting_year=category.reporting_year, - ) - if category.existing_rows > 0: - category.action = "overwrite" if args.overwrite else "skip_existing" - else: - category.action = "import" - - _print_categories_report("Import Plan", categories) - - total_imported = 0 - to_import: list[ImportCategory] = [] - try: - with Session(engine) as session: - for category in categories: - file_path = Path(category.path) - if not file_path.exists(): - category.status = "missing" - category.message = "file not found" - continue - - if category.existing_rows > 0 and not args.overwrite: - category.status = "skipped" - category.message = "existing data found; rerun with --overwrite" - continue - - if category.existing_rows > 0 and args.overwrite: - category.deleted_rows = delete_category_rows( - session, - indicator=category.indicator, - reporting_year=category.reporting_year, - ) - - category.status = "queued" - category.message = "waiting for worker" - to_import.append(category) - - with ThreadPoolExecutor(max_workers=max(1, args.workers)) as executor: - future_to_category = { - executor.submit( - import_single_file, - Path(category.path), - category.indicator, - args.source, - args.batch_size, - ): category - for category in to_import - } - for future in as_completed(future_to_category): - category = future_to_category[future] - category.status = "running" - try: - imported = future.result() - category.imported_rows = imported - category.status = "imported" - category.message = "completed" - total_imported += imported - except Exception as exc: - category.status = "failed" - category.message = str(exc) - finally: - _print_categories_report("Import Result", categories) - - print(f"\nTotal imported rows: {total_imported:,}") - - -if __name__ == "__main__": - main() diff --git a/backend/app/scripts/cde/import_plan.py b/backend/app/scripts/cde/import_plan.py deleted file mode 100644 index 95ebeec..0000000 --- a/backend/app/scripts/cde/import_plan.py +++ /dev/null @@ -1,84 +0,0 @@ -from __future__ import annotations - -import re -from dataclasses import dataclass -from pathlib import Path - -from sqlalchemy import delete, func -from sqlmodel import Session, select - -from app.model.academic_indicator import AcademicIndicator - -YEAR_PATTERN = re.compile(r"(20\d{2})") - - -@dataclass -class ImportCategory: - source: str - indicator: str - reporting_year: str - path: str - existing_rows: int = 0 - action: str = "import" - status: str = "pending" - imported_rows: int = 0 - deleted_rows: int = 0 - message: str = "" - - -def detect_reporting_year(file_path: Path, fallback_year: str = "2025") -> str: - candidates = [file_path.name, file_path.parent.name] - for candidate in candidates: - match = YEAR_PATTERN.search(candidate) - if match: - return match.group(1) - return fallback_year - - -def count_existing_rows( - session: Session, *, indicator: str, reporting_year: str -) -> int: - result = session.exec( - select(func.count()) - .select_from(AcademicIndicator) - .where(AcademicIndicator.indicator == indicator) - .where(AcademicIndicator.reportingyear == reporting_year) - ).one() - return int(result or 0) - - -def delete_category_rows( - session: Session, *, indicator: str, reporting_year: str -) -> int: - stmt = ( - delete(AcademicIndicator) - .where( - AcademicIndicator.indicator == indicator # type: ignore[arg-type] - ) - .where( - AcademicIndicator.reportingyear == reporting_year # type: ignore[arg-type] - ) - ) - result = session.exec(stmt) - session.commit() - return int(result.rowcount or 0) - - -def render_ascii_table(headers: list[str], rows: list[list[str]]) -> str: - widths = [len(h) for h in headers] - for row in rows: - for index, value in enumerate(row): - widths[index] = max(widths[index], len(value)) - - def _line(char: str) -> str: - return "+" + "+".join(char * (w + 2) for w in widths) + "+" - - def _row(values: list[str]) -> str: - cells = [f" {v.ljust(widths[i])} " for i, v in enumerate(values)] - return "|" + "|".join(cells) + "|" - - output = [_line("-"), _row(headers), _line("=")] - for row in rows: - output.append(_row(row)) - output.append(_line("-")) - return "\n".join(output) diff --git a/backend/app/scripts/cde/run_import_pipeline.py b/backend/app/scripts/cde/run_import_pipeline.py deleted file mode 100644 index 010692f..0000000 --- a/backend/app/scripts/cde/run_import_pipeline.py +++ /dev/null @@ -1,300 +0,0 @@ -import argparse -import subprocess -import sys -from pathlib import Path - -BACKEND_DIR = Path(__file__).resolve().parents[3] - -MODES = { - "full", - "migrate_only", - "initial_data", - "import_ela_data", - "import_indicators", - "both_imports", -} - - -def _normalize_indicators_source(source: str) -> str: - normalized = source.strip().lower().replace("_", "-") - if normalized in {"state", "california-state", "california state"}: - return "state" - return "cde" - - -def _is_year_folder(name: str, year: str, source: str) -> bool: - lowered = name.lower() - if year not in lowered: - return False - if source == "cde": - return "cde" in lowered - return ( - "california-state" in lowered - or "california_state" in lowered - or ("california" in lowered and "state" in lowered) - ) - - -def _discover_indicator_paths( - indicators_path: str | None, resources_path: str, years: list[str], source: str -) -> list[str]: - base = (indicators_path or resources_path).strip() - if not base: - base = resources_path - base_path = Path(base).expanduser() - discovered: list[Path] = [] - - def _get_year_folders(dir_path: Path, src: str) -> list[Path]: - found: list[Path] = [] - if dir_path.is_dir(): - for child in sorted(dir_path.iterdir()): - if not child.is_dir(): - continue - if any(_is_year_folder(child.name, year, src) for year in years): - found.append(child) - return found - - # If the input already points to a year folder, use it directly. - if any(_is_year_folder(base_path.name, year, source) for year in years): - discovered = [base_path] - elif base_path.is_dir(): - # Discover for the primary source - discovered.extend(_get_year_folders(base_path, source)) - - # If source is 'state', we also need 'cde' folders for indicators like CHRONIC - if source == "state": - discovered.extend(_get_year_folders(base_path, "cde")) - - if not discovered: - sources = [source] - if source == "state": - sources.append("cde") - - for s in sources: - prefix = "cde" if s == "cde" else "california-state" - discovered.extend( - [ - Path(resources_path).expanduser() / f"{prefix}-{year}" - for year in years - ] - ) - - # Deduplicate while preserving order. - result: list[str] = [] - seen: set[str] = set() - for path in discovered: - p = str(path) - if p in seen: - continue - seen.add(p) - result.append(p) - return result - - -def _discover_ela_files(resources_path: str, years: list[str]) -> list[str]: - root = Path(resources_path).expanduser() - discovered: list[str] = [] - seen: set[str] = set() - - for year in years: - year_matches: list[Path] = [] - if root.exists(): - year_matches = sorted( - p - for p in root.rglob("*.xlsx") - if p.is_file() - and year in p.name.lower() - and "ela" in p.name.lower() - and "download" in p.name.lower() - and "cde" in str(p.parent).lower() - ) - - if not year_matches: - year_matches = [ - root / f"cde-{year}" / f"eladownload{year}.xlsx", - root / "cde" / f"eladownload{year}.xlsx", - ] - - for match in year_matches: - path = str(match) - if path in seen: - continue - seen.add(path) - discovered.append(path) - - return discovered - - -def run_step(args: list[str], label: str) -> None: - print(f"[pipeline] starting {label}: {' '.join(args)}", flush=True) - subprocess.run([sys.executable, *args], check=True, cwd=BACKEND_DIR) - print(f"[pipeline] finished {label}", flush=True) - - -def main() -> None: - parser = argparse.ArgumentParser( - description="Run backend import pipeline inside one Cloud Run job execution." - ) - parser.add_argument("--mode", default="full", choices=sorted(MODES)) - parser.add_argument("--gcs-uri", default="gs://ca-panel-001-resources/resources") - parser.add_argument("--resources-path", default="/tmp/resources") - parser.add_argument("--ela-file", default=None) - parser.add_argument("--ela-files", default="") - parser.add_argument("--years", default="2024,2025") - parser.add_argument("--indicators-source", default="cde") - parser.add_argument("--indicators-path", default=None) - parser.add_argument("--indicators-paths", default="") - parser.add_argument("--batch-size", type=int, default=5000) - parser.add_argument("--indicator", default="") - parser.add_argument( - "--skip-sync", - action="store_true", - help="Skip GCS sync and use only local resources already present at --resources-path.", - ) - parser.add_argument( - "--overwrite", - action="store_true", - help="Overwrite existing category rows (indicator + reporting year).", - ) - args = parser.parse_args() - - if args.batch_size <= 0: - raise ValueError("--batch-size must be > 0") - - resources_path = args.resources_path - ela_file = args.ela_file or f"{resources_path}/cde/eladownload2025.xlsx" - indicators_source = _normalize_indicators_source(args.indicators_source) - indicators_path = args.indicators_path or resources_path - - years = [y.strip() for y in args.years.split(",") if y.strip()] - explicit_ela_files = [p.strip() for p in args.ela_files.split(",") if p.strip()] - discovered_ela_files = _discover_ela_files(resources_path, years) - ela_files = explicit_ela_files or discovered_ela_files - if not ela_files: - ela_files = [ela_file] - explicit_indicator_paths = [ - p.strip() for p in args.indicators_paths.split(",") if p.strip() - ] - indicator_paths = explicit_indicator_paths or _discover_indicator_paths( - indicators_path=indicators_path, - resources_path=resources_path, - years=years, - source=indicators_source, - ) - - if args.mode in {"full", "initial_data", "migrate_only"}: - run_step(["-m", "alembic", "upgrade", "head"], "migrate") - - if args.mode in {"full", "initial_data"}: - run_step(["app/scripts/initial_data.py"], "initial_data") - - if not args.skip_sync and args.mode in { - "full", - "import_ela_data", - "import_indicators", - "both_imports", - }: - run_step( - [ - "app/scripts/gcp/sync_gcs_resources.py", - "--uri", - args.gcs_uri, - "--dest", - resources_path, - ], - "sync_gcs_resources", - ) - elif args.skip_sync: - print( - "[pipeline] skipping sync_gcs_resources (--skip-sync enabled)", flush=True - ) - - if args.mode == "import_ela_data": - chosen_ela_file = next((p for p in ela_files if Path(p).exists()), ela_file) - cmd = [ - "app/scripts/cde/import_ela_data.py", - chosen_ela_file, - "--batch-size", - str(args.batch_size), - ] - if args.overwrite: - cmd.append("--overwrite") - run_step(cmd, "import_ela_data") - - if args.mode == "import_indicators": - sources = ( - ["state", "cde"] if indicators_source == "state" else [indicators_source] - ) - for src in sources: - # Filter paths based on the source being imported - relevant_paths = [ - p for p in indicator_paths if _is_year_folder(Path(p).name, "", src) - ] - for index, indicator_path in enumerate(relevant_paths, start=1): - cmd = [ - "app/scripts/cde/import_indicators.py", - "--source", - src, - "--path", - indicator_path, - "--batch-size", - str(args.batch_size), - ] - if args.overwrite: - cmd.append("--overwrite") - if args.indicator: - cmd.extend(["--indicator", args.indicator]) - if years: - cmd.extend(["--years", ",".join(years)]) - run_step(cmd, f"import_indicators_{src}_{index}") - - if args.mode in {"both_imports", "full"}: - existing_ela_files = [p for p in ela_files if Path(p).exists()] - if not existing_ela_files: - raise FileNotFoundError( - f"No ELA files found for years={years} under resources_path={resources_path}. " - f"Tried: {ela_files}" - ) - for index, current_ela_file in enumerate(existing_ela_files, start=1): - cmd = [ - "app/scripts/cde/import_ela_data.py", - current_ela_file, - "--batch-size", - str(args.batch_size), - ] - if args.overwrite: - cmd.append("--overwrite") - run_step(cmd, f"import_ela_data_{index}") - - sources = ( - ["state", "cde"] if indicators_source == "state" else [indicators_source] - ) - for src in sources: - # Filter paths based on the source being imported - relevant_paths = [ - p for p in indicator_paths if _is_year_folder(Path(p).name, "", src) - ] - for index, indicator_path in enumerate(relevant_paths, start=1): - cmd = [ - "app/scripts/cde/import_indicators.py", - "--source", - src, - "--path", - indicator_path, - "--batch-size", - str(args.batch_size), - "--all-files", - ] - if args.overwrite: - cmd.append("--overwrite") - if args.indicator: - cmd.extend(["--indicator", args.indicator]) - if years: - cmd.extend(["--years", ",".join(years)]) - run_step(cmd, f"import_indicators_all_files_{src}_{index}") - - print("[pipeline] completed", flush=True) - - -if __name__ == "__main__": - main() diff --git a/backend/app/scripts/cde/state_parser.py b/backend/app/scripts/cde/state_parser.py deleted file mode 100644 index fc3292d..0000000 --- a/backend/app/scripts/cde/state_parser.py +++ /dev/null @@ -1,248 +0,0 @@ -""" -State assessment TXT file parser for California assessment data. - -Parses caret-delimited (^) text files from the California State assessment -data downloads. These contain raw assessment results rather than accountability -indicators. -""" - -import sys -from collections.abc import Generator -from pathlib import Path -from typing import Any - -import pandas as pd # type: ignore[import-untyped] -from sqlmodel import Session - -from .base import BaseIndicatorParser - -sys.path.insert(0, str(Path(__file__).parent.parent.parent)) - -from app.model.academic_indicator import AcademicIndicator - - -class StateParser(BaseIndicatorParser): - """Parser for state assessment caret-delimited TXT files.""" - - CHUNK_SIZE = 50000 # Read large files in chunks - - # Mapping of Type ID to rtype - TYPE_ID_MAP = { - "4": "X", # State aggregate - "5": "C", # County - "6": "D", # District - "7": "S", # School - } - - def __init__(self, indicator: str): - """Initialize parser for a specific indicator. - - Args: - indicator: One of ELA, MATH, SCI - """ - self.INDICATOR = indicator.upper() - - def get_extra_fields(self) -> dict[str, str]: - """Return indicator-specific field mappings for state files.""" - # State files have different column names - return { - # Map state file columns to our model fields - "County Code": "county_code_raw", - "District Code": "district_code_raw", - "School Code": "school_code_raw", - "Type ID": "type_id_raw", - "County Name": "countyname", - "District Name": "districtname", - "School Name": "schoolname", - "Subgroup ID": "studentgroup", - "Test Year": "reportingyear", - "Students Tested": "currdenom", - "Mean Scale Score": "currstatus", - # Additional state-specific fields can be added here - } - - def build_cds_code( - self, county_code: str, district_code: str, school_code: str - ) -> str: - """Build 14-character CDS code from component codes. - - Args: - county_code: 2-digit county code - district_code: 5-digit district code - school_code: 7-digit school code - - Returns: - 14-character CDS code - """ - county = str(county_code or "").zfill(2) - district = str(district_code or "").zfill(5) - school = str(school_code or "").zfill(7) - return f"{county}{district}{school}" - - def parse_row_state( - self, row: pd.Series, columns: list[str] - ) -> dict[str, Any] | None: - """Parse a row from state assessment file. - - Args: - row: pandas Series representing a row - columns: list of column names - - Returns: - dict suitable for AcademicIndicator model or None if invalid - """ - try: - # Build CDS code - county_code = row.get("county code", "") - district_code = row.get("district code", "") - school_code = row.get("school code", "") - - # Handle statewide aggregate (Type ID = 4) - type_id = str(row.get("type id", "7")) - if type_id == "4": - cds = "00000000000000" - rtype = "X" - else: - cds = self.build_cds_code(county_code, district_code, school_code) - rtype = self.TYPE_ID_MAP.get(type_id, "S") - - # Map studentgroup - subgroup_id = str(row.get("subgroup id", "1")) - studentgroup = self.map_subgroup(subgroup_id) - - record_data = { - "cds": cds, - "rtype": rtype, - "countyname": self.clean_value(row.get("county name")), - "districtname": self.clean_value(row.get("district name")), - "schoolname": self.clean_value(row.get("school name")), - "studentgroup": studentgroup, - "indicator": self.INDICATOR, - "reportingyear": self.clean_value(row.get("test year"), "str") - or "2025", - "currdenom": self.clean_value(row.get("students tested"), "int"), - "currstatus": self.clean_value(row.get("mean scale score"), "float"), - } - - # Validate required fields - if not cds or not studentgroup: - return None - - return record_data - - except Exception as e: - print(f"Error parsing state row: {e}") - return None - - def map_subgroup(self, subgroup_id: str) -> str: - """Map state file subgroup ID to dashboard studentgroup code. - - Args: - subgroup_id: Numeric subgroup ID from state file - - Returns: - Dashboard studentgroup code (ALL, AA, AI, etc.) - """ - # Common subgroup ID mappings (may need adjustment based on actual data) - subgroup_map = { - "1": "ALL", - "74": "AA", # African American - "75": "AI", # American Indian - "76": "AS", # Asian - "77": "FI", # Filipino - "78": "HI", # Hispanic - "79": "PI", # Pacific Islander - "80": "WH", # White - "31": "MR", # Two or More Races - "111": "EL", # English Learners - "128": "SED", # Socioeconomically Disadvantaged - "99": "SWD", # Students with Disabilities - "121": "FOS", # Foster - "160": "HOM", # Homeless - "142": "MIG", # Migrant - } - return subgroup_map.get(subgroup_id, f"SG{subgroup_id}") - - def parse_txt( - self, file_path: str | Path - ) -> Generator[AcademicIndicator, None, None]: - """Parse a caret-delimited TXT file and yield AcademicIndicator records. - - Args: - file_path: Path to the TXT file - - Yields: - AcademicIndicator instances - """ - file_path = Path(file_path) - print(f"Reading TXT file: {file_path}") - - # Read in chunks for large files - # Use latin-1 encoding to handle Spanish characters (ñ, accents, etc.) - chunk_iter = pd.read_csv( - file_path, - sep="^", - encoding="latin-1", - dtype=str, - chunksize=self.CHUNK_SIZE, - on_bad_lines="skip", - ) - - total_rows = 0 - for chunk in chunk_iter: - # Normalize column names to lowercase - chunk.columns = chunk.columns.str.lower() - columns = list(chunk.columns) - - for idx, row in chunk.iterrows(): - try: - record_data = self.parse_row_state(row, columns) - if record_data is None: - continue - - yield AcademicIndicator(**record_data) - total_rows += 1 - - except Exception as e: - print(f"Error processing row {idx}: {e}") - continue - - print(f"Processed chunk, total rows so far: {total_rows}") - - print(f"Total rows parsed: {total_rows}") - - def import_file( - self, session: Session, file_path: str | Path, batch_size: int | None = None - ) -> int: - """Import a TXT file to the database. - - Args: - session: SQLModel Session - file_path: Path to the TXT file - batch_size: Override default batch size - - Returns: - Number of records imported - """ - records = self.parse_txt(file_path) - return self.import_to_session(session, records, batch_size) - - -# State file patterns -STATE_FILES = { - "ELA": "sb_ca*_all_csv_ela_*.txt", - "MATH": "sb_ca*_all_csv_math_*.txt", - "SCI": "cast_ca*_all_csv_*.txt", -} - - -def get_parser(indicator: str) -> StateParser: - """Get the appropriate parser for an indicator. - - Args: - indicator: Indicator code (ELA, MATH, SCI) - - Returns: - StateParser instance configured for the indicator - """ - return StateParser(indicator) diff --git a/backend/app/scripts/check_table.py b/backend/app/scripts/check_table.py deleted file mode 100644 index b948773..0000000 --- a/backend/app/scripts/check_table.py +++ /dev/null @@ -1,50 +0,0 @@ -from sqlalchemy import Engine -from sqlmodel import text - -from app.core.database import engine -from app.scripts.gcp.gcp_utils import load_repo_env_if_present - -load_repo_env_if_present(__file__, scope="check_table") - - -def init(db_engine: Engine) -> None: - """ - Check if the 'censusdata' table exists in the database and lists all tables. - - Syntax: - python check_table.py - - How to use: - 1. Ensure your database URI is set in app.core.config.settings.SQLALCHEMY_DATABASE_URI. - 2. Run this script from the command line: - python check_table.py - 3. The script will print whether the 'censusdata' table exists and list all tables in the database. - """ - with db_engine.connect() as conn: - result = conn.execute( - text( - "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'censusdata';" - ) - ).fetchall() - print(f"Does 'censusdata' table exist: {len(result) > 0}") - print(f"Tables found: {result}") - all_tables = conn.execute( - text( - "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';" - ) - ).fetchall() - print("All tables in the database:") - if not all_tables: - print(" - No tables found.") - else: - print(" - Tables found:") - for (table_name,) in all_tables: - print(f" - {table_name}") - - -def main() -> None: - init(engine) - - -if __name__ == "__main__": - main() diff --git a/backend/app/scripts/gcp/create_secrets.py b/backend/app/scripts/gcp/create_secrets.py deleted file mode 100644 index 9459543..0000000 --- a/backend/app/scripts/gcp/create_secrets.py +++ /dev/null @@ -1,110 +0,0 @@ -from __future__ import annotations - -import sys -from pathlib import Path - -from app.scripts.gcp.gcp_utils import ( - ScriptError, - env_required, - load_env_file, - log, - resolve_env_file, - run_command, -) - -SCRIPT_DIR = Path(__file__).resolve().parent -BACKEND_DIR = SCRIPT_DIR.parents[1] -if str(BACKEND_DIR) not in sys.path: - sys.path.insert(0, str(BACKEND_DIR)) - - -def main() -> int: - env_path = resolve_env_file(__file__, sys.argv[1] if len(sys.argv) > 1 else None) - print(f"Loading environment from {env_path}") - load_env_file(env_path) - - project_id = env_required("GCP_PROJECT_ID") - run_service_account = env_required("RUN_SERVICE_ACCOUNT") - cloud_sql_password = env_required("CLOUD_SQL_PASSWORD") - secret_key = env_required("SECRET_KEY") - - run_sa_email = f"{run_service_account}@{project_id}.iam.gserviceaccount.com" - - secrets = { - "capanel-postgres-password": cloud_sql_password, - "capanel-secret-key": secret_key, - } - - log("create-secrets", "Enabling Secret Manager API") - run_command( - [ - "gcloud", - "services", - "enable", - "secretmanager.googleapis.com", - f"--project={project_id}", - ] - ) - - for secret_name, secret_value in secrets.items(): - describe = run_command( - ["gcloud", "secrets", "describe", secret_name, f"--project={project_id}"], - capture_output=True, - check=False, - ) - if describe.returncode != 0: - log("create-secrets", f"Creating secret {secret_name}") - run_command( - [ - "gcloud", - "secrets", - "create", - secret_name, - f"--project={project_id}", - "--replication-policy=automatic", - ] - ) - else: - log("create-secrets", f"Secret {secret_name} already exists") - - log("create-secrets", f"Adding latest version for {secret_name}") - run_command( - [ - "gcloud", - "secrets", - "versions", - "add", - secret_name, - f"--project={project_id}", - "--data-file=-", - ], - input_text=secret_value, - ) - - log("create-secrets", f"Granting accessor role on {secret_name}") - run_command( - [ - "gcloud", - "secrets", - "add-iam-policy-binding", - secret_name, - f"--project={project_id}", - f"--member=serviceAccount:{run_sa_email}", - "--role=roles/secretmanager.secretAccessor", - "--quiet", - ] - ) - - print("\nAll secrets created/updated and IAM bindings applied.") - print( - "Verify with:\n" - f" gcloud secrets list --project={project_id} --filter='name:capanel-'" - ) - return 0 - - -if __name__ == "__main__": - try: - raise SystemExit(main()) - except ScriptError as exc: - raise SystemExit(str(exc)) from exc diff --git a/backend/app/scripts/gcp/deploy_cloud_run.py b/backend/app/scripts/gcp/deploy_cloud_run.py deleted file mode 100644 index 470dd71..0000000 --- a/backend/app/scripts/gcp/deploy_cloud_run.py +++ /dev/null @@ -1,704 +0,0 @@ -from __future__ import annotations - -import argparse -import os -import sys -import tempfile -from dataclasses import dataclass -from pathlib import Path - -from app.scripts.gcp.gcp_utils import ( - GcpDefaults, - ScriptError, - compute_paths, - env_bool, - env_or, - env_required, - load_env_file, - load_gcp_defaults, - resolve_env_file, - run_command, - yaml_escape, -) - - -@dataclass(frozen=True) -class DeployConfig: - project_id: str - region: str - ar_repository: str - backend_service: str - frontend_service: str - run_service_account: str - vpc_network: str - vpc_subnet: str - cloud_sql_instance: str - cloud_sql_db: str - cloud_sql_user: str - full_service: str - tag: str - api_v1_str: str - project_name: str - cloud_sql_connection_name: str - run_service_account_email: str - run_data_imports: str - run_startup_data_imports: str - import_gcs_uri: str - import_resources_local_path: str - sync_local_imports_to_bucket: bool - backend_init_job: str - init_trigger_function_name: str - backend_init_job_task_timeout: str - backend_init_job_parallelism: str - backend_init_job_max_retries: str - backend_init_job_cpu: str - backend_init_job_memory: str - init_trigger_function_timeout: str - job_step_timeout_seconds: str - job_poll_interval_seconds: str - init_trigger_function_source_dir: Path - environment: str - frontend_host: str - backend_cors_origins: str - backend_image: str - frontend_image: str - - -def cmd_exists(cmd: list[str]) -> bool: - return run_command(cmd, capture_output=True, check=False).returncode == 0 - - -def current_git_tag(repo_dir: Path) -> str: - result = run_command( - ["git", "rev-parse", "--short", "HEAD"], cwd=repo_dir, capture_output=True - ) - return result.stdout.strip() - - -def load_and_apply_env(defaults: GcpDefaults) -> None: - os.environ["RUN_SERVICE_ACCOUNT"] = env_or( - "RUN_SERVICE_ACCOUNT", defaults.run_service_account - ) - os.environ["VPC_NETWORK"] = env_or("VPC_NETWORK", defaults.vpc_network) - os.environ["VPC_SUBNET"] = env_or("VPC_SUBNET", defaults.vpc_subnet) - os.environ["CLOUD_SQL_INSTANCE"] = env_or( - "CLOUD_SQL_INSTANCE", defaults.cloud_sql_instance - ) - os.environ["CLOUD_SQL_DB"] = env_or("CLOUD_SQL_DB", defaults.cloud_sql_db) - os.environ["CLOUD_SQL_USER"] = env_or("CLOUD_SQL_USER", defaults.cloud_sql_user) - os.environ["FULL_SERVICE"] = env_or("FULL_SERVICE", defaults.full_service) - - -def build_config(defaults: GcpDefaults) -> DeployConfig: - paths = compute_paths(__file__) - project_id = env_required("GCP_PROJECT_ID") - region = env_required("GCP_REGION", "for example us-central1") - ar_repository = env_required("GCP_AR_REPOSITORY") - backend_service = env_required("BACKEND_SERVICE") - frontend_service = env_required("FRONTEND_SERVICE") - run_service_account = env_required("RUN_SERVICE_ACCOUNT") - vpc_network = env_required("VPC_NETWORK", "for example default") - vpc_subnet = env_required("VPC_SUBNET", "for example default") - cloud_sql_instance = env_required("CLOUD_SQL_INSTANCE") - cloud_sql_db = env_required("CLOUD_SQL_DB") - cloud_sql_user = env_required("CLOUD_SQL_USER") - full_service = env_required("FULL_SERVICE") - - tag = env_or("TAG", current_git_tag(paths.repo_dir)) - api_v1_str = env_or("API_V1_STR", "/api/v1") - project_name = env_or("PROJECT_NAME", defaults.project_name) - cloud_sql_connection_name = f"{project_id}:{region}:{cloud_sql_instance}" - run_sa_email = f"{run_service_account}@{project_id}.iam.gserviceaccount.com" - run_data_imports = env_or("RUN_DATA_IMPORTS", "false") - run_startup_data_imports = env_or("RUN_STARTUP_DATA_IMPORTS", "false") - import_gcs_uri = env_or("IMPORT_GCS_URI", defaults.import_gcs_uri) - import_resources_local_path = env_or( - "IMPORT_RESOURCES_LOCAL_PATH", defaults.import_resources_local_path - ) - sync_local_imports_to_bucket = env_bool("SYNC_LOCAL_IMPORTS_TO_BUCKET", False) - backend_init_job = env_or("BACKEND_INIT_JOB", f"{full_service}-init") - init_trigger_function_name = env_or( - "INIT_TRIGGER_FUNCTION_NAME", f"{full_service}-init-trigger" - ) - backend_init_job_task_timeout = env_or("BACKEND_INIT_JOB_TASK_TIMEOUT", "7200s") - backend_init_job_parallelism = env_or("BACKEND_INIT_JOB_PARALLELISM", "1") - backend_init_job_max_retries = env_or("BACKEND_INIT_JOB_MAX_RETRIES", "0") - backend_init_job_cpu = env_or("BACKEND_INIT_JOB_CPU", "4") - backend_init_job_memory = env_or("BACKEND_INIT_JOB_MEMORY", "8Gi") - init_trigger_function_timeout = env_or("INIT_TRIGGER_FUNCTION_TIMEOUT", "3600s") - job_step_timeout_seconds = env_or("JOB_STEP_TIMEOUT_SECONDS", "7200") - job_poll_interval_seconds = env_or("JOB_POLL_INTERVAL_SECONDS", "10") - source_dir = paths.backend_dir / "app/scripts/gcp/functions/manual_backend_init" - environment = "production" - frontend_host = env_or( - "FRONTEND_HOST_PRODUCTION", defaults.frontend_host_production - ) - backend_cors_origins = env_or( - "BACKEND_CORS_ORIGINS_PRODUCTION", env_or("BACKEND_CORS_ORIGINS", frontend_host) - ) - - backend_image = ( - f"{region}-docker.pkg.dev/{project_id}/{ar_repository}/{backend_service}:{tag}" - ) - frontend_image = ( - f"{region}-docker.pkg.dev/{project_id}/{ar_repository}/{frontend_service}:{tag}" - ) - - return DeployConfig( - project_id=project_id, - region=region, - ar_repository=ar_repository, - backend_service=backend_service, - frontend_service=frontend_service, - run_service_account=run_service_account, - vpc_network=vpc_network, - vpc_subnet=vpc_subnet, - cloud_sql_instance=cloud_sql_instance, - cloud_sql_db=cloud_sql_db, - cloud_sql_user=cloud_sql_user, - full_service=full_service, - tag=tag, - api_v1_str=api_v1_str, - project_name=project_name, - cloud_sql_connection_name=cloud_sql_connection_name, - run_service_account_email=run_sa_email, - run_data_imports=run_data_imports, - run_startup_data_imports=run_startup_data_imports, - import_gcs_uri=import_gcs_uri, - import_resources_local_path=import_resources_local_path, - sync_local_imports_to_bucket=sync_local_imports_to_bucket, - backend_init_job=backend_init_job, - init_trigger_function_name=init_trigger_function_name, - backend_init_job_task_timeout=backend_init_job_task_timeout, - backend_init_job_parallelism=backend_init_job_parallelism, - backend_init_job_max_retries=backend_init_job_max_retries, - backend_init_job_cpu=backend_init_job_cpu, - backend_init_job_memory=backend_init_job_memory, - init_trigger_function_timeout=init_trigger_function_timeout, - job_step_timeout_seconds=job_step_timeout_seconds, - job_poll_interval_seconds=job_poll_interval_seconds, - init_trigger_function_source_dir=source_dir, - environment=environment, - frontend_host=frontend_host, - backend_cors_origins=backend_cors_origins, - backend_image=backend_image, - frontend_image=frontend_image, - ) - - -def ensure_bucket_exists(import_gcs_uri: str, region: str) -> None: - bucket = import_gcs_uri.removeprefix("gs://").split("/", 1)[0] - if not cmd_exists(["gcloud", "storage", "buckets", "describe", f"gs://{bucket}"]): - print(f"Creating bucket gs://{bucket} in {region}") - run_command( - [ - "gcloud", - "storage", - "buckets", - "create", - f"gs://{bucket}", - f"--location={region}", - "--uniform-bucket-level-access", - ] - ) - - -def maybe_sync_local_resources(cfg: DeployConfig) -> None: - if not cfg.sync_local_imports_to_bucket: - print("SYNC_LOCAL_IMPORTS_TO_BUCKET=false; skipping local->bucket sync.") - return - - local_path = Path(cfg.import_resources_local_path).expanduser() - if not local_path.is_dir(): - msg = f"Local resources path not found: {local_path}" - raise ScriptError(msg) - - print( - f"Merging local resources {local_path} -> {cfg.import_gcs_uri} " - "(new files only; no overwrite/delete)" - ) - run_command( - [ - "gcloud", - "storage", - "cp", - "--recursive", - "--no-clobber", - f"{local_path}/.", - cfg.import_gcs_uri, - ] - ) - - -def render_build_config(dockerfile: str, image_subst: str) -> str: - return ( - "steps:\n" - " - name: gcr.io/cloud-builders/docker\n" - " env:\n" - " - DOCKER_BUILDKIT=1\n" - " args:\n" - " - build\n" - f" - -f\n - {dockerfile}\n" - " - -t\n" - f" - {image_subst}\n" - " - .\n" - "images:\n" - f" - {image_subst}\n" - ) - - -def build_backend_image(cfg: DeployConfig) -> None: - print(f"Building backend image {cfg.backend_image}") - content = render_build_config("backend/Dockerfile", "${_IMAGE}") - with tempfile.NamedTemporaryFile("w", delete=False) as tmp: - tmp.write(content) - config_path = Path(tmp.name) - - try: - run_command( - [ - "gcloud", - "builds", - "submit", - "--substitutions", - f"_IMAGE={cfg.backend_image}", - "--config", - str(config_path), - ".", - ] - ) - finally: - config_path.unlink(missing_ok=True) - - -def deploy_init_job(cfg: DeployConfig) -> None: - print(f"Deploying backend init job {cfg.backend_init_job}") - with tempfile.NamedTemporaryFile("w", delete=False) as tmp: - env_file = Path(tmp.name) - tmp.write(f"ENVIRONMENT: '{yaml_escape(cfg.environment)}'\n") - tmp.write(f"PROJECT_NAME: '{yaml_escape(cfg.project_name)}'\n") - tmp.write(f"API_V1_STR: '{yaml_escape(cfg.api_v1_str)}'\n") - tmp.write(f"BACKEND_CORS_ORIGINS: '{yaml_escape(cfg.backend_cors_origins)}'\n") - tmp.write(f"FRONTEND_HOST: '{yaml_escape(cfg.frontend_host)}'\n") - tmp.write( - "CLOUD_SQL_INSTANCE_CONNECTION_NAME: " - f"'{yaml_escape(cfg.cloud_sql_connection_name)}'\n" - ) - tmp.write(f"POSTGRES_DB: '{yaml_escape(cfg.cloud_sql_db)}'\n") - tmp.write(f"POSTGRES_USER: '{yaml_escape(cfg.cloud_sql_user)}'\n") - tmp.write("POSTGRES_SERVER: 'localhost'\n") - tmp.write("RUN_DATA_IMPORTS: 'false'\n") - tmp.write("RUN_STARTUP_DATA_IMPORTS: 'false'\n") - tmp.write(f"IMPORT_GCS_URI: '{yaml_escape(cfg.import_gcs_uri)}'\n") - tmp.write( - "IMPORT_RESOURCES_LOCAL_PATH: " - f"'{yaml_escape(cfg.import_resources_local_path)}'\n" - ) - - try: - run_command( - [ - "gcloud", - "run", - "jobs", - "deploy", - cfg.backend_init_job, - "--image", - cfg.backend_image, - "--region", - cfg.region, - "--service-account", - cfg.run_service_account_email, - "--task-timeout", - cfg.backend_init_job_task_timeout, - "--parallelism", - cfg.backend_init_job_parallelism, - "--max-retries", - cfg.backend_init_job_max_retries, - "--cpu", - cfg.backend_init_job_cpu, - "--memory", - cfg.backend_init_job_memory, - "--network", - cfg.vpc_network, - "--subnet", - cfg.vpc_subnet, - "--vpc-egress", - "private-ranges-only", - "--set-cloudsql-instances", - cfg.cloud_sql_connection_name, - "--command", - "python", - "--args", - "app/scripts/cde/run_import_pipeline.py", - "--env-vars-file", - str(env_file), - "--set-secrets", - "POSTGRES_PASSWORD=capanel-postgres-password:latest," - "SECRET_KEY=capanel-secret-key:latest", - ] - ) - finally: - env_file.unlink(missing_ok=True) - - run_command( - [ - "gcloud", - "run", - "jobs", - "add-iam-policy-binding", - cfg.backend_init_job, - "--region", - cfg.region, - "--member", - f"serviceAccount:{cfg.run_service_account_email}", - "--role", - "roles/run.invoker", - ] - ) - - -def deploy_trigger_function(cfg: DeployConfig) -> str: - if not cfg.init_trigger_function_source_dir.is_dir(): - msg = f"Function source directory not found: {cfg.init_trigger_function_source_dir}" - raise ScriptError(msg) - - run_command( - [ - "gcloud", - "functions", - "deploy", - cfg.init_trigger_function_name, - "--gen2", - "--runtime", - "python314", - "--region", - cfg.region, - "--timeout", - cfg.init_trigger_function_timeout, - "--source", - str(cfg.init_trigger_function_source_dir), - "--entry-point", - "trigger_backend_init", - "--trigger-http", - "--no-allow-unauthenticated", - "--service-account", - cfg.run_service_account_email, - "--set-env-vars", - "GCP_PROJECT_ID=" - f"{cfg.project_id}," - f"GCP_REGION={cfg.region}," - f"BACKEND_INIT_JOB={cfg.backend_init_job}," - f"JOB_STEP_TIMEOUT_SECONDS={cfg.job_step_timeout_seconds}," - f"JOB_POLL_INTERVAL_SECONDS={cfg.job_poll_interval_seconds}", - ] - ) - - return run_command( - [ - "gcloud", - "functions", - "describe", - cfg.init_trigger_function_name, - "--region", - cfg.region, - "--gen2", - "--format=value(serviceConfig.uri)", - ], - capture_output=True, - ).stdout.strip() - - -def parse_args(argv: list[str]) -> argparse.Namespace: - parser = argparse.ArgumentParser( - description=( - "Build and deploy CAPanel Cloud Run resources. " - "Default deploys all resources." - ) - ) - parser.add_argument( - "env_file", - nargs="?", - help="Optional path to environment file (defaults to script resolution).", - ) - mode_group = parser.add_mutually_exclusive_group() - mode_group.add_argument( - "--init-trigger-only", - action="store_true", - help=( - "Deploy only backend init resources " - "(backend image + init job + init trigger function)." - ), - ) - mode_group.add_argument( - "--full-only", - action="store_true", - help=( - "Deploy only full service resources " - "(backend image + frontend image + combined Cloud Run service)." - ), - ) - return parser.parse_args(argv) - - -def build_frontend_image(cfg: DeployConfig) -> None: - print( - f"Building frontend image {cfg.frontend_image} with VITE_API_URL={cfg.api_v1_str}" - ) - content = ( - "steps:\n" - " - name: gcr.io/cloud-builders/docker\n" - " env:\n" - " - DOCKER_BUILDKIT=1\n" - " args:\n" - " - build\n" - " - -f\n" - " - frontend/Dockerfile\n" - " - -t\n" - " - ${_IMAGE}\n" - " - --build-arg\n" - " - VITE_API_URL=${_VITE_API_URL}\n" - " - .\n" - "images:\n" - " - ${_IMAGE}\n" - ) - with tempfile.NamedTemporaryFile("w", delete=False) as tmp: - tmp.write(content) - config_path = Path(tmp.name) - - try: - run_command( - [ - "gcloud", - "builds", - "submit", - "--substitutions", - f"_IMAGE={cfg.frontend_image},_VITE_API_URL={cfg.api_v1_str}", - "--config", - str(config_path), - ".", - ] - ) - finally: - config_path.unlink(missing_ok=True) - - -def deploy_combined_service(cfg: DeployConfig) -> tuple[str, str]: - with tempfile.NamedTemporaryFile("w", delete=False) as tmp: - rendered_path = Path(tmp.name) - render_script = Path(__file__).resolve().parent / "render_cloud_run_service.py" - - try: - env = os.environ.copy() - env.update( - { - "FULL_SERVICE": cfg.full_service, - "GCP_REGION": cfg.region, - "RUN_SERVICE_ACCOUNT_EMAIL": cfg.run_service_account_email, - "FRONTEND_IMAGE": cfg.frontend_image, - "BACKEND_IMAGE": cfg.backend_image, - "CLOUD_SQL_CONNECTION_NAME": cfg.cloud_sql_connection_name, - "ENVIRONMENT": cfg.environment, - "PROJECT_NAME": cfg.project_name, - "API_V1_STR": cfg.api_v1_str, - "BACKEND_CORS_ORIGINS": cfg.backend_cors_origins, - "FRONTEND_HOST": cfg.frontend_host, - "CLOUD_SQL_DB": cfg.cloud_sql_db, - "CLOUD_SQL_USER": cfg.cloud_sql_user, - "RUN_DATA_IMPORTS": cfg.run_data_imports, - "RUN_STARTUP_DATA_IMPORTS": cfg.run_startup_data_imports, - "IMPORT_GCS_URI": cfg.import_gcs_uri, - "IMPORT_RESOURCES_LOCAL_PATH": cfg.import_resources_local_path, - "VPC_NETWORK": cfg.vpc_network, - "VPC_SUBNET": cfg.vpc_subnet, - } - ) - - rendered = run_command( - ["python", str(render_script)], - env=env, - capture_output=True, - check=False, - ) - if rendered.returncode != 0: - details = (rendered.stderr or rendered.stdout or "").strip() - msg = ( - "Failed to render Cloud Run service YAML via " - f"{render_script} (exit {rendered.returncode})." - ) - if details: - msg = f"{msg}\n{details}" - raise ScriptError(msg) - rendered_path.write_text(rendered.stdout) - - run_command( - [ - "gcloud", - "run", - "services", - "replace", - str(rendered_path), - "--region", - cfg.region, - ] - ) - run_command( - [ - "gcloud", - "run", - "services", - "add-iam-policy-binding", - cfg.full_service, - "--region", - cfg.region, - "--member", - "allUsers", - "--role", - "roles/run.invoker", - ] - ) - - service_url = run_command( - [ - "gcloud", - "run", - "services", - "describe", - cfg.full_service, - "--region", - cfg.region, - "--format=value(status.url)", - ], - capture_output=True, - ).stdout.strip() - - function_url = run_command( - [ - "gcloud", - "functions", - "describe", - cfg.init_trigger_function_name, - "--region", - cfg.region, - "--gen2", - "--format=value(serviceConfig.uri)", - ], - capture_output=True, - ).stdout.strip() - return service_url, function_url - finally: - rendered_path.unlink(missing_ok=True) - - -def main() -> int: - args = parse_args(sys.argv[1:]) - env_path = resolve_env_file(__file__, args.env_file) - print(f"Loading environment from {env_path}") - load_env_file(env_path) - defaults = load_gcp_defaults(__file__) - load_and_apply_env(defaults) - - original_environment = os.environ.get("ENVIRONMENT", "") - cfg = build_config(defaults) - - print(f"Using project={cfg.project_id}, region={cfg.region}, tag={cfg.tag}") - print(f"Using FRONTEND_HOST={cfg.frontend_host}") - if original_environment != "production": - print( - f"Forcing ENVIRONMENT=production for Cloud Run deploy (was: {original_environment})" - ) - - run_command(["gcloud", "config", "set", "project", cfg.project_id]) - run_command( - [ - "gcloud", - "services", - "enable", - "run.googleapis.com", - "cloudfunctions.googleapis.com", - "eventarc.googleapis.com", - "artifactregistry.googleapis.com", - "cloudbuild.googleapis.com", - "sqladmin.googleapis.com", - "storage.googleapis.com", - ] - ) - - ensure_bucket_exists(cfg.import_gcs_uri, cfg.region) - maybe_sync_local_resources(cfg) - - if not cmd_exists( - [ - "gcloud", - "artifacts", - "repositories", - "describe", - cfg.ar_repository, - f"--location={cfg.region}", - ] - ): - run_command( - [ - "gcloud", - "artifacts", - "repositories", - "create", - cfg.ar_repository, - f"--location={cfg.region}", - "--repository-format=docker", - "--description=Container images for CAPanel services", - ] - ) - - deploy_init_only = args.init_trigger_only - deploy_full_only = args.full_only - - if deploy_init_only: - print("Deploy mode: init-trigger-only") - build_backend_image(cfg) - deploy_init_job(cfg) - function_url = deploy_trigger_function(cfg) - print(f"Manual init trigger URL: {function_url}") - print("Invoke with:") - print( - 'curl -X POST -H "Authorization: Bearer ' - '$(gcloud auth print-identity-token)" ' - f'"{function_url}"' - ) - print("Done.") - return 0 - - if deploy_full_only: - print("Deploy mode: full-only") - build_backend_image(cfg) - build_frontend_image(cfg) - full_service_url, function_url = deploy_combined_service(cfg) - print(f"Full service URL: {full_service_url}") - print(f"Manual init trigger URL (existing): {function_url}") - print("Done.") - return 0 - - print("Deploy mode: all") - build_backend_image(cfg) - deploy_init_job(cfg) - deploy_trigger_function(cfg) - build_frontend_image(cfg) - full_service_url, function_url = deploy_combined_service(cfg) - - print(f"Full service URL: {full_service_url}") - print(f"Manual init trigger URL: {function_url}") - print("Invoke with:") - print( - 'curl -X POST -H "Authorization: Bearer ' - '$(gcloud auth print-identity-token)" ' - f'"{function_url}"' - ) - print("Done.") - return 0 - - -if __name__ == "__main__": - try: - raise SystemExit(main()) - except ScriptError as exc: - raise SystemExit(str(exc)) from exc diff --git a/backend/app/scripts/gcp/functions/manual_backend_init/__init__.py b/backend/app/scripts/gcp/functions/manual_backend_init/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/app/scripts/gcp/functions/manual_backend_init/main.py b/backend/app/scripts/gcp/functions/manual_backend_init/main.py deleted file mode 100644 index d71adc0..0000000 --- a/backend/app/scripts/gcp/functions/manual_backend_init/main.py +++ /dev/null @@ -1,489 +0,0 @@ -import json -import os -import time -from typing import Any, TypedDict, cast - -import google.auth -from google.auth.transport.requests import ( - AuthorizedSession, -) - -MODES = { - "full", - "migrate_only", - "initial_data", - "import_ela_data", - "import_indicators", - "both_imports", -} - - -class Step(TypedDict): - name: str - args: list[str] - - -def _normalize_indicators_source(source: str) -> str: - normalized = source.strip().lower().replace("_", "-") - if normalized in {"state", "california-state", "california state"}: - return "state" - return "cde" - - -def _is_year_folder(name: str, year: str, source: str) -> bool: - lowered = name.lower() - if year not in lowered: - return False - if source == "cde": - return "cde" in lowered - return ( - "california-state" in lowered - or "california_state" in lowered - or ("california" in lowered and "state" in lowered) - ) - - -def _discover_indicator_paths( - resources_path: str, years: list[str], source: str, indicators_path: str -) -> list[str]: - base_path = (indicators_path or resources_path).strip() - base_path = base_path.rstrip("/") or base_path - discovered: list[str] = [] - - def _get_year_folders(base: str, src: str) -> list[str]: - found: list[str] = [] - if os.path.isdir(base): - try: - for entry in sorted(os.listdir(base)): - child = os.path.join(base, entry) - if not os.path.isdir(child): - continue - if any(_is_year_folder(entry, year, src) for year in years): - found.append(child) - except OSError: - pass - return found - - # If a specific year folder is already provided, keep it. - base_name = os.path.basename(base_path) - if any(_is_year_folder(base_name, year, source) for year in years): - discovered = [base_path] - elif os.path.isdir(base_path): - # Discover for primary source - discovered.extend(_get_year_folders(base_path, source)) - - # If source is 'state', also discover 'cde' folders - if source == "state": - discovered.extend(_get_year_folders(base_path, "cde")) - - # If nothing was found, fallback to expected year-folder names under resources_path. - if not discovered: - root = resources_path.rstrip("/") or resources_path - sources = [source] - if source == "state": - sources.append("cde") - - for s in sources: - prefix = "cde" if s == "cde" else "california-state" - for year in years: - discovered.append(f"{root}/{prefix}-{year}") - - # Deduplicate while preserving order. - deduped: list[str] = [] - seen: set[str] = set() - for path in discovered: - if path in seen: - continue - seen.add(path) - deduped.append(path) - return deduped - - -def _env_int(name: str, default: int) -> int: - raw = os.environ.get(name) - if raw is None or raw == "": - return default - try: - return int(raw) - except ValueError: - return default - - -def _parse_bool(name: str, raw: Any, *, default: bool) -> bool: - if raw is None: - return default - if isinstance(raw, bool): - return raw - if isinstance(raw, str): - normalized = raw.strip().lower() - if normalized in {"1", "true", "t", "yes", "y", "on"}: - return True - if normalized in {"0", "false", "f", "no", "n", "off"}: - return False - if isinstance(raw, (int, float)): - return bool(raw) - raise ValueError(f"{name} must be a boolean.") - - -def _parse_positive_int(name: str, raw: Any, *, default: int) -> int: - value = default if raw is None else int(raw) - if value <= 0: - raise ValueError(f"{name} must be > 0.") - return value - - -DEFAULT_STEP_TIMEOUT_SECONDS = _env_int("JOB_STEP_TIMEOUT_SECONDS", 7200) -DEFAULT_POLL_INTERVAL_SECONDS = max(1, _env_int("JOB_POLL_INTERVAL_SECONDS", 10)) - - -def _response(status: int, payload: dict[str, Any]) -> tuple[str, int, dict[str, str]]: - return json.dumps(payload), status, {"Content-Type": "application/json"} - - -def _poll_operation( - session: AuthorizedSession, - operation_name: str, - *, - timeout_seconds: int, - poll_interval_seconds: int, -) -> dict[str, Any]: - operation_url = f"https://run.googleapis.com/v2/{operation_name}" - deadline = time.time() + timeout_seconds - - while True: - response = session.get(operation_url) - response.raise_for_status() - payload = cast(dict[str, Any], response.json()) - if payload.get("done"): - return payload - if time.time() >= deadline: - raise TimeoutError(f"Timed out waiting for operation {operation_name}") - time.sleep(poll_interval_seconds) - - -def _poll_execution( - session: AuthorizedSession, - execution_name: str, - *, - timeout_seconds: int, - poll_interval_seconds: int, -) -> dict[str, Any]: - execution_url = f"https://run.googleapis.com/v2/{execution_name}" - deadline = time.time() + timeout_seconds - - while True: - response = session.get(execution_url) - response.raise_for_status() - execution = cast(dict[str, Any], response.json()) - conditions = execution.get("conditions", []) - completed = next((c for c in conditions if c.get("type") == "Completed"), None) - if completed and completed.get("status") == "True": - return execution - if completed and completed.get("status") == "False": - msg = completed.get("message") or "Cloud Run job execution failed" - raise RuntimeError(msg) - if time.time() >= deadline: - raise TimeoutError(f"Timed out waiting for execution {execution_name}") - time.sleep(poll_interval_seconds) - - -def _start_job( - session: AuthorizedSession, - *, - project_id: str, - region: str, - job_name: str, - args: list[str], -) -> str: - endpoint = ( - "https://run.googleapis.com/v2/projects/" - f"{project_id}/locations/{region}/jobs/{job_name}:run" - ) - run_payload = { - "overrides": { - "containerOverrides": [ - { - "args": args, - } - ] - } - } - run_response = session.post(endpoint, json=run_payload) - run_response.raise_for_status() - operation_name = cast(dict[str, Any], run_response.json()).get("name") - if not operation_name: - raise RuntimeError("Missing operation name when running job") - return str(operation_name) - - -# Modes that run alembic migrations (and possibly seed initial data) require -# explicit confirmation to prevent accidental schema changes in production. -_DESTRUCTIVE_MODES = {"full", "initial_data", "migrate_only"} - - -def _build_pipeline_args( - request_json: dict[str, Any], -) -> tuple[list[str], dict[str, Any]]: - mode = str(request_json.get("mode", "both_imports")).strip() - if mode not in MODES: - raise ValueError(f"Invalid mode: {mode}. Allowed: {sorted(MODES)}") - - # Destructive modes (alembic + seed) require an explicit opt-in flag. - if mode in _DESTRUCTIVE_MODES: - confirm = _parse_bool( - "confirm_destructive", - request_json.get("confirm_destructive"), - default=False, - ) - if not confirm: - raise ValueError( - f"mode='{mode}' runs database migrations. " - 'Set "confirm_destructive": true to proceed.' - ) - - # overwrite=true permanently replaces existing DB rows — require explicit opt-in. - overwrite_raw = request_json.get("overwrite") - if overwrite_raw is not None: - overwrite = _parse_bool("overwrite", overwrite_raw, default=False) - if overwrite: - confirm_overwrite = _parse_bool( - "confirm_overwrite", - request_json.get("confirm_overwrite"), - default=False, - ) - if not confirm_overwrite: - raise ValueError( - "overwrite=true will permanently replace existing DB rows. " - 'Set "confirm_overwrite": true to proceed.' - ) - else: - overwrite = False - - gcs_uri = str( - request_json.get("gcs_uri", "gs://ca-panel-001-resources/resources") - ).strip() - resources_path = str(request_json.get("resources_path", "/tmp/resources")).strip() - - years_raw = request_json.get("years") - if years_raw is None: - years = ["2024", "2025"] - elif isinstance(years_raw, list): - years = [str(y).strip() for y in years_raw if str(y).strip()] - else: - years = [y.strip() for y in str(years_raw).split(",") if y.strip()] - if not years: - years = ["2024", "2025"] - - default_ela_year = years[-1] if years else "2025" - default_ela_file = ( - f"{resources_path}/cde-{default_ela_year}/eladownload{default_ela_year}.xlsx" - ) - ela_file = str(request_json.get("ela_file", default_ela_file)).strip() - - ela_files_raw = request_json.get("ela_files") - if isinstance(ela_files_raw, list): - ela_files = [str(p).strip() for p in ela_files_raw if str(p).strip()] - elif isinstance(ela_files_raw, str) and ela_files_raw.strip(): - ela_files = [ela_files_raw.strip()] - else: - # Let run_import_pipeline discover year-specific ELA files after sync. - ela_files = [] - - indicators_source = _normalize_indicators_source( - str(request_json.get("indicators_source", "state")) - ) - indicators_path = str(request_json.get("indicators_path", resources_path)).strip() - indicators_paths = _discover_indicator_paths( - resources_path=resources_path, - years=years, - source=indicators_source, - indicators_path=indicators_path, - ) - batch_size = _parse_positive_int( - "batch_size", request_json.get("batch_size"), default=5000 - ) - indicator = str(request_json.get("indicator", "")).strip() - # overwrite already parsed and validated above. - skip_sync = _parse_bool("skip_sync", request_json.get("skip_sync"), default=False) - - args: list[str] = [ - "app/scripts/cde/run_import_pipeline.py", - "--mode", - mode, - "--gcs-uri", - gcs_uri, - "--resources-path", - resources_path, - "--ela-file", - ela_file, - "--years", - ",".join(years), - "--indicators-source", - indicators_source, - "--indicators-path", - indicators_path, - "--indicators-paths", - ",".join(indicators_paths), - "--batch-size", - str(batch_size), - ] - if overwrite: - args.append("--overwrite") - if skip_sync: - args.append("--skip-sync") - if ela_files: - args.extend(["--ela-files", ",".join(ela_files)]) - if indicator: - args.extend(["--indicator", indicator]) - - request_summary: dict[str, Any] = { - "mode": mode, - "gcs_uri": gcs_uri, - "resources_path": resources_path, - "ela_file": ela_file, - "ela_files": ela_files, - "years": years, - "indicators_source": indicators_source, - "indicators_path": indicators_path, - "indicators_paths": indicators_paths, - "batch_size": batch_size, - "overwrite": overwrite, - "skip_sync": skip_sync, - # Echo confirmation flags so callers can audit what was acknowledged. - "confirm_destructive": mode in _DESTRUCTIVE_MODES, - "confirm_overwrite": overwrite, - } - if indicator: - request_summary["indicator"] = indicator - - return args, request_summary - - -def trigger_backend_init(request: Any) -> tuple[str, int, dict[str, str]]: - if request.method != "POST": - return _response(405, {"error": "Method not allowed. Use POST."}) - - project_id = os.environ.get("GCP_PROJECT_ID") - region = os.environ.get("GCP_REGION") - job_name = os.environ.get("BACKEND_INIT_JOB") - if not project_id or not region or not job_name: - return _response( - 500, - { - "error": "Missing required env vars", - "required": ["GCP_PROJECT_ID", "GCP_REGION", "BACKEND_INIT_JOB"], - }, - ) - - request_json = request.get_json(silent=True) or {} - if not isinstance(request_json, dict): - return _response(400, {"error": "Request body must be a JSON object."}) - - try: - pipeline_args, summary = _build_pipeline_args(request_json) - except ValueError as exc: - return _response(400, {"error": str(exc), "allowed_modes": sorted(MODES)}) - except Exception as exc: - return _response(400, {"error": f"Invalid request: {exc}"}) - - try: - wait_for_completion = _parse_bool( - "wait_for_completion", - request_json.get("wait_for_completion"), - default=False, - ) - step_timeout_seconds = _parse_positive_int( - "step_timeout_seconds", - request_json.get("step_timeout_seconds"), - default=DEFAULT_STEP_TIMEOUT_SECONDS, - ) - poll_interval_seconds = _parse_positive_int( - "poll_interval_seconds", - request_json.get("poll_interval_seconds"), - default=DEFAULT_POLL_INTERVAL_SECONDS, - ) - except ValueError as exc: - return _response(400, {"error": str(exc)}) - - credentials, _ = google.auth.default( - scopes=["https://www.googleapis.com/auth/cloud-platform"] - ) - session = AuthorizedSession(credentials) # type: ignore[no-untyped-call] - - try: - operation_name = _start_job( - session, - project_id=project_id, - region=region, - job_name=job_name, - args=pipeline_args, - ) - - if not wait_for_completion: - return _response( - 202, - { - "job": job_name, - "status": "started", - "operation": operation_name, - "wait_for_completion": False, - "request": summary, - "args": pipeline_args, - }, - ) - - operation = _poll_operation( - session, - operation_name, - timeout_seconds=step_timeout_seconds, - poll_interval_seconds=poll_interval_seconds, - ) - operation_error = operation.get("error") - if operation_error: - return _response( - 500, - { - "error": operation_error.get("message") - or "Job run operation failed", - "operation": operation_name, - }, - ) - - execution_name = operation.get("response", {}).get("name") - if not execution_name: - return _response( - 500, - { - "error": "Missing execution name from operation response", - "operation": operation_name, - }, - ) - - execution = _poll_execution( - session, - str(execution_name), - timeout_seconds=step_timeout_seconds, - poll_interval_seconds=poll_interval_seconds, - ) - return _response( - 200, - { - "job": job_name, - "status": "completed", - "operation": operation_name, - "execution": execution_name, - "succeeded": int(execution.get("succeededCount", 0)), - "failed": int(execution.get("failedCount", 0)), - "request": summary, - "args": pipeline_args, - }, - ) - except Exception as exc: - return _response( - 500, - { - "error": "Failed to start backend import pipeline", - "message": str(exc), - "job": job_name, - }, - ) diff --git a/backend/app/scripts/gcp/functions/manual_backend_init/requirements.txt b/backend/app/scripts/gcp/functions/manual_backend_init/requirements.txt deleted file mode 100644 index 17696c3..0000000 --- a/backend/app/scripts/gcp/functions/manual_backend_init/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -google-auth>=2.30.0 -requests>=2.31.0 -functions-framework>=3.8.1 diff --git a/backend/app/scripts/gcp/gcp.defaults.env b/backend/app/scripts/gcp/gcp.defaults.env deleted file mode 100644 index a77d051..0000000 --- a/backend/app/scripts/gcp/gcp.defaults.env +++ /dev/null @@ -1,13 +0,0 @@ -# Shared defaults for Cloud Run deploy scripts. -# Override any value in .env, Cloud Build trigger env, or shell before invoking scripts. - -DEFAULT_FULL_SERVICE="capanel-full" -DEFAULT_RUN_SERVICE_ACCOUNT="capanel-runner" -DEFAULT_CLOUD_SQL_INSTANCE="capanel-pg" -DEFAULT_CLOUD_SQL_DB="capanel" -DEFAULT_CLOUD_SQL_USER="capanel_app" -DEFAULT_PROJECT_NAME="California Accountability Panel" -DEFAULT_IMPORT_RESOURCES_LOCAL_PATH="$HOME/Downloads/resources" -DEFAULT_VPC_NETWORK="default" -DEFAULT_VPC_SUBNET="default" -DEFAULT_FRONTEND_HOST_PRODUCTION="https://localhost" diff --git a/backend/app/scripts/gcp/provision_cloud_run.py b/backend/app/scripts/gcp/provision_cloud_run.py deleted file mode 100644 index 16fd229..0000000 --- a/backend/app/scripts/gcp/provision_cloud_run.py +++ /dev/null @@ -1,251 +0,0 @@ -from __future__ import annotations - -import sys - -from app.scripts.gcp.gcp_utils import ( - ScriptError, - env_or, - env_required, - load_env_file, - resolve_env_file, - run_command, -) - - -def exists(cmd: list[str]) -> bool: - result = run_command(cmd, capture_output=True, check=False) - return result.returncode == 0 - - -def main() -> int: - env_path = resolve_env_file(__file__, sys.argv[1] if len(sys.argv) > 1 else None) - print(f"Loading environment from {env_path}") - load_env_file(env_path) - - project_id = env_required("GCP_PROJECT_ID") - region = env_required("GCP_REGION", "for example us-central1") - ar_repo = env_required("GCP_AR_REPOSITORY") - run_service_account = env_required("RUN_SERVICE_ACCOUNT") - vpc_network = env_required("VPC_NETWORK", "for example default") - private_range_name = env_required("PRIVATE_RANGE_NAME") - private_range_prefix = env_required("PRIVATE_RANGE_PREFIX", "for example 16") - cloud_sql_instance = env_required("CLOUD_SQL_INSTANCE") - cloud_sql_db = env_required("CLOUD_SQL_DB") - cloud_sql_user = env_required("CLOUD_SQL_USER") - cloud_sql_password = env_required("CLOUD_SQL_PASSWORD") - import_gcs_uri = env_required("IMPORT_GCS_URI") - - cloud_sql_version = env_or("CLOUD_SQL_VERSION", "POSTGRES_18") - cloud_sql_edition = env_or("CLOUD_SQL_EDITION", "enterprise") - run_sa_email = f"{run_service_account}@{project_id}.iam.gserviceaccount.com" - - run_command(["gcloud", "config", "set", "project", project_id]) - - run_command( - [ - "gcloud", - "services", - "enable", - "run.googleapis.com", - "cloudfunctions.googleapis.com", - "eventarc.googleapis.com", - "pubsub.googleapis.com", - "artifactregistry.googleapis.com", - "cloudbuild.googleapis.com", - "sqladmin.googleapis.com", - "secretmanager.googleapis.com", - "storage.googleapis.com", - "servicenetworking.googleapis.com", - "compute.googleapis.com", - ] - ) - - if not exists( - [ - "gcloud", - "artifacts", - "repositories", - "describe", - ar_repo, - f"--location={region}", - ] - ): - run_command( - [ - "gcloud", - "artifacts", - "repositories", - "create", - ar_repo, - f"--location={region}", - "--repository-format=docker", - "--description=Container images for CAPanel services", - ] - ) - - if not exists(["gcloud", "iam", "service-accounts", "describe", run_sa_email]): - run_command( - [ - "gcloud", - "iam", - "service-accounts", - "create", - run_service_account, - "--display-name=CAPanel Cloud Run runtime", - ] - ) - - for role in [ - "roles/cloudsql.client", - "roles/artifactregistry.reader", - "roles/run.developer", - "roles/storage.objectViewer", - ]: - run_command( - [ - "gcloud", - "projects", - "add-iam-policy-binding", - project_id, - f"--member=serviceAccount:{run_sa_email}", - f"--role={role}", - ] - ) - - if not exists( - ["gcloud", "compute", "addresses", "describe", private_range_name, "--global"] - ): - run_command( - [ - "gcloud", - "compute", - "addresses", - "create", - private_range_name, - "--global", - "--purpose=VPC_PEERING", - f"--prefix-length={private_range_prefix}", - f"--network={vpc_network}", - ] - ) - - peerings = run_command( - [ - "gcloud", - "services", - "vpc-peerings", - "list", - f"--network={vpc_network}", - "--format=value(service)", - ], - capture_output=True, - ) - if "servicenetworking.googleapis.com" not in peerings.stdout.splitlines(): - run_command( - [ - "gcloud", - "services", - "vpc-peerings", - "connect", - "--service=servicenetworking.googleapis.com", - f"--network={vpc_network}", - f"--ranges={private_range_name}", - ] - ) - - if not exists(["gcloud", "sql", "instances", "describe", cloud_sql_instance]): - run_command( - [ - "gcloud", - "sql", - "instances", - "create", - cloud_sql_instance, - f"--database-version={cloud_sql_version}", - f"--edition={cloud_sql_edition}", - "--cpu=1", - "--memory=3840MiB", - f"--region={region}", - "--availability-type=zonal", - "--storage-size=20GB", - "--storage-type=SSD", - f"--network={vpc_network}", - "--no-assign-ip", - ] - ) - - if not exists( - [ - "gcloud", - "sql", - "databases", - "describe", - cloud_sql_db, - f"--instance={cloud_sql_instance}", - ] - ): - run_command( - [ - "gcloud", - "sql", - "databases", - "create", - cloud_sql_db, - f"--instance={cloud_sql_instance}", - ] - ) - - users = run_command( - [ - "gcloud", - "sql", - "users", - "list", - f"--instance={cloud_sql_instance}", - "--format=value(name)", - ], - capture_output=True, - ) - if cloud_sql_user not in users.stdout.splitlines(): - run_command( - [ - "gcloud", - "sql", - "users", - "create", - cloud_sql_user, - f"--instance={cloud_sql_instance}", - f"--password={cloud_sql_password}", - ] - ) - - # Ensure the resources bucket exists and is in the correct region - if import_gcs_uri.startswith("gs://"): - import_gcs_bucket = import_gcs_uri.split("/")[2] - if not exists( - ["gcloud", "storage", "buckets", "describe", f"gs://{import_gcs_bucket}"] - ): - print(f"Creating bucket gs://{import_gcs_bucket} in {region}") - run_command( - [ - "gcloud", - "storage", - "buckets", - "create", - f"gs://{import_gcs_bucket}", - f"--location={region}", - "--uniform-bucket-level-access", - ] - ) - - print("Provisioning complete.") - print(f"Artifact Registry: {region}-docker.pkg.dev/{project_id}/{ar_repo}") - print(f"Cloud SQL connection: {project_id}:{region}:{cloud_sql_instance}") - return 0 - - -if __name__ == "__main__": - try: - raise SystemExit(main()) - except ScriptError as exc: - raise SystemExit(str(exc)) from exc diff --git a/backend/app/scripts/gcp/render_cloud_run_service.py b/backend/app/scripts/gcp/render_cloud_run_service.py deleted file mode 100644 index e23b128..0000000 --- a/backend/app/scripts/gcp/render_cloud_run_service.py +++ /dev/null @@ -1,212 +0,0 @@ -from __future__ import annotations - -import os -from dataclasses import dataclass - -from app.scripts.gcp.gcp_utils import ScriptError, env_required, yaml_escape - - -@dataclass(frozen=True) -class RenderEnv: - full_service: str - gcp_region: str - run_service_account_email: str - frontend_image: str - backend_image: str - cloud_sql_connection_name: str - environment: str - project_name: str - api_v1_str: str - backend_cors_origins: str - frontend_host: str - cloud_sql_db: str - cloud_sql_user: str - run_data_imports: str - run_startup_data_imports: str - import_gcs_uri: str - import_resources_local_path: str - vpc_network: str | None - vpc_subnet: str | None - - -TEMPLATE = """apiVersion: serving.knative.dev/v1 -kind: Service -metadata: - name: ${full_service} - labels: - cloud.googleapis.com/location: ${gcp_region} -spec: - template: - metadata: - annotations: - run.googleapis.com/cloudsql-instances: ${cloud_sql_connection_name} -${network_annotations} spec: - serviceAccountName: ${run_service_account_email} - containers: - - name: frontend - image: ${frontend_image} - ports: - - containerPort: 8080 - startupProbe: - httpGet: - path: / - port: 8080 - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 12 - livenessProbe: - httpGet: - path: / - port: 8080 - periodSeconds: 30 - timeoutSeconds: 5 - failureThreshold: 3 - resources: - limits: - cpu: 500m - memory: 256Mi - - name: backend - image: ${backend_image} - startupProbe: - httpGet: - path: ${backend_health_check_path} - port: 9000 - initialDelaySeconds: 20 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 18 - livenessProbe: - httpGet: - path: ${backend_health_check_path} - port: 9000 - periodSeconds: 30 - timeoutSeconds: 5 - failureThreshold: 3 - env: - - name: ENVIRONMENT - value: '${environment}' - - name: PROJECT_NAME - value: '${project_name}' - - name: API_V1_STR - value: '${api_v1_str}' - - name: BACKEND_CORS_ORIGINS - value: '${backend_cors_origins}' - - name: FRONTEND_HOST - value: '${frontend_host}' - - name: CLOUD_SQL_INSTANCE_CONNECTION_NAME - value: '${cloud_sql_connection_name}' - - name: POSTGRES_SERVER - value: "localhost" - - name: POSTGRES_DB - value: '${cloud_sql_db}' - - name: POSTGRES_USER - value: '${cloud_sql_user}' - - name: RUN_DATA_IMPORTS - value: '${run_data_imports}' - - name: RUN_STARTUP_DATA_IMPORTS - value: '${run_startup_data_imports}' - - name: IMPORT_GCS_URI - value: '${import_gcs_uri}' - - name: IMPORT_RESOURCES_LOCAL_PATH - value: '${import_resources_local_path}' - - name: SECRET_KEY - valueFrom: - secretKeyRef: - key: latest - name: capanel-secret-key - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - key: latest - name: capanel-postgres-password - resources: - limits: - cpu: 1000m - memory: 2Gi -""" - - -def build_env() -> RenderEnv: - return RenderEnv( - full_service=env_required("FULL_SERVICE"), - gcp_region=env_required("GCP_REGION"), - run_service_account_email=env_required("RUN_SERVICE_ACCOUNT_EMAIL"), - frontend_image=env_required("FRONTEND_IMAGE"), - backend_image=env_required("BACKEND_IMAGE"), - cloud_sql_connection_name=env_required("CLOUD_SQL_CONNECTION_NAME"), - environment=env_required("ENVIRONMENT"), - project_name=env_required("PROJECT_NAME"), - api_v1_str=env_required("API_V1_STR"), - backend_cors_origins=env_required("BACKEND_CORS_ORIGINS"), - frontend_host=env_required("FRONTEND_HOST"), - cloud_sql_db=env_required("CLOUD_SQL_DB"), - cloud_sql_user=env_required("CLOUD_SQL_USER"), - run_data_imports=env_required("RUN_DATA_IMPORTS"), - run_startup_data_imports=env_required("RUN_STARTUP_DATA_IMPORTS"), - import_gcs_uri=env_required("IMPORT_GCS_URI"), - import_resources_local_path=env_required("IMPORT_RESOURCES_LOCAL_PATH"), - vpc_network=os.environ.get("VPC_NETWORK") or None, - vpc_subnet=os.environ.get("VPC_SUBNET") or None, - ) - - -def network_annotations(env: RenderEnv) -> str: - if env.vpc_network and env.vpc_subnet: - return ( - " run.googleapis.com/network-interfaces: " - f'\'[{{"network":"{env.vpc_network}","subnetwork":"{env.vpc_subnet}"}}]\'\n' - " run.googleapis.com/vpc-access-egress: private-ranges-only\n" - ) - return "" - - -def backend_health_check_path(api_v1_str: str) -> str: - normalized_api_v1 = "/" + api_v1_str.strip("/") - return f"{normalized_api_v1}/utils/health-check/" - - -def main() -> int: - env = build_env() - output = TEMPLATE - output = output.replace("${full_service}", env.full_service) - output = output.replace("${gcp_region}", env.gcp_region) - output = output.replace( - "${run_service_account_email}", env.run_service_account_email - ) - output = output.replace("${frontend_image}", env.frontend_image) - output = output.replace("${backend_image}", env.backend_image) - output = output.replace( - "${cloud_sql_connection_name}", env.cloud_sql_connection_name - ) - output = output.replace("${environment}", yaml_escape(env.environment)) - output = output.replace("${project_name}", yaml_escape(env.project_name)) - output = output.replace("${api_v1_str}", yaml_escape(env.api_v1_str)) - output = output.replace( - "${backend_cors_origins}", yaml_escape(env.backend_cors_origins) - ) - output = output.replace("${frontend_host}", yaml_escape(env.frontend_host)) - output = output.replace("${cloud_sql_db}", yaml_escape(env.cloud_sql_db)) - output = output.replace("${cloud_sql_user}", yaml_escape(env.cloud_sql_user)) - output = output.replace("${run_data_imports}", yaml_escape(env.run_data_imports)) - output = output.replace( - "${run_startup_data_imports}", yaml_escape(env.run_startup_data_imports) - ) - output = output.replace("${import_gcs_uri}", yaml_escape(env.import_gcs_uri)) - output = output.replace( - "${import_resources_local_path}", yaml_escape(env.import_resources_local_path) - ) - output = output.replace( - "${backend_health_check_path}", backend_health_check_path(env.api_v1_str) - ) - output = output.replace("${network_annotations}", network_annotations(env)) - - print(output, end="") - return 0 - - -if __name__ == "__main__": - try: - raise SystemExit(main()) - except ScriptError as exc: - raise SystemExit(str(exc)) from exc diff --git a/backend/app/scripts/gcp/rotate_exposed_secrets.py b/backend/app/scripts/gcp/rotate_exposed_secrets.py deleted file mode 100644 index c7ec681..0000000 --- a/backend/app/scripts/gcp/rotate_exposed_secrets.py +++ /dev/null @@ -1,158 +0,0 @@ -from __future__ import annotations - -import argparse -import json -import secrets -import string -from collections.abc import Iterable -from dataclasses import dataclass - -TARGET_ALL = "all" -TARGET_GCLOUD = "gcloud" -TARGET_LOCAL_DB = "local-db" -TARGET_SECRET_KEY = "secret-key" - -ALL_TARGETS = { - TARGET_ALL, - TARGET_GCLOUD, - TARGET_LOCAL_DB, - TARGET_SECRET_KEY, -} - - -@dataclass(frozen=True) -class RotationConfig: - password_length: int - output_format: str - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser( - description=( - "Generate rotated secret values for exposed credentials. " - "Select one or more targets, or use --target all." - ) - ) - parser.add_argument( - "--target", - action="append", - choices=sorted(ALL_TARGETS), - help=( - "Secret groups to rotate. Repeat for multiple groups. " - "Choices: all, gcloud, local-db, secret-key" - ), - ) - parser.add_argument( - "--password-length", - type=int, - default=32, - help="Length for generated passwords (default: 32, min: 16).", - ) - parser.add_argument( - "--format", - choices=("env", "json"), - default="env", - help="Output format (default: env).", - ) - return parser.parse_args() - - -def expand_targets(raw_targets: list[str] | None) -> set[str]: - if not raw_targets: - msg = ( - "No targets selected. Use --target all or pass one/more targets, " - "for example: --target gcloud --target secret-key" - ) - raise ValueError(msg) - - targets = set(raw_targets) - if TARGET_ALL in targets: - return {TARGET_GCLOUD, TARGET_LOCAL_DB, TARGET_SECRET_KEY} - return targets - - -def generate_strong_password(length: int) -> str: - if length < 16: - msg = "--password-length must be >= 16." - raise ValueError(msg) - - upper = string.ascii_uppercase - lower = string.ascii_lowercase - digits = string.digits - punctuation = "!@#$%^&*()-_=+[]{}:,.?" - full_alphabet = upper + lower + digits + punctuation - - required_chars = [ - secrets.choice(upper), - secrets.choice(lower), - secrets.choice(digits), - secrets.choice(punctuation), - ] - remaining = [secrets.choice(full_alphabet) for _ in range(length - 4)] - all_chars = required_chars + remaining - secrets.SystemRandom().shuffle(all_chars) - return "".join(all_chars) - - -def build_rotations(targets: Iterable[str], config: RotationConfig) -> dict[str, str]: - selected = set(targets) - values: dict[str, str] = {} - - if TARGET_SECRET_KEY in selected: - values["SECRET_KEY"] = secrets.token_urlsafe(32) - - if TARGET_GCLOUD in selected: - values["CLOUD_SQL_PASSWORD"] = generate_strong_password(config.password_length) - - if TARGET_LOCAL_DB in selected: - values["POSTGRES_PASSWORD"] = generate_strong_password(config.password_length) - values["FIRST_SUPERUSER_PASSWORD"] = generate_strong_password( - config.password_length - ) - - return values - - -def print_env(values: dict[str, str]) -> None: - for key, value in values.items(): - print(f"{key}={value}") - - -def main() -> int: - """ - # Only SECRET_KEY (uses secrets.token_urlsafe(32)) - python3 backend/app/scripts/gcp/rotate_exposed_secrets.py --target secret-key - - # Only GCP-related passwords - python3 backend/app/scripts/gcp/rotate_exposed_secrets.py --target gcloud - - # Only local DB passwords - python3 backend/app/scripts/gcp/rotate_exposed_secrets.py --target local-db - - # Everything exposed - python3 backend/app/scripts/gcp/rotate_exposed_secrets.py --target all - - # Combined, JSON output - python3 backend/app/scripts/gcp/rotate_exposed_secrets.py --target gcloud --target local-db --target secret-key --format json - """ - args = parse_args() - try: - config = RotationConfig( - password_length=args.password_length, - output_format=args.format, - ) - selected_targets = expand_targets(args.target) - rotated = build_rotations(selected_targets, config) - except ValueError as exc: - raise SystemExit(str(exc)) from exc - - if config.output_format == "json": - print(json.dumps(rotated, indent=2)) - return 0 - - print_env(rotated) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/backend/app/scripts/gcp/rotate_gcp_credentials.py b/backend/app/scripts/gcp/rotate_gcp_credentials.py deleted file mode 100644 index 706ef3a..0000000 --- a/backend/app/scripts/gcp/rotate_gcp_credentials.py +++ /dev/null @@ -1,286 +0,0 @@ -from __future__ import annotations - -import argparse -import shlex -import subprocess -import sys -from pathlib import Path - -from app.scripts.gcp.gcp_utils import ( - ScriptError, - env_or, - env_required, - load_env_file, - log, - resolve_env_file, - run_command, -) - -SCRIPT_DIR = Path(__file__).resolve().parent -BACKEND_DIR = SCRIPT_DIR.parents[1] -if str(BACKEND_DIR) not in sys.path: - sys.path.insert(0, str(BACKEND_DIR)) - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser( - description=( - "Rotate Cloud SQL app password and service account keys, " - "and update runtime references." - ) - ) - parser.add_argument( - "env_file", - nargs="?", - default=None, - help="Optional env file path. Defaults to repo root .env.", - ) - parser.add_argument( - "--project-id", - default=None, - help="GCP project id (default: GCP_PROJECT_ID from env).", - ) - parser.add_argument( - "--instance", - default=None, - help="Cloud SQL instance id (default: CLOUD_SQL_INSTANCE from env).", - ) - parser.add_argument( - "--db-user", - default=None, - help="Cloud SQL database user (default: CLOUD_SQL_USER from env).", - ) - parser.add_argument( - "--new-db-password", - default=None, - help="New DB password (default: CLOUD_SQL_PASSWORD from env).", - ) - parser.add_argument( - "--secret-name", - default="capanel-postgres-password", - help="Secret Manager secret name for DB password.", - ) - parser.add_argument( - "--region", - default=None, - help="Cloud Run region (default: GCP_REGION from env).", - ) - parser.add_argument( - "--restart-service", - action="append", - default=[], - help=( - "Cloud Run service to restart via update command. " - "Repeat flag for multiple services." - ), - ) - parser.add_argument( - "--service-account-email", - default=None, - help=( - "Service account email. Defaults to " - "RUN_SERVICE_ACCOUNT@GCP_PROJECT_ID.iam.gserviceaccount.com." - ), - ) - parser.add_argument( - "--create-sa-key", - default=None, - help="Create a new service-account JSON key at this output path.", - ) - parser.add_argument( - "--delete-sa-key", - action="append", - default=[], - help="Delete a service-account key id. Repeat for multiple key ids.", - ) - parser.add_argument( - "--rotate-cloud-sql-password", - action="store_true", - help="Run gcloud sql users set-password with the selected password.", - ) - parser.add_argument( - "--update-secret-manager", - action="store_true", - help="Add new version to Secret Manager for DB password.", - ) - parser.add_argument( - "--list-sa-keys", - action="store_true", - help="List current service-account keys.", - ) - parser.add_argument( - "--all", - action="store_true", - help=( - "Run common rotation flow: rotate DB password, update secret manager, " - "restart backend service, and list service-account keys." - ), - ) - return parser.parse_args() - - -def run_sensitive_command(cmd: list[str]) -> subprocess.CompletedProcess[str]: - masked_cmd = [] - for item in cmd: - if item.startswith("--password="): - masked_cmd.append("--password=***") - continue - masked_cmd.append(item) - print(f"+ {shlex.join(masked_cmd)}", flush=True) - return subprocess.run(cmd, check=True, text=True, capture_output=False) - - -def normalize_sa_email(project_id: str, provided: str | None) -> str: - if provided: - return provided - run_service_account = env_required("RUN_SERVICE_ACCOUNT") - return f"{run_service_account}@{project_id}.iam.gserviceaccount.com" - - -def ensure_actions_selected(args: argparse.Namespace) -> None: - if args.all: - return - if args.rotate_cloud_sql_password: - return - if args.update_secret_manager: - return - if args.restart_service: - return - if args.list_sa_keys: - return - if args.create_sa_key: - return - if args.delete_sa_key: - return - msg = ( - "No actions selected. Pass one or more action flags, " - "for example --rotate-cloud-sql-password --update-secret-manager." - ) - raise ScriptError(msg) - - -def main() -> int: - args = parse_args() - env_path = resolve_env_file(__file__, args.env_file) - print(f"Loading environment from {env_path}") - load_env_file(env_path) - - ensure_actions_selected(args) - - project_id = args.project_id or env_required("GCP_PROJECT_ID") - instance = args.instance or env_required("CLOUD_SQL_INSTANCE") - db_user = args.db_user or env_required("CLOUD_SQL_USER") - new_db_password = args.new_db_password or env_required("CLOUD_SQL_PASSWORD") - region = args.region or env_required("GCP_REGION") - default_backend_service = env_or("BACKEND_SERVICE", "capanel-backend") - - rotate_cloud_sql_password = args.rotate_cloud_sql_password or args.all - update_secret_manager = args.update_secret_manager or args.all - list_sa_keys = args.list_sa_keys or args.all - - restart_services = list(args.restart_service) - if args.all and not restart_services: - restart_services = [default_backend_service] - - sa_email = normalize_sa_email(project_id, args.service_account_email) - - if rotate_cloud_sql_password: - log("rotate-gcp-credentials", "Rotating Cloud SQL user password") - run_sensitive_command( - [ - "gcloud", - "sql", - "users", - "set-password", - db_user, - f"--instance={instance}", - f"--project={project_id}", - f"--password={new_db_password}", - ] - ) - - if update_secret_manager: - log("rotate-gcp-credentials", f"Updating secret {args.secret_name}") - run_command( - [ - "gcloud", - "secrets", - "versions", - "add", - args.secret_name, - f"--project={project_id}", - "--data-file=-", - ], - input_text=new_db_password, - ) - - for service in restart_services: - log("rotate-gcp-credentials", f"Restarting Cloud Run service {service}") - run_command( - [ - "gcloud", - "run", - "services", - "update", - service, - f"--project={project_id}", - f"--region={region}", - ] - ) - - if list_sa_keys: - log("rotate-gcp-credentials", f"Listing keys for {sa_email}") - run_command( - [ - "gcloud", - "iam", - "service-accounts", - "keys", - "list", - f"--iam-account={sa_email}", - f"--project={project_id}", - ] - ) - - if args.create_sa_key: - key_path = Path(args.create_sa_key).expanduser().resolve() - key_path.parent.mkdir(parents=True, exist_ok=True) - log("rotate-gcp-credentials", f"Creating new key at {key_path}") - run_command( - [ - "gcloud", - "iam", - "service-accounts", - "keys", - "create", - str(key_path), - f"--iam-account={sa_email}", - f"--project={project_id}", - ] - ) - - for key_id in args.delete_sa_key: - log("rotate-gcp-credentials", f"Deleting service-account key {key_id}") - run_command( - [ - "gcloud", - "iam", - "service-accounts", - "keys", - "delete", - key_id, - f"--iam-account={sa_email}", - f"--project={project_id}", - "--quiet", - ] - ) - - log("rotate-gcp-credentials", "Rotation actions complete") - return 0 - - -if __name__ == "__main__": - try: - raise SystemExit(main()) - except ScriptError as exc: - raise SystemExit(str(exc)) from exc diff --git a/backend/app/scripts/gcp/sync_gcs_resources.py b/backend/app/scripts/gcp/sync_gcs_resources.py deleted file mode 100644 index 158aae0..0000000 --- a/backend/app/scripts/gcp/sync_gcs_resources.py +++ /dev/null @@ -1,186 +0,0 @@ -from __future__ import annotations - -import argparse -import os -import sys -from pathlib import Path -from urllib.parse import quote - -import httpx - -METADATA_URL = ( - "http://metadata.google.internal/computeMetadata/v1/" - "instance/service-accounts/default/token" -) - - -def parse_gs_uri(uri: str) -> tuple[str, str]: - if not uri.startswith("gs://"): - msg = f"Expected gs:// URI, got: {uri}" - raise ValueError(msg) - remainder = uri.removeprefix("gs://") - bucket, _, prefix = remainder.partition("/") - if not bucket: - msg = f"Bucket is missing in URI: {uri}" - raise ValueError(msg) - normalized_prefix = prefix.strip("/") - if normalized_prefix: - normalized_prefix = f"{normalized_prefix}/" - return bucket, normalized_prefix - - -def _get_token_from_adc() -> str: - """Obtain a bearer token via Application Default Credentials (local dev).""" - try: - import google.auth - import google.auth.transport.requests - except ImportError as exc: - msg = "google-auth is not installed. Run: pip install google-auth" - raise RuntimeError(msg) from exc - - credentials, _ = google.auth.default( - scopes=["https://www.googleapis.com/auth/devstorage.read_only"] - ) - request = google.auth.transport.requests.Request() - credentials.refresh(request) # type: ignore[no-untyped-call] - if not credentials.token: - msg = "ADC did not return an access token." - raise RuntimeError(msg) - return str(credentials.token) - - -def get_access_token(client: httpx.Client) -> str: - """Return a GCS bearer token. - - Tries the GCE metadata server first (works inside Cloud Run / GCE). - Falls back to Application Default Credentials when running locally. - """ - try: - response = client.get( - METADATA_URL, - headers={"Metadata-Flavor": "Google"}, - timeout=3.0, - ) - response.raise_for_status() - payload = response.json() - token = payload.get("access_token") - if not token: - msg = "Metadata server response did not include access_token." - raise RuntimeError(msg) - return str(token) - except (httpx.ConnectError, httpx.TimeoutException): - print( - "[sync_gcs_resources] GCE metadata server unreachable; " - "falling back to Application Default Credentials.", - flush=True, - ) - return _get_token_from_adc() - - -def list_objects( - client: httpx.Client, token: str, bucket: str, prefix: str -) -> list[str]: - object_names: list[str] = [] - page_token: str | None = None - headers = {"Authorization": f"Bearer {token}"} - - while True: - params: dict[str, str] = {"prefix": prefix, "maxResults": "1000"} - if page_token: - params["pageToken"] = page_token - response = client.get( - f"https://storage.googleapis.com/storage/v1/b/{bucket}/o", - params=params, - headers=headers, - timeout=30.0, - ) - if response.status_code == 404: - return [] - response.raise_for_status() - payload = response.json() - for item in payload.get("items", []): - name = item.get("name") - if name and not str(name).endswith("/"): - object_names.append(str(name)) - page_token = payload.get("nextPageToken") - if not page_token: - break - - return object_names - - -def download_objects( - client: httpx.Client, - token: str, - bucket: str, - prefix: str, - destination: Path, - object_names: list[str], -) -> int: - headers = {"Authorization": f"Bearer {token}"} - downloaded_count = 0 - - for object_name in object_names: - encoded_name = quote(object_name, safe="") - response = client.get( - f"https://storage.googleapis.com/storage/v1/b/{bucket}/o/{encoded_name}", - params={"alt": "media"}, - headers=headers, - timeout=120.0, - ) - response.raise_for_status() - - relative_name = object_name - if prefix and relative_name.startswith(prefix): - relative_name = relative_name[len(prefix) :] - if not relative_name: - continue - - output_path = destination / relative_name - output_path.parent.mkdir(parents=True, exist_ok=True) - output_path.write_bytes(response.content) - downloaded_count += 1 - - return downloaded_count - - -def main() -> None: - parser = argparse.ArgumentParser( - description="Sync objects from a gs:// bucket prefix into a local folder." - ) - parser.add_argument( - "--uri", - help="Source GCS URI, for example gs://ca-panel-001-resources or gs://bucket/path", - ) - parser.add_argument( - "--dest", - help="Destination directory inside the container.", - ) - args = parser.parse_args() - - # Fallback to environment variables if arguments are missing - uri = args.uri or os.getenv("IMPORT_GCS_URI") - dest = args.dest or os.getenv("IMPORT_RESOURCES_DEST_PATH") - - if not uri: - print("Error: --uri or IMPORT_GCS_URI environment variable is required.") - sys.exit(1) - if not dest: - print( - "Error: --dest or IMPORT_RESOURCES_DEST_PATH environment variable is required." - ) - sys.exit(1) - - destination = Path(dest).resolve() - destination.mkdir(parents=True, exist_ok=True) - - bucket, prefix = parse_gs_uri(uri) - with httpx.Client(follow_redirects=True) as client: - token = get_access_token(client) - objects = list_objects(client, token, bucket, prefix) - count = download_objects(client, token, bucket, prefix, destination, objects) - print(f"Downloaded {count} object(s) from {uri} to {destination}") - - -if __name__ == "__main__": - main() diff --git a/backend/app/scripts/gcp/gcp_utils.py b/backend/app/scripts/gcp_utils.py similarity index 98% rename from backend/app/scripts/gcp/gcp_utils.py rename to backend/app/scripts/gcp_utils.py index 8bf6bf3..2d3dba5 100644 --- a/backend/app/scripts/gcp/gcp_utils.py +++ b/backend/app/scripts/gcp_utils.py @@ -4,6 +4,7 @@ import shlex import shutil import subprocess +import sys from collections.abc import Mapping from dataclasses import dataclass from datetime import UTC, datetime @@ -64,7 +65,7 @@ def timestamp() -> str: def log(scope: str, message: str) -> None: - print(f"[{timestamp()}] [{scope}] {message}", flush=True) + print(f"[{timestamp()}] [{scope}] {message}", file=sys.stderr, flush=True) def run_command( @@ -81,7 +82,7 @@ def run_command( raise ScriptError(msg) resolved_cmd = [resolve_executable(cmd[0]), *cmd[1:]] - print(f"+ {shlex.join(cmd)}", flush=True) + print(f"+ {shlex.join(cmd)}", file=sys.stderr, flush=True) return subprocess.run( resolved_cmd, cwd=str(cwd) if cwd is not None else None, diff --git a/backend/app/scripts/generate_client.py b/backend/app/scripts/generate_client.py index 61d2a85..8d988d8 100644 --- a/backend/app/scripts/generate_client.py +++ b/backend/app/scripts/generate_client.py @@ -1,6 +1,6 @@ from __future__ import annotations -from app.scripts.gcp.gcp_utils import ScriptError, compute_paths, run_command +from app.scripts.gcp_utils import ScriptError, compute_paths, run_command def main() -> int: diff --git a/backend/app/scripts/initial_data.py b/backend/app/scripts/initial_data.py index a3b8394..fe154bc 100644 --- a/backend/app/scripts/initial_data.py +++ b/backend/app/scripts/initial_data.py @@ -3,7 +3,7 @@ from sqlmodel import Session from app.core.database import engine, init_db -from app.scripts.gcp.gcp_utils import load_repo_env_if_present +from app.scripts.gcp_utils import load_repo_env_if_present load_repo_env_if_present(__file__, scope="initial_data") diff --git a/backend/app/scripts/main.py b/backend/app/scripts/main.py deleted file mode 100644 index 2153b5e..0000000 --- a/backend/app/scripts/main.py +++ /dev/null @@ -1,456 +0,0 @@ -import json -import os -import time -from typing import Any, TypedDict, cast - -import google.auth -from google.auth.transport.requests import ( - AuthorizedSession, -) - -MODES = { - "full", - "initial_data", - "import_ela_data", - "import_indicators", - "both_imports", -} - - -class Step(TypedDict): - name: str - args: list[str] - - -def _env_int(name: str, default: int) -> int: - raw = os.environ.get(name) - if raw is None or raw == "": - return default - try: - return int(raw) - except ValueError: - return default - - -def _parse_bool(raw: Any, default: bool = False) -> bool: - if raw is None: - return default - if isinstance(raw, bool): - return raw - if isinstance(raw, (int, float)): - return bool(raw) - if isinstance(raw, str): - normalized = raw.strip().lower() - if normalized in {"1", "true", "t", "yes", "y", "on"}: - return True - if normalized in {"0", "false", "f", "no", "n", "off"}: - return False - raise ValueError("must be a boolean") - - -DEFAULT_STEP_TIMEOUT_SECONDS = _env_int("JOB_STEP_TIMEOUT_SECONDS", 7200) -DEFAULT_POLL_INTERVAL_SECONDS = max(1, _env_int("JOB_POLL_INTERVAL_SECONDS", 10)) - - -def _response(status: int, payload: dict[str, Any]) -> tuple[str, int, dict[str, str]]: - return json.dumps(payload), status, {"Content-Type": "application/json"} - - -def _poll_operation( - session: AuthorizedSession, - operation_name: str, - *, - timeout_seconds: int = 1800, - poll_interval_seconds: int = 5, -) -> dict[str, Any]: - operation_url = f"https://run.googleapis.com/v2/{operation_name}" - deadline = time.time() + timeout_seconds - - while True: - response = session.get(operation_url) - response.raise_for_status() - payload = cast(dict[str, Any], response.json()) - if payload.get("done"): - return payload - if time.time() >= deadline: - msg = f"Timed out waiting for operation {operation_name}" - raise TimeoutError(msg) - time.sleep(poll_interval_seconds) - - -def _poll_execution( - session: AuthorizedSession, - execution_name: str, - *, - timeout_seconds: int = 1800, - poll_interval_seconds: int = 5, -) -> dict[str, Any]: - execution_url = f"https://run.googleapis.com/v2/{execution_name}" - deadline = time.time() + timeout_seconds - - while True: - response = session.get(execution_url) - response.raise_for_status() - execution = cast(dict[str, Any], response.json()) - conditions = execution.get("conditions", []) - completed = next( - (c for c in conditions if c.get("type") == "Completed"), - None, - ) - if completed and completed.get("status") == "True": - return execution - if completed and completed.get("status") == "False": - msg = completed.get("message") or "Cloud Run job execution failed" - raise RuntimeError(msg) - if time.time() >= deadline: - msg = f"Timed out waiting for execution {execution_name}" - raise TimeoutError(msg) - time.sleep(poll_interval_seconds) - - -def _run_job_step( - session: AuthorizedSession, - *, - project_id: str, - region: str, - job_name: str, - step_name: str, - args: list[str], - step_timeout_seconds: int, - poll_interval_seconds: int, -) -> dict[str, Any]: - endpoint = ( - "https://run.googleapis.com/v2/projects/" - f"{project_id}/locations/{region}/jobs/{job_name}:run" - ) - run_payload = { - "overrides": { - "containerOverrides": [ - { - "args": args, - } - ] - } - } - - run_response = session.post(endpoint, json=run_payload) - run_response.raise_for_status() - run_body = cast(dict[str, Any], run_response.json()) - operation_name = run_body.get("name") - if not operation_name: - msg = f"Missing operation name when running step '{step_name}'" - raise RuntimeError(msg) - - operation = _poll_operation( - session, - operation_name, - timeout_seconds=step_timeout_seconds, - poll_interval_seconds=poll_interval_seconds, - ) - operation_error = operation.get("error") - if operation_error: - msg = operation_error.get("message") or f"Step '{step_name}' failed" - raise RuntimeError(msg) - - execution_name = operation.get("response", {}).get("name") - if not execution_name: - msg = f"Missing execution name when running step '{step_name}'" - raise RuntimeError(msg) - - execution = _poll_execution( - session, - execution_name, - timeout_seconds=step_timeout_seconds, - poll_interval_seconds=poll_interval_seconds, - ) - return { - "step": step_name, - "args": args, - "execution": execution_name, - "succeeded": int(execution.get("succeededCount", 0)), - "failed": int(execution.get("failedCount", 0)), - } - - -def _build_steps( - *, - mode: str, - gcs_uri: str, - resources_path: str, - ela_file: str, - ela_files: list[str], - indicators_source: str, - indicators_path: str, - batch_size: int, - overwrite: bool, - skip_sync: bool, - indicator: str, - years: list[str], -) -> list[Step]: - migrate_step: Step = { - "name": "migrate", - "args": ["-m", "alembic", "upgrade", "head"], - } - initial_data_step: Step = { - "name": "initial_data", - "args": ["app/scripts/initial_data.py"], - } - sync_step: Step = { - "name": "sync_gcs_resources", - "args": [ - "app/scripts/gcp/sync_gcs_resources.py", - "--uri", - gcs_uri, - "--dest", - resources_path, - ], - } - import_ela_step: Step = { - "name": "import_ela_data", - "args": [ - "app/scripts/cde/import_ela_data.py", - ela_file, - "--batch-size", - str(batch_size), - ], - } - import_indicators_step: Step = { - "name": "import_indicators", - "args": [ - "app/scripts/cde/import_indicators.py", - "--source", - indicators_source, - "--path", - indicators_path, - "--batch-size", - str(batch_size), - ], - } - if indicator: - import_indicators_step["args"].extend(["--indicator", indicator]) - if years: - import_indicators_step["args"].extend(["--years", ",".join(years)]) - if overwrite: - import_ela_step["args"].append("--overwrite") - import_indicators_step["args"].append("--overwrite") - - if mode == "initial_data": - return [migrate_step, initial_data_step] - if mode == "import_ela_data": - return [import_ela_step] if skip_sync else [sync_step, import_ela_step] - if mode == "import_indicators": - return ( - [import_indicators_step] - if skip_sync - else [sync_step, import_indicators_step] - ) - if mode == "both_imports": - ela_steps: list[Step] = [] - for i, current_ela_file in enumerate(ela_files): - ela_steps.append( - { - "name": f"import_ela_data_{i + 1}", - "args": [ - "app/scripts/cde/import_ela_data.py", - current_ela_file, - "--batch-size", - str(batch_size), - ], - } - ) - if overwrite: - ela_steps[-1]["args"].append("--overwrite") - import_indicators_all_step: Step = { - "name": "import_indicators_all_files", - "args": [ - "app/scripts/cde/import_indicators.py", - "--source", - indicators_source, - "--path", - indicators_path, - "--batch-size", - str(batch_size), - "--all-files", - ], - } - if indicator: - import_indicators_all_step["args"].extend(["--indicator", indicator]) - if years: - import_indicators_all_step["args"].extend(["--years", ",".join(years)]) - if overwrite: - import_indicators_all_step["args"].append("--overwrite") - if skip_sync: - return [*ela_steps, import_indicators_all_step] - return [sync_step, *ela_steps, import_indicators_all_step] - if skip_sync: - return [ - migrate_step, - initial_data_step, - import_ela_step, - import_indicators_step, - ] - return [ - migrate_step, - initial_data_step, - sync_step, - import_ela_step, - import_indicators_step, - ] - - -def trigger_backend_init(request: Any) -> tuple[str, int, dict[str, str]]: - if request.method != "POST": - return _response(405, {"error": "Method not allowed. Use POST."}) - - project_id = os.environ.get("GCP_PROJECT_ID") - region = os.environ.get("GCP_REGION") - job_name = os.environ.get("BACKEND_INIT_JOB") - - if not project_id or not region or not job_name: - return _response( - 500, - { - "error": "Missing required env vars", - "required": ["GCP_PROJECT_ID", "GCP_REGION", "BACKEND_INIT_JOB"], - }, - ) - - request_json = request.get_json(silent=True) or {} - if not isinstance(request_json, dict): - return _response(400, {"error": "Request body must be a JSON object."}) - mode = str(request_json.get("mode", "full")).strip() - if mode not in MODES: - return _response( - 400, - { - "error": "Invalid mode.", - "allowed_modes": sorted(MODES), - }, - ) - gcs_uri = str( - request_json.get("gcs_uri", "gs://ca-panel-001-resources/resources") - ).strip() - resources_path = str(request_json.get("resources_path", "/tmp/resources")).strip() - ela_file = str( - request_json.get("ela_file", f"{resources_path}/cde/eladownload2025.xlsx") - ).strip() - years_raw = request_json.get("years") - years: list[str] - if years_raw is None: - years = ["2024", "2025"] - elif isinstance(years_raw, list): - years = [str(y).strip() for y in years_raw if str(y).strip()] - else: - years = [y.strip() for y in str(years_raw).split(",") if y.strip()] - - ela_files_raw = request_json.get("ela_files") - if isinstance(ela_files_raw, list): - ela_files = [str(p).strip() for p in ela_files_raw if str(p).strip()] - elif isinstance(ela_files_raw, str) and ela_files_raw.strip(): - ela_files = [ela_files_raw.strip()] - else: - ela_files = [f"{resources_path}/cde/eladownload{year}.xlsx" for year in years] - if not ela_files: - ela_files = [ela_file] - indicators_source = str(request_json.get("indicators_source", "cde")).strip() - indicators_path = str( - request_json.get("indicators_path", f"{resources_path}/cde") - ).strip() - try: - batch_size = int(request_json.get("batch_size", 1000)) - except (TypeError, ValueError): - return _response(400, {"error": "batch_size must be an integer."}) - if batch_size <= 0: - return _response(400, {"error": "batch_size must be > 0."}) - try: - step_timeout_seconds = int( - request_json.get("step_timeout_seconds", DEFAULT_STEP_TIMEOUT_SECONDS) - ) - except (TypeError, ValueError): - return _response(400, {"error": "step_timeout_seconds must be an integer."}) - if step_timeout_seconds <= 0: - return _response(400, {"error": "step_timeout_seconds must be > 0."}) - try: - poll_interval_seconds = int( - request_json.get("poll_interval_seconds", DEFAULT_POLL_INTERVAL_SECONDS) - ) - except (TypeError, ValueError): - return _response(400, {"error": "poll_interval_seconds must be an integer."}) - if poll_interval_seconds <= 0: - return _response(400, {"error": "poll_interval_seconds must be > 0."}) - indicator = str(request_json.get("indicator", "")).strip() - try: - overwrite = _parse_bool(request_json.get("overwrite"), False) - except ValueError: - return _response(400, {"error": "overwrite must be a boolean."}) - try: - skip_sync = _parse_bool(request_json.get("skip_sync"), False) - except ValueError: - return _response(400, {"error": "skip_sync must be a boolean."}) - - if not gcs_uri.startswith("gs://"): - return _response(400, {"error": "gcs_uri must start with gs://"}) - - credentials, _ = google.auth.default( - scopes=["https://www.googleapis.com/auth/cloud-platform"] - ) - session = AuthorizedSession(credentials) # type: ignore[no-untyped-call] - - steps = _build_steps( - mode=mode, - gcs_uri=gcs_uri, - resources_path=resources_path, - ela_file=ela_file, - ela_files=ela_files, - indicators_source=indicators_source, - indicators_path=indicators_path, - batch_size=batch_size, - overwrite=overwrite, - skip_sync=skip_sync, - indicator=indicator, - years=years, - ) - - completed_steps: list[dict[str, Any]] = [] - for step in steps: - try: - result = _run_job_step( - session, - project_id=project_id, - region=region, - job_name=job_name, - step_name=step["name"], - args=step["args"], - step_timeout_seconds=step_timeout_seconds, - poll_interval_seconds=poll_interval_seconds, - ) - completed_steps.append(result) - except Exception as exc: - return _response( - 500, - { - "error": "Backend import pipeline failed", - "job": job_name, - "failed_step": step["name"], - "message": str(exc), - "completed_steps": completed_steps, - }, - ) - - return _response( - 200, - { - "job": job_name, - "mode": mode, - "gcs_uri": gcs_uri, - "resources_path": resources_path, - "years": years, - "ela_files": ela_files, - "overwrite": overwrite, - "skip_sync": skip_sync, - "step_timeout_seconds": step_timeout_seconds, - "poll_interval_seconds": poll_interval_seconds, - "status": "completed", - "steps": completed_steps, - }, - ) diff --git a/backend/app/scripts/prestart.py b/backend/app/scripts/prestart.py index f390fa5..7186adc 100644 --- a/backend/app/scripts/prestart.py +++ b/backend/app/scripts/prestart.py @@ -1,6 +1,6 @@ from __future__ import annotations -from app.scripts.gcp.gcp_utils import ScriptError, log, run_command +from app.scripts.gcp_utils import ScriptError, log, run_command def main() -> int: diff --git a/backend/app/scripts/prestart_with_data.py b/backend/app/scripts/prestart_with_data.py deleted file mode 100644 index dfdc9c1..0000000 --- a/backend/app/scripts/prestart_with_data.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import annotations - -from app.scripts import prestart -from app.scripts.gcp.gcp_utils import ScriptError, log - - -def main() -> int: - prestart.main() - log( - "prestart-with-data", - "Prestart tasks completed (initial_data only; imports must be triggered manually)", - ) - return 0 - - -if __name__ == "__main__": - try: - raise SystemExit(main()) - except ScriptError as exc: - raise SystemExit(str(exc)) from exc diff --git a/backend/docs/source/_extension/gallery_directive.py b/backend/docs/source/_extension/gallery_directive.py index 7486764..ae3f480 100644 --- a/backend/docs/source/_extension/gallery_directive.py +++ b/backend/docs/source/_extension/gallery_directive.py @@ -18,7 +18,7 @@ from sphinx.application import Sphinx from sphinx.util import logging from sphinx.util.docutils import SphinxDirective -from yaml import safe_load # type: ignore[import-untyped] +from yaml import safe_load logger = logging.getLogger(__name__) diff --git a/backend/docs/source/_static/image/favicon/apple-touch-icon.png b/backend/docs/source/_static/image/favicon/apple-touch-icon.png new file mode 100644 index 0000000..0ed1328 Binary files /dev/null and b/backend/docs/source/_static/image/favicon/apple-touch-icon.png differ diff --git a/backend/docs/source/_static/image/favicon/favicon-96x96.png b/backend/docs/source/_static/image/favicon/favicon-96x96.png new file mode 100644 index 0000000..755ec9d Binary files /dev/null and b/backend/docs/source/_static/image/favicon/favicon-96x96.png differ diff --git a/backend/docs/source/_static/image/favicon/favicon.ico b/backend/docs/source/_static/image/favicon/favicon.ico new file mode 100644 index 0000000..d1f4399 Binary files /dev/null and b/backend/docs/source/_static/image/favicon/favicon.ico differ diff --git a/backend/docs/source/_static/image/favicon/favicon.svg b/backend/docs/source/_static/image/favicon/favicon.svg new file mode 100644 index 0000000..ede3ce5 --- /dev/null +++ b/backend/docs/source/_static/image/favicon/favicon.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/docs/source/_static/image/favicon/site.webmanifest b/backend/docs/source/_static/image/favicon/site.webmanifest new file mode 100644 index 0000000..f775e36 --- /dev/null +++ b/backend/docs/source/_static/image/favicon/site.webmanifest @@ -0,0 +1,21 @@ +{ + "name": "MyWebSite", + "short_name": "MySite", + "icons": [ + { + "src": "/web-app-manifest-192x192.png?v=20260509", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/web-app-manifest-512x512.png?v=20260509", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/backend/docs/source/_static/image/favicon/web-app-manifest-192x192.png b/backend/docs/source/_static/image/favicon/web-app-manifest-192x192.png new file mode 100644 index 0000000..a61268a Binary files /dev/null and b/backend/docs/source/_static/image/favicon/web-app-manifest-192x192.png differ diff --git a/backend/docs/source/_static/image/favicon/web-app-manifest-512x512.png b/backend/docs/source/_static/image/favicon/web-app-manifest-512x512.png new file mode 100644 index 0000000..7e99187 Binary files /dev/null and b/backend/docs/source/_static/image/favicon/web-app-manifest-512x512.png differ diff --git a/backend/docs/source/conf.py b/backend/docs/source/conf.py index 5b39cb0..072ca50 100644 --- a/backend/docs/source/conf.py +++ b/backend/docs/source/conf.py @@ -15,7 +15,7 @@ sys.path.insert(0, os.path.abspath("../..")) sys.path.insert(0, os.path.abspath(".")) project = "California Accountability Panel" -copyright = "2025, Open Sacramento" +copyright = "2026, Open Sacramento" author = "Open Sacramento" extensions = [ "sphinx.ext.autodoc", @@ -30,13 +30,13 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "**.ipynb_checkpoints"] html_theme = "pydata_sphinx_theme" html_static_path = ["_static"] -html_favicon = "_static/image/favicon.ico" -html_logo = "_static/image/logo.svg" +html_favicon = "_static/image/favicon/favicon.ico" +html_logo = "_static/image/favicon/favicon.svg" html_show_sourcelink = False html_theme_options = { "use_edit_page_button": True, "navbar_align": "content", - "logo": {"text": "CAPanel Docs"}, + "logo": {"text": "Accountability Panel"}, "navbar_center": ["navbar-nav"], "navbar_end": ["theme-switcher", "navbar-icon-links"], "navbar_persistent": ["search-button"], @@ -45,7 +45,7 @@ "icon_links": [ { "name": "Website", - "url": "https://lbsis.org", + "url": "https://capanel-full-5418848943.us-west1.run.app", "icon": "fas fa-globe", "type": "fontawesome", }, diff --git a/backend/docs/source/developer-guide/all-modules.rst b/backend/docs/source/developer-guide/all-modules.rst index 0c2155f..02e29e9 100644 --- a/backend/docs/source/developer-guide/all-modules.rst +++ b/backend/docs/source/developer-guide/all-modules.rst @@ -75,7 +75,7 @@ Core Data models and CRUD -------------------- -.. automodule:: app.model.models +.. automodule:: app.model.other :members: :undoc-members: :show-inheritance: diff --git a/backend/docs/source/developer-guide/index.rst b/backend/docs/source/developer-guide/index.rst index d3b0e58..5634ac5 100644 --- a/backend/docs/source/developer-guide/index.rst +++ b/backend/docs/source/developer-guide/index.rst @@ -1,3 +1,6 @@ +.. meta:: + :description lang=en: Developing with Pyhon on the California Accountability Panel project. + Developer Guide ================================================================ Learn how to build and run the application locally. @@ -44,3 +47,9 @@ Learn how to build and run the application locally. readme-reference documentation-repository-sync AGENTS + +.. toctree:: + :caption: Explore the API + :maxdepth: 2 + + all-modules diff --git a/backend/docs/source/index.md b/backend/docs/source/index.md index 9734484..fe9b40f 100644 --- a/backend/docs/source/index.md +++ b/backend/docs/source/index.md @@ -14,48 +14,40 @@ A dashboard that displays key school performance metrics. ```{gallery-grid} :grid-columns: 1 2 2 3 -- header: "{fas}`chart-simple;pst-color-primary` Dashboard panel" - content: "View key school performance metrics and California state-wide metrics.\n- View our [website](https://lbsis.org)." -- header: "{fas}`circle-user;pst-color-primary` Who it's for" - content: "For people who want real‑time, personalized performance data.\n- Guardians\n- Schools\n- Educational Policy Makers" - header: "{fas}`gauge-simple-high;pst-color-primary` Metrics" - content: "Metrics are based on student assessment results and other aspects of school performance." + content: "Metrics are based on student assessment results and other aspects of school performance.\n- [California Accountability System](https://www.cde.ca.gov/ta/ac/cm/fivebyfivecolortables.asp)" +- header: "{fas}`circle-user;pst-color-primary` Who it's for" + content: "For people who want to learn more about the California education system.\n- Parents/ Guardians\n- Schools\n- Educational Policy Makers" - header: "{fas}`database;pst-color-primary` Public data" - content: "Uses public data from the [California Department of Education](https://www.cde.ca.gov/)." -- header: "{fas}`file-csv;pst-color-primary` CSV upload" - content: "Use your own data by uploading a CSV file." -- header: "{fas}`lightbulb;pst-color-primary` Contribute" - content: "We welcome contributions! The project is open-source.\n- [GitHub](https://github.com/opensacorg/app-capanel-web)\n- [GitHub docs](https://github.com/opensacorg/app-capanel-doc)" + content: "Uses public data from the [California Department of Education](https://www.cde.ca.gov/ta/ac/cm/dashboardresources.asp).\n\n Inspired by the [California Data Dashboard](https://www.caschooldashboard.org)." ``` -## User guide +## About the project -Information about using the California Accountability Panel website. +This project's goal is to provide a user-friendly interface for exploring key school performance metrics in California. It leverages public data from the California Department of Education and aims to inspire transparency and understanding of the education system. ```{toctree} :maxdepth: 2 -user-guide/index +project/index ``` -## Developer guide +## User guide -Information about developing this application and how you can contribute. +Learn how to use the website and more about the California Accountability System. ```{toctree} :maxdepth: 2 -developer-guide/index +user-guide/index ``` -## API reference +## Developer guide -The application uses FastAPI. You can view the Open API docs at [lbsis.org/docs](https://lbsis.org/docs) or view the -full Python module -reference. +Information about developing this application and how you can contribute. ```{toctree} :maxdepth: 2 -developer-guide/all-modules -``` \ No newline at end of file +developer-guide/index +``` diff --git a/backend/docs/source/project/index.rst b/backend/docs/source/project/index.rst new file mode 100644 index 0000000..0e8dc17 --- /dev/null +++ b/backend/docs/source/project/index.rst @@ -0,0 +1,31 @@ +.. meta:: + :description lang=en: About the the California Accountability Panel project. + +About +================================================================ + +The California Accountability Panel is an open-source project. Contributions are welcome + +Methodology + +The project uses the agile methodology. Take a look at the GitHub discussions to learn about the features and epics that are planned. + +Contribute a user story + +If you have an idea about how the project could improve, please submit a user story. + +Contribute code + +Submit a pull request on GitHub. + +Meetings + +Catch up with us at one of Open Sacramento's weekly Hack Nights. + +Learn how to build and run the application locally. + +.. toctree:: + :caption: Security and privacy + :maxdepth: 2 + + security diff --git a/backend/docs/source/project/security.rst b/backend/docs/source/project/security.rst new file mode 100644 index 0000000..c57f28e --- /dev/null +++ b/backend/docs/source/project/security.rst @@ -0,0 +1,2 @@ +Privacy policy +========== \ No newline at end of file diff --git a/backend/docs/source/user-guide/csv-upload.rst b/backend/docs/source/user-guide/csv-upload.rst index 064fde4..293cc4a 100644 --- a/backend/docs/source/user-guide/csv-upload.rst +++ b/backend/docs/source/user-guide/csv-upload.rst @@ -1,3 +1,671 @@ CSV Upload -================================================================ -Use your own data by uploading a CSV file. \ No newline at end of file +========== + +Use your own data by uploading a CSV file. + +---- + +California Assessment of Student Performance and Progress (CAASPP) +=================================================================== + +The Smarter Balanced Summative Assessments research files contain comprehensive +results from the California Assessment of Student Performance and Progress +(CAASPP) administrations. These files provide the same underlying data as the +public "Detailed Test Results" website but are optimized for complex statistical +analysis, longitudinal studies, and customized reporting. + +.. note:: + + No scores are reported for any group or demographic containing fewer than 11 + students. + +Research files are categorized by their geographic and administrative scope. +Users can download data at the following levels: + +- **Statewide Files.** The entire State of California, including all individual counties, districts, and schools. + +- **County Files.** County and all associated districts and schools within that county's jurisdiction. + +- **District Files.** District and all schools associated with that district. + +.. note:: + + "School only" files are not available for individual download. School-level + data must be extracted from the corresponding District, County, or Statewide + files. + +---- + +Special Entity Handling +----------------------- + +Independent Charter Schools +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Direct-funded independent charter schools are treated as individual districts +within these research files. Consequently, their results are integrated into +the totals for the state, the county in which they reside, and their specific +school-level records. + +---- + +Technical Specifications +------------------------ + +Before performing data analysis, researchers should consult the supplementary +technical documentation to ensure accurate data interpretation. https://caaspp-elpac.ets.org/caaspp/ResearchFileListSB?ps=true&lstTestYear=2025&lstTestType=B&lstCounty=00&lstDistrict=00000#accurate-results + +File Formats and Layouts +~~~~~~~~~~~~~~~~~~~~~~~~ + +Research file structures and data formats may vary between academic years. +Users must refer to the specific Research File Layout for the corresponding +year to map field headers and data types correctly. + +Lookup Tables +~~~~~~~~~~~~~ + +Lookup tables are provided to map numerical codes within the research files to +human-readable labels for: + +- Counties, Districts, and Schools (CDS codes) +- Student Demographic Groups +- Test Subjects and Achievement Levels + + +Research File Schemas +===================== + +2025 Caaspp +===================== + +All research files use caret (``^``) as the field delimiter. + +---- + +Common Fields +------------- + +The following fields appear as the first 16 columns in all research files. + +.. list-table:: + :header-rows: 1 + :widths: 5 30 65 + + * - # + - Field Name + - Notes + * - 1 + - County Code + - + * - 2 + - District Code + - + * - 3 + - District Name + - + * - 4 + - School Code + - + * - 5 + - School Name + - + * - 6 + - Type ID + - + * - 7 + - Filler + - + * - 8 + - Test Year + - + * - 9 + - Test Type + - + * - 10 + - Test ID + - + * - 11 + - Student Group ID + - + * - 12 + - Grade + - + * - 13 + - Total Students Enrolled + - + * - 14 + - Total Students Tested + - + * - 15 + - Total Students Tested with Scores + - + * - 16 + - Mean Scale Score + - + +---- + +File Schemas +------------ + +Smarter Balanced ELA and Math +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Files:** + +- ``sb_ca2025_all_csv_ela_v1.txt`` +- ``sb_ca2025_all_csv_math_v1.txt`` + +Extends the common fields with overall performance levels, four content area +domains, and two composite areas. + +.. list-table:: + :header-rows: 1 + :widths: 5 45 50 + + * - # + - Field Name + - Notes + * - 17 + - Percentage Standard Exceeded + - + * - 18 + - Count Standard Exceeded + - + * - 19 + - Percentage Standard Met + - + * - 20 + - Count Standard Met + - + * - 21 + - Percentage Standard Met and Above + - + * - 22 + - Count Standard Met and Above + - + * - 23 + - Percentage Standard Nearly Met + - + * - 24 + - Count Standard Nearly Met + - + * - 25 + - Percentage Standard Not Met + - + * - 26 + - Count Standard Not Met + - + * - 27 + - Overall Total + - + * - 28–34 + - Area 1 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + * - 35–41 + - Area 2 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + * - 42–48 + - Area 3 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + * - 49–55 + - Area 4 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + * - 56–62 + - Composite Area 1 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + * - 63–69 + - Composite Area 2 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + +---- + +California Alternate Assessments (CAA and CAAS) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Files:** + +- ``caa_ca2025_all_csv_v1.txt`` +- ``caas_ca2025_all_csv_v1.txt`` + +Extends the common fields with three performance levels and an overall total. + +.. list-table:: + :header-rows: 1 + :widths: 5 45 50 + + * - # + - Field Name + - Notes + * - 17 + - Percentage Level 3 + - + * - 18 + - Count Level 3 + - + * - 19 + - Percentage Level 2 + - + * - 20 + - Count Level 2 + - + * - 21 + - Percentage Level 1 + - + * - 22 + - Count Level 1 + - + * - 23 + - Overall Total + - + +---- + +California Science Test (CAST) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**File:** ``cast_ca2025_all_csv_v1.txt`` + +Extends the common fields with overall performance levels and three science +domain breakdowns. + +.. list-table:: + :header-rows: 1 + :widths: 5 50 45 + + * - # + - Field Name + - Notes + * - 17 + - Percentage Standard Exceeded + - + * - 18 + - Count Standard Exceeded + - + * - 19 + - Percentage Standard Met + - + * - 20 + - Count Standard Met + - + * - 21 + - Percentage Standard Met and Above + - + * - 22 + - Count Standard Met and Above + - + * - 23 + - Percentage Standard Nearly Met + - + * - 24 + - Count Standard Nearly Met + - + * - 25 + - Percentage Standard Not Met + - + * - 26 + - Count Standard Not Met + - + * - 27 + - Overall Total + - + * - 28–34 + - Life Sciences Domain — Percent Below Standard, Count Below Standard, Percent Near Standard, Count Near Standard, Percent Above Standard, Count Above Standard, Total + - + * - 35–41 + - Physical Sciences Domain — Percent Below Standard, Count Below Standard, Percent Near Standard, Count Near Standard, Percent Above Standard, Count Above Standard, Total + - + * - 42–48 + - Earth and Space Sciences Domain — Percent Below Standard, Count Below Standard, Percent Near Standard, Count Near Standard, Percent Above Standard, Count Above Standard, Total + - + +---- + +California Spanish Assessment (CSA) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**File:** ``csa_ca2025_all_csv_v1.txt`` + +.. note:: + + The 2025 CSA schema differs significantly from 2024. Field 16 is renamed + ``Overall Mean Scale Score``. Overall performance uses Level 1–3 terminology + (replacing Range 1–3). Four language domains and two composites with + independent mean scale scores are added. + +Extends the common fields with overall performance levels, four language +domain breakdowns, and two composite scores. + +.. list-table:: + :header-rows: 1 + :widths: 5 50 45 + + * - # + - Field Name + - Notes + * - 16 + - Overall Mean Scale Score + - Renamed from ``Mean Scale Score`` in 2024 + * - 17 + - Percent Level 3 + - + * - 18 + - Count Level 3 + - + * - 19 + - Percent Level 2 + - + * - 20 + - Count Level 2 + - + * - 21 + - Percent Level 1 + - + * - 22 + - Count Level 1 + - + * - 23 + - Overall Total + - + * - 24–30 + - Listening Domain — Percent Level 1, Count Level 1, Percent Level 2, Count Level 2, Percent Level 3, Count Level 3, Total + - + * - 31–37 + - Writing Domain — Percent Level 1, Count Level 1, Percent Level 2, Count Level 2, Percent Level 3, Count Level 3, Total + - + * - 38–44 + - Reading Domain — Percent Level 1, Count Level 1, Percent Level 2, Count Level 2, Percent Level 3, Count Level 3, Total + - + * - 45–51 + - Speaking Domain — Percent Level 1, Count Level 1, Percent Level 2, Count Level 2, Percent Level 3, Count Level 3, Total + - + * - 52–59 + - Composite 1 — Mean Scale Score, Percent Level 1, Count Level 1, Percent Level 2, Count Level 2, Percent Level 3, Count Level 3, Total + - + * - 60–67 + - Composite 2 — Mean Scale Score, Percent Level 1, Count Level 1, Percent Level 2, Count Level 2, Percent Level 3, Count Level 3, Total + - + + +2024 Caaspp +===================== + +All research files use caret (``^``) as the field delimiter. + +---- + +Common Fields +------------- + +The following fields appear as the first 16 columns in all research files. + +.. list-table:: + :header-rows: 1 + :widths: 5 30 65 + + * - # + - Field Name + - Notes + * - 1 + - County Code + - + * - 2 + - District Code + - + * - 3 + - District Name + - + * - 4 + - School Code + - + * - 5 + - School Name + - + * - 6 + - Type ID + - + * - 7 + - Filler + - + * - 8 + - Test Year + - + * - 9 + - Test Type + - + * - 10 + - Test ID + - + * - 11 + - Student Group ID + - + * - 12 + - Grade + - + * - 13 + - Total Students Enrolled + - + * - 14 + - Total Students Tested + - + * - 15 + - Total Students Tested with Scores + - + * - 16 + - Mean Scale Score + - + +---- + +File Schemas +------------ + +Smarter Balanced ELA and Math +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Files:** + +- ``sb_ca2024_all_csv_ela_v1.txt`` +- ``sb_ca2024_all_csv_math_v1.txt`` + +Extends the common fields with overall performance levels, four content area +domains, and two composite areas. + +.. list-table:: + :header-rows: 1 + :widths: 5 45 50 + + * - # + - Field Name + - Notes + * - 17 + - Percentage Standard Exceeded + - + * - 18 + - Count Standard Exceeded + - + * - 19 + - Percentage Standard Met + - + * - 20 + - Count Standard Met + - + * - 21 + - Percentage Standard Met and Above + - + * - 22 + - Count Standard Met and Above + - + * - 23 + - Percentage Standard Nearly Met + - + * - 24 + - Count Standard Nearly Met + - + * - 25 + - Percentage Standard Not Met + - + * - 26 + - Count Standard Not Met + - + * - 27 + - Overall Total + - + * - 28–34 + - Area 1 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + * - 35–41 + - Area 2 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + * - 42–48 + - Area 3 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + * - 49–55 + - Area 4 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + * - 56–62 + - Composite Area 1 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + * - 63–69 + - Composite Area 2 — Percentage Above Standard, Count Above Standard, Percentage Near Standard, Count Near Standard, Percentage Below Standard, Count Below Standard, Total + - + +---- + +California Alternate Assessments (CAA and CAAS) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Files:** + +- ``caa_ca2024_all_csv_v1.txt`` +- ``caas_ca2024_all_csv_v1.txt`` + +Extends the common fields with three performance levels and an overall total. + +.. list-table:: + :header-rows: 1 + :widths: 5 45 50 + + * - # + - Field Name + - Notes + * - 17 + - Percentage Level 3 + - + * - 18 + - Count Level 3 + - + * - 19 + - Percentage Level 2 + - + * - 20 + - Count Level 2 + - + * - 21 + - Percentage Level 1 + - + * - 22 + - Count Level 1 + - + * - 23 + - Overall Total + - + +---- + +California Science Test (CAST) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**File:** ``cast_ca2024_all_csv_v1.txt`` + +Extends the common fields with overall performance levels and three science +domain breakdowns. + +.. list-table:: + :header-rows: 1 + :widths: 5 50 45 + + * - # + - Field Name + - Notes + * - 17 + - Percentage Standard Exceeded + - + * - 18 + - Count Standard Exceeded + - + * - 19 + - Percentage Standard Met + - + * - 20 + - Count Standard Met + - + * - 21 + - Percentage Standard Met and Above + - + * - 22 + - Count Standard Met and Above + - + * - 23 + - Percentage Standard Nearly Met + - + * - 24 + - Count Standard Nearly Met + - + * - 25 + - Percentage Standard Not Met + - + * - 26 + - Count Standard Not Met + - + * - 27 + - Overall Total + - + * - 28–34 + - Life Sciences Domain — Percent Below Standard, Count Below Standard, Percent Near Standard, Count Near Standard, Percent Above Standard, Count Above Standard, Total + - + * - 35–41 + - Physical Sciences Domain — Percent Below Standard, Count Below Standard, Percent Near Standard, Count Near Standard, Percent Above Standard, Count Above Standard, Total + - + * - 42–48 + - Earth and Space Sciences Domain — Percent Below Standard, Count Below Standard, Percent Near Standard, Count Near Standard, Percent Above Standard, Count Above Standard, Total + - + +---- + +California Spanish Assessment (CSA) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**File:** ``csa_ca2024_all_csv_v1.txt`` + +Extends the common fields with three performance ranges and an overall total. + +.. list-table:: + :header-rows: 1 + :widths: 5 45 50 + + * - # + - Field Name + - Notes + * - 17 + - Percent Range 3 + - + * - 18 + - Count Range 3 + - + * - 19 + - Percent Range 2 + - + * - 20 + - Count Range 2 + - + * - 21 + - Percent Range 1 + - + * - 22 + - Count Range 1 + - + * - 23 + - Overall Total + - diff --git a/backend/docs/source/user-guide/get-started.rst b/backend/docs/source/user-guide/get-started.rst index af91f69..37ac062 100644 --- a/backend/docs/source/user-guide/get-started.rst +++ b/backend/docs/source/user-guide/get-started.rst @@ -4,20 +4,18 @@ Overview The California Accountability Panel is an open-source project. Contributions are welcome Methodology -------------- + The project uses the agile methodology. Take a look at the GitHub discussions to learn about the features and epics that are planned. Contribute a user story -------------- If you have an idea about how the project could improve, please submit a user story. Contribute code -------------- Submit a pull request on GitHub. Meetings -------------- + Catch up with us at one of Open Sacramento's weekly Hack Nights. diff --git a/backend/docs/source/user-guide/index.rst b/backend/docs/source/user-guide/index.rst index 6f67eba..50c6e0d 100644 --- a/backend/docs/source/user-guide/index.rst +++ b/backend/docs/source/user-guide/index.rst @@ -4,7 +4,7 @@ Get Started ================================================================ -A dashboard that displays key school performance metrics. View our `website `_. +A dashboard that displays key school performance metrics. View our `website `_. For people who want real‑time, personalized performance data - Guardians @@ -19,6 +19,7 @@ Open source :caption: Get started :maxdepth: 2 + about get-started .. toctree:: diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 9cb517b..d821311 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -2,27 +2,25 @@ name = "app" version = "1.0.1" description = "Sphinx documentation for the California Accountability Panel website." -requires-python = ">=3.10,<4.0" +requires-python = ">=3.14,<4.0" dependencies = [ - "fastapi[standard]<1.0.0,>=0.114.2", - "python-multipart<1.0.0,>=0.0.7", - "email-validator<3.0.0.0,>=2.1.0.post1", - "tenacity<9.0.0,>=8.2.3", - "pydantic>2.0", - "emails<1.0,>=0.6", - "jinja2<4.0.0,>=3.1.4", - "alembic<2.0.0,>=1.12.1", - "httpx<1.0.0,>=0.25.1", - "psycopg[binary]<4.0.0,>=3.1.13", - "sqlmodel<1.0.0,>=0.0.21", - "pydantic-settings<3.0.0,>=2.2.1", - "sentry-sdk[fastapi]<2.0.0,>=1.40.6", - "pyjwt<3.0.0,>=2.8.0", - "pwdlib[argon2,bcrypt]>=0.3.0", - "pandas>=2.3.3", - "openpyxl>=3.1.5", - "chardet<6.0.0,>=3.0.2", - "google-auth>=2.0.0", + "python-multipart", + "email-validator", + "tenacity", + "pydantic", + "emails", + "jinja2", + "alembic", + "httpx", + "psycopg[binary]", + "sqlmodel", + "pydantic-settings", + "pyjwt", + "pwdlib[argon2,bcrypt]", + "pandas", + "openpyxl", + "chardet", + "google-auth", "sphinx", "sphinx-autodoc-typehints", "sphinx-autobuild", @@ -31,28 +29,25 @@ dependencies = [ "types-docutils", "myst-parser", "sphinx-design", - "sphinxcontrib-mermaid>=1.0.0", + "sphinxcontrib-mermaid", + "fastapi[standard-no-fastapi-cloud-cli]", ] [dependency-groups] dev = [ - "pytest<8.0.0,>=7.4.3", - "mypy<2.0.0,>=1.8.0", - "ruff<1.0.0,>=0.2.2", - "prek>=0.2.24,<1.0.0", - "coverage<8.0.0,>=7.4.3", + "pytest", + "ruff", + "prek", + "coverage", + "ty", ] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" -[tool.mypy] -strict = true -exclude = ["venv", ".venv", "alembic"] - [tool.ruff] -target-version = "py310" +target-version = "py314" exclude = ["alembic"] [tool.ruff.lint] @@ -65,7 +60,6 @@ select = [ "C4", # flake8-comprehensions "UP", # pyupgrade "ARG001", # unused arguments in functions - "T201", # print statements are not allowed ] ignore = [ "E501", # line too long, handled by black @@ -89,3 +83,6 @@ sort = "-Cover" [tool.coverage.html] show_contexts = true + +[tool.ty.terminal] +error-on-warning = true diff --git a/backend/tests/api/routes/test_dashboard.py b/backend/tests/api/routes/test_dashboard.py new file mode 100644 index 0000000..2b05bfe --- /dev/null +++ b/backend/tests/api/routes/test_dashboard.py @@ -0,0 +1,62 @@ +from decimal import Decimal + +from fastapi.testclient import TestClient +from sqlmodel import Session + +from app.core.config import settings +from app.model.assessments import CaasppStudentGroup, CaasppTest, Entity, SbResult + + +def test_dashboard_summary_normalizes_all_students_and_preserves_zero_values( + client: TestClient, db: Session +) -> None: + cds_code = "99999999999999" + + db.merge( + Entity( + cds_code=cds_code, + school_name="Dashboard Test School", + ) + ) + db.merge( + CaasppStudentGroup( + demographic_id="1", + demographic_id_num=1, + student_group="All Students", + ) + ) + db.merge(CaasppTest(test_id=1, test_name="ELA")) + db.add( + SbResult( + cds_code=cds_code, + test_year=2025, + student_group_id="1", + test_id=1, + grade="03", + total_students_enrolled=10, + total_students_tested=0, + mean_scale_score=Decimal("0.0"), + percentage_standard_not_met=Decimal("0.0"), + percentage_standard_nearly_met=Decimal("0.0"), + percentage_standard_met=Decimal("0.0"), + percentage_standard_exceeded=Decimal("0.0"), + percentage_standard_met_and_above=Decimal("0.0"), + ) + ) + db.commit() + + response = client.get( + f"{settings.API_V1_STR}/dashboard/summary", + params={"cds": cds_code, "reportingYear": "2025", "studentGroup": "ALL"}, + ) + + assert response.status_code == 200 + content = response.json() + assert content["cds"] == cds_code + assert len(content["indicators"]) == 1 + + indicator = content["indicators"][0] + assert indicator["studentsTested"] == "0" + assert indicator["overallMeanScaleScore"] == "0.0" + assert Decimal(indicator["overallMetAndAbovePct"]) == Decimal("0") + assert indicator["levels"]["Standard Not Met (Level 1)"] == 0.0 diff --git a/backend/tests/api/routes/test_items.py b/backend/tests/api/routes/test_items.py index 3e82cd0..c6a9522 100644 --- a/backend/tests/api/routes/test_items.py +++ b/backend/tests/api/routes/test_items.py @@ -21,7 +21,7 @@ def test_create_item( assert content["title"] == data["title"] assert content["description"] == data["description"] assert "id" in content - assert "owner_id" in content + assert "ownerId" in content def test_read_item( @@ -37,7 +37,7 @@ def test_read_item( assert content["title"] == item.title assert content["description"] == item.description assert content["id"] == str(item.id) - assert content["owner_id"] == str(item.owner_id) + assert content["ownerId"] == str(item.owner_id) def test_read_item_not_found( @@ -94,7 +94,7 @@ def test_update_item( assert content["title"] == data["title"] assert content["description"] == data["description"] assert content["id"] == str(item.id) - assert content["owner_id"] == str(item.owner_id) + assert content["ownerId"] == str(item.owner_id) def test_update_item_not_found( diff --git a/backend/tests/api/routes/test_login.py b/backend/tests/api/routes/test_login.py index 3481d1c..f3f6ee0 100644 --- a/backend/tests/api/routes/test_login.py +++ b/backend/tests/api/routes/test_login.py @@ -21,8 +21,8 @@ def test_get_access_token(client: TestClient) -> None: r = client.post(f"{settings.API_V1_STR}/login/access-token", data=login_data) tokens = r.json() assert r.status_code == 200 - assert "access_token" in tokens - assert tokens["access_token"] + assert "accessToken" in tokens + assert tokens["accessToken"] def test_get_access_token_incorrect_password(client: TestClient) -> None: @@ -189,7 +189,7 @@ def test_login_with_bcrypt_password_upgrades_to_argon2( r = client.post(f"{settings.API_V1_STR}/login/access-token", data=login_data) assert r.status_code == 200 tokens = r.json() - assert "access_token" in tokens + assert "accessToken" in tokens db.refresh(user) @@ -223,7 +223,7 @@ def test_login_with_argon2_password_keeps_hash(client: TestClient, db: Session) r = client.post(f"{settings.API_V1_STR}/login/access-token", data=login_data) assert r.status_code == 200 tokens = r.json() - assert "access_token" in tokens + assert "accessToken" in tokens db.refresh(user) diff --git a/backend/tests/api/routes/test_users.py b/backend/tests/api/routes/test_users.py index 9eab204..835d3a9 100644 --- a/backend/tests/api/routes/test_users.py +++ b/backend/tests/api/routes/test_users.py @@ -18,8 +18,8 @@ def test_get_users_superuser_me( r = client.get(f"{settings.API_V1_STR}/users/me", headers=superuser_token_headers) current_user = r.json() assert current_user - assert current_user["is_active"] is True - assert current_user["is_superuser"] + assert current_user["isActive"] is True + assert current_user["isSuperuser"] assert current_user["email"] == settings.FIRST_SUPERUSER @@ -29,8 +29,8 @@ def test_get_users_normal_user_me( r = client.get(f"{settings.API_V1_STR}/users/me", headers=normal_user_token_headers) current_user = r.json() assert current_user - assert current_user["is_active"] is True - assert current_user["is_superuser"] is False + assert current_user["isActive"] is True + assert current_user["isSuperuser"] is False assert current_user["email"] == settings.EMAIL_TEST_USER @@ -100,7 +100,7 @@ def test_get_existing_user_current_user(client: TestClient, db: Session) -> None } r = client.post(f"{settings.API_V1_STR}/login/access-token", data=login_data) tokens = r.json() - a_token = tokens["access_token"] + a_token = tokens["accessToken"] headers = {"Authorization": f"Bearer {a_token}"} r = client.get( @@ -212,7 +212,7 @@ def test_update_user_me( assert r.status_code == 200 updated_user = r.json() assert updated_user["email"] == email - assert updated_user["full_name"] == full_name + assert updated_user["fullName"] == full_name user_query = select(User).where(User.email == email) user_db = db.exec(user_query).first() @@ -335,7 +335,7 @@ def test_register_user(client: TestClient, db: Session) -> None: assert r.status_code == 200 created_user = r.json() assert created_user["email"] == username - assert created_user["full_name"] == full_name + assert created_user["fullName"] == full_name user_query = select(User).where(User.email == username) user_db = db.exec(user_query).first() @@ -379,7 +379,7 @@ def test_update_user( assert r.status_code == 200 updated_user = r.json() - assert updated_user["full_name"] == "Updated_full_name" + assert updated_user["fullName"] == "Updated_full_name" user_query = select(User).where(User.email == username) user_db = db.exec(user_query).first() @@ -437,7 +437,7 @@ def test_delete_user_me(client: TestClient, db: Session) -> None: } r = client.post(f"{settings.API_V1_STR}/login/access-token", data=login_data) tokens = r.json() - a_token = tokens["access_token"] + a_token = tokens["accessToken"] headers = {"Authorization": f"Bearer {a_token}"} r = client.delete( @@ -451,7 +451,7 @@ def test_delete_user_me(client: TestClient, db: Session) -> None: assert result is None user_query = select(User).where(User.id == user_id) - user_db = db.execute(user_query).first() + user_db = db.exec(user_query).first() assert user_db is None diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index 832651b..54b650e 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -14,19 +14,19 @@ @pytest.fixture(scope="session", autouse=True) -def db() -> Generator[Session, None, None]: +def db() -> Generator[Session]: with Session(engine) as session: init_db(session) yield session statement = delete(Item) - session.execute(statement) + session.exec(statement) statement = delete(User) - session.execute(statement) + session.exec(statement) session.commit() @pytest.fixture(scope="module") -def client() -> Generator[TestClient, None, None]: +def client() -> Generator[TestClient]: with TestClient(app) as c: yield c diff --git a/backend/tests/scripts/tests_pre_start.py b/backend/tests/scripts/tests_pre_start.py index 5b4fee0..05ad166 100644 --- a/backend/tests/scripts/tests_pre_start.py +++ b/backend/tests/scripts/tests_pre_start.py @@ -5,7 +5,7 @@ from tenacity import after_log, before_log, retry, stop_after_attempt, wait_fixed from app.core.database import engine -from app.scripts.gcp.gcp_utils import load_repo_env_if_present +from app.scripts.gcp_utils import load_repo_env_if_present load_repo_env_if_present(__file__, scope="tests_pre_start") diff --git a/backend/tests/utils/user.py b/backend/tests/utils/user.py index 6d741d4..c895b7c 100644 --- a/backend/tests/utils/user.py +++ b/backend/tests/utils/user.py @@ -14,7 +14,7 @@ def user_authentication_headers( r = client.post(f"{settings.API_V1_STR}/login/access-token", data=data) response = r.json() - auth_token = response["access_token"] + auth_token = response["accessToken"] headers = {"Authorization": f"Bearer {auth_token}"} return headers diff --git a/backend/tests/utils/utils.py b/backend/tests/utils/utils.py index 184bac4..57aa8a5 100644 --- a/backend/tests/utils/utils.py +++ b/backend/tests/utils/utils.py @@ -21,6 +21,6 @@ def get_superuser_token_headers(client: TestClient) -> dict[str, str]: } r = client.post(f"{settings.API_V1_STR}/login/access-token", data=login_data) tokens = r.json() - a_token = tokens["access_token"] + a_token = tokens["accessToken"] headers = {"Authorization": f"Bearer {a_token}"} return headers diff --git a/backend/uv.lock b/backend/uv.lock index e3467a8..c3edcdf 100644 --- a/backend/uv.lock +++ b/backend/uv.lock @@ -1,20 +1,10 @@ version = 1 revision = 3 -requires-python = ">=3.10, <4.0" +requires-python = ">=3.14, <4.0" resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.11'", + "sys_platform == 'win32'", + "sys_platform == 'emscripten'", + "sys_platform != 'emscripten' and sys_platform != 'win32'", ] [[package]] @@ -45,7 +35,6 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mako" }, { name = "sqlalchemy" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/94/13/8b084e0f2efb0275a1d534838844926f798bd766566b1375174e2448cd31/alembic-1.18.4.tar.gz", hash = "sha256:cb6e1fd84b6174ab8dbb2329f86d631ba9559dd78df550b57804d607672cedbc", size = 2056725, upload-time = "2026-02-10T16:00:47.195Z" } @@ -73,16 +62,14 @@ wheels = [ [[package]] name = "anyio" -version = "4.12.1" +version = "4.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, + { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, ] [[package]] @@ -95,15 +82,13 @@ dependencies = [ { name = "docutils-stubs" }, { name = "email-validator" }, { name = "emails" }, - { name = "fastapi", extra = ["standard"] }, + { name = "fastapi", extra = ["standard-no-fastapi-cloud-cli"] }, { name = "google-auth" }, { name = "httpx" }, { name = "jinja2" }, - { name = "myst-parser", version = "4.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "myst-parser", version = "5.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "myst-parser" }, { name = "openpyxl" }, - { name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "pandas", version = "3.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pandas" }, { name = "psycopg", extra = ["binary"] }, { name = "pwdlib", extra = ["argon2", "bcrypt"] }, { name = "pydantic" }, @@ -111,17 +96,10 @@ dependencies = [ { name = "pydata-sphinx-theme" }, { name = "pyjwt" }, { name = "python-multipart" }, - { name = "sentry-sdk", extra = ["fastapi"] }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, - { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "sphinx-autobuild", version = "2024.10.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx-autobuild", version = "2025.8.25", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "sphinx-autodoc-typehints", version = "3.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx-autodoc-typehints", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, - { name = "sphinx-autodoc-typehints", version = "3.9.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "sphinx-design", version = "0.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx-design", version = "0.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx" }, + { name = "sphinx-autobuild" }, + { name = "sphinx-autodoc-typehints" }, + { name = "sphinx-design" }, { name = "sphinxcontrib-mermaid" }, { name = "sqlmodel" }, { name = "tenacity" }, @@ -131,51 +109,50 @@ dependencies = [ [package.dev-dependencies] dev = [ { name = "coverage" }, - { name = "mypy" }, { name = "prek" }, { name = "pytest" }, { name = "ruff" }, + { name = "ty" }, ] [package.metadata] requires-dist = [ - { name = "alembic", specifier = ">=1.12.1,<2.0.0" }, - { name = "chardet", specifier = ">=3.0.2,<6.0.0" }, + { name = "alembic" }, + { name = "chardet" }, { name = "docutils-stubs" }, - { name = "email-validator", specifier = ">=2.1.0.post1,<3.0.0.0" }, - { name = "emails", specifier = ">=0.6,<1.0" }, - { name = "fastapi", extras = ["standard"], specifier = ">=0.114.2,<1.0.0" }, - { name = "google-auth", specifier = ">=2.0.0" }, - { name = "httpx", specifier = ">=0.25.1,<1.0.0" }, - { name = "jinja2", specifier = ">=3.1.4,<4.0.0" }, + { name = "email-validator" }, + { name = "emails" }, + { name = "fastapi", extras = ["standard-no-fastapi-cloud-cli"] }, + { name = "google-auth" }, + { name = "httpx" }, + { name = "jinja2" }, { name = "myst-parser" }, - { name = "openpyxl", specifier = ">=3.1.5" }, - { name = "pandas", specifier = ">=2.3.3" }, - { name = "psycopg", extras = ["binary"], specifier = ">=3.1.13,<4.0.0" }, - { name = "pwdlib", extras = ["argon2", "bcrypt"], specifier = ">=0.3.0" }, - { name = "pydantic", specifier = ">2.0" }, - { name = "pydantic-settings", specifier = ">=2.2.1,<3.0.0" }, + { name = "openpyxl" }, + { name = "pandas" }, + { name = "psycopg", extras = ["binary"] }, + { name = "pwdlib", extras = ["argon2", "bcrypt"] }, + { name = "pydantic" }, + { name = "pydantic-settings" }, { name = "pydata-sphinx-theme" }, - { name = "pyjwt", specifier = ">=2.8.0,<3.0.0" }, - { name = "python-multipart", specifier = ">=0.0.7,<1.0.0" }, - { name = "sentry-sdk", extras = ["fastapi"], specifier = ">=1.40.6,<2.0.0" }, + { name = "pyjwt" }, + { name = "python-multipart" }, { name = "sphinx" }, { name = "sphinx-autobuild" }, { name = "sphinx-autodoc-typehints" }, { name = "sphinx-design" }, - { name = "sphinxcontrib-mermaid", specifier = ">=1.0.0" }, - { name = "sqlmodel", specifier = ">=0.0.21,<1.0.0" }, - { name = "tenacity", specifier = ">=8.2.3,<9.0.0" }, + { name = "sphinxcontrib-mermaid" }, + { name = "sqlmodel" }, + { name = "tenacity" }, { name = "types-docutils" }, ] [package.metadata.requires-dev] dev = [ - { name = "coverage", specifier = ">=7.4.3,<8.0.0" }, - { name = "mypy", specifier = ">=1.8.0,<2.0.0" }, - { name = "prek", specifier = ">=0.2.24,<1.0.0" }, - { name = "pytest", specifier = ">=7.4.3,<8.0.0" }, - { name = "ruff", specifier = ">=0.2.2,<1.0.0" }, + { name = "coverage" }, + { name = "prek" }, + { name = "pytest" }, + { name = "ruff" }, + { name = "ty" }, ] [[package]] @@ -219,11 +196,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, - { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549, upload-time = "2025-07-30T10:02:00.101Z" }, - { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539, upload-time = "2025-07-30T10:02:00.929Z" }, - { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467, upload-time = "2025-07-30T10:02:02.08Z" }, - { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355, upload-time = "2025-07-30T10:02:02.867Z" }, - { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187, upload-time = "2025-07-30T10:02:03.674Z" }, ] [[package]] @@ -241,21 +213,6 @@ version = "5.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d4/36/3329e2518d70ad8e2e5817d5a4cac6bba05a47767ec416c7d020a965f408/bcrypt-5.0.0.tar.gz", hash = "sha256:f748f7c2d6fd375cc93d3fba7ef4a9e3a092421b8dbf34d8d4dc06be9492dfdd", size = 25386, upload-time = "2025-09-25T19:50:47.829Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/85/3e65e01985fddf25b64ca67275bb5bdb4040bd1a53b66d355c6c37c8a680/bcrypt-5.0.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f3c08197f3039bec79cee59a606d62b96b16669cff3949f21e74796b6e3cd2be", size = 481806, upload-time = "2025-09-25T19:49:05.102Z" }, - { url = "https://files.pythonhosted.org/packages/44/dc/01eb79f12b177017a726cbf78330eb0eb442fae0e7b3dfd84ea2849552f3/bcrypt-5.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:200af71bc25f22006f4069060c88ed36f8aa4ff7f53e67ff04d2ab3f1e79a5b2", size = 268626, upload-time = "2025-09-25T19:49:06.723Z" }, - { url = "https://files.pythonhosted.org/packages/8c/cf/e82388ad5959c40d6afd94fb4743cc077129d45b952d46bdc3180310e2df/bcrypt-5.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:baade0a5657654c2984468efb7d6c110db87ea63ef5a4b54732e7e337253e44f", size = 271853, upload-time = "2025-09-25T19:49:08.028Z" }, - { url = "https://files.pythonhosted.org/packages/ec/86/7134b9dae7cf0efa85671651341f6afa695857fae172615e960fb6a466fa/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c58b56cdfb03202b3bcc9fd8daee8e8e9b6d7e3163aa97c631dfcfcc24d36c86", size = 269793, upload-time = "2025-09-25T19:49:09.727Z" }, - { url = "https://files.pythonhosted.org/packages/cc/82/6296688ac1b9e503d034e7d0614d56e80c5d1a08402ff856a4549cb59207/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4bfd2a34de661f34d0bda43c3e4e79df586e4716ef401fe31ea39d69d581ef23", size = 289930, upload-time = "2025-09-25T19:49:11.204Z" }, - { url = "https://files.pythonhosted.org/packages/d1/18/884a44aa47f2a3b88dd09bc05a1e40b57878ecd111d17e5bba6f09f8bb77/bcrypt-5.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ed2e1365e31fc73f1825fa830f1c8f8917ca1b3ca6185773b349c20fd606cec2", size = 272194, upload-time = "2025-09-25T19:49:12.524Z" }, - { url = "https://files.pythonhosted.org/packages/0e/8f/371a3ab33c6982070b674f1788e05b656cfbf5685894acbfef0c65483a59/bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:83e787d7a84dbbfba6f250dd7a5efd689e935f03dd83b0f919d39349e1f23f83", size = 269381, upload-time = "2025-09-25T19:49:14.308Z" }, - { url = "https://files.pythonhosted.org/packages/b1/34/7e4e6abb7a8778db6422e88b1f06eb07c47682313997ee8a8f9352e5a6f1/bcrypt-5.0.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:137c5156524328a24b9fac1cb5db0ba618bc97d11970b39184c1d87dc4bf1746", size = 271750, upload-time = "2025-09-25T19:49:15.584Z" }, - { url = "https://files.pythonhosted.org/packages/c0/1b/54f416be2499bd72123c70d98d36c6cd61a4e33d9b89562c22481c81bb30/bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:38cac74101777a6a7d3b3e3cfefa57089b5ada650dce2baf0cbdd9d65db22a9e", size = 303757, upload-time = "2025-09-25T19:49:17.244Z" }, - { url = "https://files.pythonhosted.org/packages/13/62/062c24c7bcf9d2826a1a843d0d605c65a755bc98002923d01fd61270705a/bcrypt-5.0.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:d8d65b564ec849643d9f7ea05c6d9f0cd7ca23bdd4ac0c2dbef1104ab504543d", size = 306740, upload-time = "2025-09-25T19:49:18.693Z" }, - { url = "https://files.pythonhosted.org/packages/d5/c8/1fdbfc8c0f20875b6b4020f3c7dc447b8de60aa0be5faaf009d24242aec9/bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:741449132f64b3524e95cd30e5cd3343006ce146088f074f31ab26b94e6c75ba", size = 334197, upload-time = "2025-09-25T19:49:20.523Z" }, - { url = "https://files.pythonhosted.org/packages/a6/c1/8b84545382d75bef226fbc6588af0f7b7d095f7cd6a670b42a86243183cd/bcrypt-5.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:212139484ab3207b1f0c00633d3be92fef3c5f0af17cad155679d03ff2ee1e41", size = 352974, upload-time = "2025-09-25T19:49:22.254Z" }, - { url = "https://files.pythonhosted.org/packages/10/a6/ffb49d4254ed085e62e3e5dd05982b4393e32fe1e49bb1130186617c29cd/bcrypt-5.0.0-cp313-cp313t-win32.whl", hash = "sha256:9d52ed507c2488eddd6a95bccee4e808d3234fa78dd370e24bac65a21212b861", size = 148498, upload-time = "2025-09-25T19:49:24.134Z" }, - { url = "https://files.pythonhosted.org/packages/48/a9/259559edc85258b6d5fc5471a62a3299a6aa37a6611a169756bf4689323c/bcrypt-5.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f6984a24db30548fd39a44360532898c33528b74aedf81c26cf29c51ee47057e", size = 145853, upload-time = "2025-09-25T19:49:25.702Z" }, - { url = "https://files.pythonhosted.org/packages/2d/df/9714173403c7e8b245acf8e4be8876aac64a209d1b392af457c79e60492e/bcrypt-5.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9fffdb387abe6aa775af36ef16f55e318dcda4194ddbf82007a6f21da29de8f5", size = 139626, upload-time = "2025-09-25T19:49:26.928Z" }, { url = "https://files.pythonhosted.org/packages/f8/14/c18006f91816606a4abe294ccc5d1e6f0e42304df5a33710e9e8e95416e1/bcrypt-5.0.0-cp314-cp314t-macosx_10_12_universal2.whl", hash = "sha256:4870a52610537037adb382444fefd3706d96d663ac44cbb2f37e3919dca3d7ef", size = 481862, upload-time = "2025-09-25T19:49:28.365Z" }, { url = "https://files.pythonhosted.org/packages/67/49/dd074d831f00e589537e07a0725cf0e220d1f0d5d8e85ad5bbff251c45aa/bcrypt-5.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48f753100931605686f74e27a7b49238122aa761a9aefe9373265b8b7aa43ea4", size = 268544, upload-time = "2025-09-25T19:49:30.39Z" }, { url = "https://files.pythonhosted.org/packages/f5/91/50ccba088b8c474545b034a1424d05195d9fcbaaf802ab8bfe2be5a4e0d7/bcrypt-5.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f70aadb7a809305226daedf75d90379c397b094755a710d7014b8b117df1ebbf", size = 271787, upload-time = "2025-09-25T19:49:32.144Z" }, @@ -299,10 +256,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c0/f6/688d2cd64bfd0b14d805ddb8a565e11ca1fb0fd6817175d58b10052b6d88/bcrypt-5.0.0-cp39-abi3-win32.whl", hash = "sha256:64d7ce196203e468c457c37ec22390f1a61c85c6f0b8160fd752940ccfb3a683", size = 153725, upload-time = "2025-09-25T19:50:34.384Z" }, { url = "https://files.pythonhosted.org/packages/9f/b9/9d9a641194a730bda138b3dfe53f584d61c58cd5230e37566e83ec2ffa0d/bcrypt-5.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:64ee8434b0da054d830fa8e89e1c8bf30061d539044a39524ff7dec90481e5c2", size = 150912, upload-time = "2025-09-25T19:50:35.69Z" }, { url = "https://files.pythonhosted.org/packages/27/44/d2ef5e87509158ad2187f4dd0852df80695bb1ee0cfe0a684727b01a69e0/bcrypt-5.0.0-cp39-abi3-win_arm64.whl", hash = "sha256:f2347d3534e76bf50bca5500989d6c1d05ed64b440408057a37673282c654927", size = 144953, upload-time = "2025-09-25T19:50:37.32Z" }, - { url = "https://files.pythonhosted.org/packages/8a/75/4aa9f5a4d40d762892066ba1046000b329c7cd58e888a6db878019b282dc/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7edda91d5ab52b15636d9c30da87d2cc84f426c72b9dba7a9b4fe142ba11f534", size = 271180, upload-time = "2025-09-25T19:50:38.575Z" }, - { url = "https://files.pythonhosted.org/packages/54/79/875f9558179573d40a9cc743038ac2bf67dfb79cecb1e8b5d70e88c94c3d/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:046ad6db88edb3c5ece4369af997938fb1c19d6a699b9c1b27b0db432faae4c4", size = 273791, upload-time = "2025-09-25T19:50:39.913Z" }, - { url = "https://files.pythonhosted.org/packages/bc/fe/975adb8c216174bf70fc17535f75e85ac06ed5252ea077be10d9cff5ce24/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:dcd58e2b3a908b5ecc9b9df2f0085592506ac2d5110786018ee5e160f28e0911", size = 270746, upload-time = "2025-09-25T19:50:43.306Z" }, - { url = "https://files.pythonhosted.org/packages/e4/f8/972c96f5a2b6c4b3deca57009d93e946bbdbe2241dca9806d502f29dd3ee/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:6b8f520b61e8781efee73cba14e3e8c9556ccfb375623f4f97429544734545b4", size = 273375, upload-time = "2025-09-25T19:50:45.43Z" }, ] [[package]] @@ -318,15 +271,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, ] -[[package]] -name = "cachetools" -version = "7.0.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/dd/57fe3fdb6e65b25a5987fd2cdc7e22db0aef508b91634d2e57d22928d41b/cachetools-7.0.5.tar.gz", hash = "sha256:0cd042c24377200c1dcd225f8b7b12b0ca53cc2c961b43757e774ebe190fd990", size = 37367, upload-time = "2026-03-09T20:51:29.451Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/06/f3/39cf3367b8107baa44f861dc802cbf16263c945b62d8265d36034fc07bea/cachetools-7.0.5-py3-none-any.whl", hash = "sha256:46bc8ebefbe485407621d0a4264b23c080cedd913921bad7ac3ed2f26c183114", size = 13918, upload-time = "2026-03-09T20:51:27.33Z" }, -] - [[package]] name = "certifi" version = "2026.2.25" @@ -345,55 +289,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, - { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, - { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, - { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, - { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, - { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, - { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, - { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, - { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, - { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, - { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, - { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, - { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, - { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, - { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, - { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, - { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, - { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, - { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, - { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, - { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, - { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, - { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, - { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, - { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, - { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, - { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, - { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, - { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, - { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, - { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, - { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, - { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, - { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, - { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, - { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, - { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, - { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, - { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, - { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, - { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, - { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, @@ -420,112 +315,70 @@ wheels = [ [[package]] name = "chardet" -version = "5.2.0" +version = "7.4.0.post2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618, upload-time = "2023-08-01T19:23:02.662Z" } +sdist = { url = "https://files.pythonhosted.org/packages/03/4b/1fe1ade6b4d33abff0224b45a8310775b04308668ad1bdef725af8e3fcaa/chardet-7.4.0.post2.tar.gz", hash = "sha256:21a6b5ca695252c03385dcfcc8b55c27907f1fe80838aa171b1ff4e356a1bb67", size = 767694, upload-time = "2026-03-29T18:07:23.19Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385, upload-time = "2023-08-01T19:23:00.661Z" }, + { url = "https://files.pythonhosted.org/packages/b2/1e/8b5d54ecc873e828e9b91cddfce6bf5a058d7bb3d64007cfbbbc872b0bda/chardet-7.4.0.post2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5862b17677f7e8fcee4e37fe641f01d30762e4b075ac37ce9584e4407896e2d9", size = 853887, upload-time = "2026-03-29T18:07:12.156Z" }, + { url = "https://files.pythonhosted.org/packages/26/17/8c2cf762c876b04036e561d2a27df8a6305435db1cb584f71c356e319c40/chardet-7.4.0.post2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:22d05c4b7e721d5330d99ef4a6f6233a9de58ae6f2275c21a098bedd778a6cb7", size = 838555, upload-time = "2026-03-29T18:07:13.689Z" }, + { url = "https://files.pythonhosted.org/packages/3b/21/51fb8cfbcf2f1acc7c03776f4452f64ff2b9051505b38bc9e2a3941af330/chardet-7.4.0.post2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a035d407f762c21eb77069982425eb403e518dd758617aa43bf11d0d2203a1b6", size = 861305, upload-time = "2026-03-29T18:07:15.194Z" }, + { url = "https://files.pythonhosted.org/packages/fb/b6/13cc503f45beeb1117fc9c83f294df16ebce5d75eac9f0cefb8cce4357a1/chardet-7.4.0.post2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2adfa7390e69cb5ed499b54978d31f6d476788d07d83da3426811181b7ca7682", size = 868868, upload-time = "2026-03-29T18:07:16.781Z" }, + { url = "https://files.pythonhosted.org/packages/30/ca/f1ab73f8d431c5257ad536956992513a5c135c53cf2a3dc94b8a45f83082/chardet-7.4.0.post2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2345f20ea67cdadddb778b2bc31e2defc2a85ae027931f9ad6ab84fd5d345320", size = 863417, upload-time = "2026-03-29T18:07:18.467Z" }, + { url = "https://files.pythonhosted.org/packages/1a/cc/d2918dc6d110cf585a30ee11dbdcfa56a2b2fbf16e2b4117fe8bf800f320/chardet-7.4.0.post2-cp314-cp314-win_amd64.whl", hash = "sha256:52602972d4815047cee262551bc383ab394aa145f5ca9ee10d0a53d27965882e", size = 919100, upload-time = "2026-03-29T18:07:20.312Z" }, + { url = "https://files.pythonhosted.org/packages/94/d2/22ac0b5b832bb9d2f29311dcded6c09ad0c32c23e3e53a8033aad5eb8652/chardet-7.4.0.post2-py3-none-any.whl", hash = "sha256:e0c9c6b5c296c0e5197bc8876fcc04d58a6ddfba18399e598ba353aba28b038e", size = 625322, upload-time = "2026-03-29T18:07:21.81Z" }, ] [[package]] name = "charset-normalizer" -version = "3.4.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/35/02daf95b9cd686320bb622eb148792655c9412dbb9b67abb5694e5910a24/charset_normalizer-3.4.5.tar.gz", hash = "sha256:95adae7b6c42a6c5b5b559b1a99149f090a57128155daeea91732c8d970d8644", size = 134804, upload-time = "2026-03-06T06:03:19.46Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/21/a2b1505639008ba2e6ef03733a81fc6cfd6a07ea6139a2b76421230b8dad/charset_normalizer-3.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4167a621a9a1a986c73777dbc15d4b5eac8ac5c10393374109a343d4013ec765", size = 283319, upload-time = "2026-03-06T06:00:26.433Z" }, - { url = "https://files.pythonhosted.org/packages/70/67/df234c29b68f4e1e095885c9db1cb4b69b8aba49cf94fac041db4aaf1267/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f64c6bf8f32f9133b668c7f7a7cbdbc453412bc95ecdbd157f3b1e377a92990", size = 189974, upload-time = "2026-03-06T06:00:28.222Z" }, - { url = "https://files.pythonhosted.org/packages/df/7f/fc66af802961c6be42e2c7b69c58f95cbd1f39b0e81b3365d8efe2a02a04/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:568e3c34b58422075a1b49575a6abc616d9751b4d61b23f712e12ebb78fe47b2", size = 207866, upload-time = "2026-03-06T06:00:29.769Z" }, - { url = "https://files.pythonhosted.org/packages/c9/23/404eb36fac4e95b833c50e305bba9a241086d427bb2167a42eac7c4f7da4/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:036c079aa08a6a592b82487f97c60b439428320ed1b2ea0b3912e99d30c77765", size = 203239, upload-time = "2026-03-06T06:00:31.086Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2f/8a1d989bfadd120c90114ab33e0d2a0cbde05278c1fc15e83e62d570f50a/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:340810d34ef83af92148e96e3e44cb2d3f910d2bf95e5618a5c467d9f102231d", size = 196529, upload-time = "2026-03-06T06:00:32.608Z" }, - { url = "https://files.pythonhosted.org/packages/a5/0c/c75f85ff7ca1f051958bb518cd43922d86f576c03947a050fbedfdfb4f15/charset_normalizer-3.4.5-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:cd2d0f0ec9aa977a27731a3209ebbcacebebaf41f902bd453a928bfd281cf7f8", size = 184152, upload-time = "2026-03-06T06:00:33.93Z" }, - { url = "https://files.pythonhosted.org/packages/f9/20/4ed37f6199af5dde94d4aeaf577f3813a5ec6635834cda1d957013a09c76/charset_normalizer-3.4.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0b362bcd27819f9c07cbf23db4e0e8cd4b44c5ecd900c2ff907b2b92274a7412", size = 195226, upload-time = "2026-03-06T06:00:35.469Z" }, - { url = "https://files.pythonhosted.org/packages/28/31/7ba1102178cba7c34dcc050f43d427172f389729e356038f0726253dd914/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:77be992288f720306ab4108fe5c74797de327f3248368dfc7e1a916d6ed9e5a2", size = 192933, upload-time = "2026-03-06T06:00:36.83Z" }, - { url = "https://files.pythonhosted.org/packages/4b/23/f86443ab3921e6a60b33b93f4a1161222231f6c69bc24fb18f3bee7b8518/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:8b78d8a609a4b82c273257ee9d631ded7fac0d875bdcdccc109f3ee8328cfcb1", size = 185647, upload-time = "2026-03-06T06:00:38.367Z" }, - { url = "https://files.pythonhosted.org/packages/82/44/08b8be891760f1f5a6d23ce11d6d50c92981603e6eb740b4f72eea9424e2/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ba20bdf69bd127f66d0174d6f2a93e69045e0b4036dc1ca78e091bcc765830c4", size = 209533, upload-time = "2026-03-06T06:00:41.931Z" }, - { url = "https://files.pythonhosted.org/packages/3b/5f/df114f23406199f8af711ddccfbf409ffbc5b7cdc18fa19644997ff0c9bb/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:76a9d0de4d0eab387822e7b35d8f89367dd237c72e82ab42b9f7bf5e15ada00f", size = 195901, upload-time = "2026-03-06T06:00:43.978Z" }, - { url = "https://files.pythonhosted.org/packages/07/83/71ef34a76fe8aa05ff8f840244bda2d61e043c2ef6f30d200450b9f6a1be/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8fff79bf5978c693c9b1a4d71e4a94fddfb5fe744eb062a318e15f4a2f63a550", size = 204950, upload-time = "2026-03-06T06:00:45.202Z" }, - { url = "https://files.pythonhosted.org/packages/58/40/0253be623995365137d7dc68e45245036207ab2227251e69a3d93ce43183/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c7e84e0c0005e3bdc1a9211cd4e62c78ba80bc37b2365ef4410cd2007a9047f2", size = 198546, upload-time = "2026-03-06T06:00:46.481Z" }, - { url = "https://files.pythonhosted.org/packages/ed/5c/5f3cb5b259a130895ef5ae16b38eaf141430fa3f7af50cd06c5d67e4f7b2/charset_normalizer-3.4.5-cp310-cp310-win32.whl", hash = "sha256:58ad8270cfa5d4bef1bc85bd387217e14ff154d6630e976c6f56f9a040757475", size = 132516, upload-time = "2026-03-06T06:00:47.924Z" }, - { url = "https://files.pythonhosted.org/packages/a5/c3/84fb174e7770f2df2e1a2115090771bfbc2227fb39a765c6d00568d1aab4/charset_normalizer-3.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:02a9d1b01c1e12c27883b0c9349e0bcd9ae92e727ff1a277207e1a262b1cbf05", size = 142906, upload-time = "2026-03-06T06:00:49.389Z" }, - { url = "https://files.pythonhosted.org/packages/d7/b2/6f852f8b969f2cbd0d4092d2e60139ab1af95af9bb651337cae89ec0f684/charset_normalizer-3.4.5-cp310-cp310-win_arm64.whl", hash = "sha256:039215608ac7b358c4da0191d10fc76868567fbf276d54c14721bdedeb6de064", size = 133258, upload-time = "2026-03-06T06:00:51.051Z" }, - { url = "https://files.pythonhosted.org/packages/8f/9e/bcec3b22c64ecec47d39bf5167c2613efd41898c019dccd4183f6aa5d6a7/charset_normalizer-3.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:610f72c0ee565dfb8ae1241b666119582fdbfe7c0975c175be719f940e110694", size = 279531, upload-time = "2026-03-06T06:00:52.252Z" }, - { url = "https://files.pythonhosted.org/packages/58/12/81fd25f7e7078ab5d1eedbb0fac44be4904ae3370a3bf4533c8f2d159acd/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60d68e820af339df4ae8358c7a2e7596badeb61e544438e489035f9fbf3246a5", size = 188006, upload-time = "2026-03-06T06:00:53.8Z" }, - { url = "https://files.pythonhosted.org/packages/ae/6e/f2d30e8c27c1b0736a6520311982cf5286cfc7f6cac77d7bc1325e3a23f2/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b473fc8dca1c3ad8559985794815f06ca3fc71942c969129070f2c3cdf7281", size = 205085, upload-time = "2026-03-06T06:00:55.311Z" }, - { url = "https://files.pythonhosted.org/packages/d0/90/d12cefcb53b5931e2cf792a33718d7126efb116a320eaa0742c7059a95e4/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d4eb8ac7469b2a5d64b5b8c04f84d8bf3ad340f4514b98523805cbf46e3b3923", size = 200545, upload-time = "2026-03-06T06:00:56.532Z" }, - { url = "https://files.pythonhosted.org/packages/03/f4/44d3b830a20e89ff82a3134912d9a1cf6084d64f3b95dcad40f74449a654/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bcb3227c3d9aaf73eaaab1db7ccd80a8995c509ee9941e2aae060ca6e4e5d81", size = 193863, upload-time = "2026-03-06T06:00:57.823Z" }, - { url = "https://files.pythonhosted.org/packages/25/4b/f212119c18a6320a9d4a730d1b4057875cdeabf21b3614f76549042ef8a8/charset_normalizer-3.4.5-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:75ee9c1cce2911581a70a3c0919d8bccf5b1cbc9b0e5171400ec736b4b569497", size = 181827, upload-time = "2026-03-06T06:00:59.323Z" }, - { url = "https://files.pythonhosted.org/packages/74/00/b26158e48b425a202a92965f8069e8a63d9af1481dfa206825d7f74d2a3c/charset_normalizer-3.4.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d1401945cb77787dbd3af2446ff2d75912327c4c3a1526ab7955ecf8600687c", size = 191085, upload-time = "2026-03-06T06:01:00.546Z" }, - { url = "https://files.pythonhosted.org/packages/c4/c2/1c1737bf6fd40335fe53d28fe49afd99ee4143cc57a845e99635ce0b9b6d/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a45e504f5e1be0bd385935a8e1507c442349ca36f511a47057a71c9d1d6ea9e", size = 190688, upload-time = "2026-03-06T06:01:02.479Z" }, - { url = "https://files.pythonhosted.org/packages/5a/3d/abb5c22dc2ef493cd56522f811246a63c5427c08f3e3e50ab663de27fcf4/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e09f671a54ce70b79a1fc1dc6da3072b7ef7251fadb894ed92d9aa8218465a5f", size = 183077, upload-time = "2026-03-06T06:01:04.231Z" }, - { url = "https://files.pythonhosted.org/packages/44/33/5298ad4d419a58e25b3508e87f2758d1442ff00c2471f8e0403dab8edad5/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d01de5e768328646e6a3fa9e562706f8f6641708c115c62588aef2b941a4f88e", size = 206706, upload-time = "2026-03-06T06:01:05.773Z" }, - { url = "https://files.pythonhosted.org/packages/7b/17/51e7895ac0f87c3b91d276a449ef09f5532a7529818f59646d7a55089432/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:131716d6786ad5e3dc542f5cc6f397ba3339dc0fb87f87ac30e550e8987756af", size = 191665, upload-time = "2026-03-06T06:01:07.473Z" }, - { url = "https://files.pythonhosted.org/packages/90/8f/cce9adf1883e98906dbae380d769b4852bb0fa0004bc7d7a2243418d3ea8/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a374cc0b88aa710e8865dc1bd6edb3743c59f27830f0293ab101e4cf3ce9f85", size = 201950, upload-time = "2026-03-06T06:01:08.973Z" }, - { url = "https://files.pythonhosted.org/packages/08/ca/bce99cd5c397a52919e2769d126723f27a4c037130374c051c00470bcd38/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d31f0d1671e1534e395f9eb84a68e0fb670e1edb1fe819a9d7f564ae3bc4e53f", size = 195830, upload-time = "2026-03-06T06:01:10.155Z" }, - { url = "https://files.pythonhosted.org/packages/87/4f/2e3d023a06911f1281f97b8f036edc9872167036ca6f55cc874a0be6c12c/charset_normalizer-3.4.5-cp311-cp311-win32.whl", hash = "sha256:cace89841c0599d736d3d74a27bc5821288bb47c5441923277afc6059d7fbcb4", size = 132029, upload-time = "2026-03-06T06:01:11.706Z" }, - { url = "https://files.pythonhosted.org/packages/fe/1f/a853b73d386521fd44b7f67ded6b17b7b2367067d9106a5c4b44f9a34274/charset_normalizer-3.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:f8102ae93c0bc863b1d41ea0f4499c20a83229f52ed870850892df555187154a", size = 142404, upload-time = "2026-03-06T06:01:12.865Z" }, - { url = "https://files.pythonhosted.org/packages/b4/10/dba36f76b71c38e9d391abe0fd8a5b818790e053c431adecfc98c35cd2a9/charset_normalizer-3.4.5-cp311-cp311-win_arm64.whl", hash = "sha256:ed98364e1c262cf5f9363c3eca8c2df37024f52a8fa1180a3610014f26eac51c", size = 132796, upload-time = "2026-03-06T06:01:14.106Z" }, - { url = "https://files.pythonhosted.org/packages/9c/b6/9ee9c1a608916ca5feae81a344dffbaa53b26b90be58cc2159e3332d44ec/charset_normalizer-3.4.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed97c282ee4f994ef814042423a529df9497e3c666dca19be1d4cd1129dc7ade", size = 280976, upload-time = "2026-03-06T06:01:15.276Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d8/a54f7c0b96f1df3563e9190f04daf981e365a9b397eedfdfb5dbef7e5c6c/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0294916d6ccf2d069727d65973c3a1ca477d68708db25fd758dd28b0827cff54", size = 189356, upload-time = "2026-03-06T06:01:16.511Z" }, - { url = "https://files.pythonhosted.org/packages/42/69/2bf7f76ce1446759a5787cb87d38f6a61eb47dbbdf035cfebf6347292a65/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dc57a0baa3eeedd99fafaef7511b5a6ef4581494e8168ee086031744e2679467", size = 206369, upload-time = "2026-03-06T06:01:17.853Z" }, - { url = "https://files.pythonhosted.org/packages/10/9c/949d1a46dab56b959d9a87272482195f1840b515a3380e39986989a893ae/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ed1a9a204f317ef879b32f9af507d47e49cd5e7f8e8d5d96358c98373314fc60", size = 203285, upload-time = "2026-03-06T06:01:19.473Z" }, - { url = "https://files.pythonhosted.org/packages/67/5c/ae30362a88b4da237d71ea214a8c7eb915db3eec941adda511729ac25fa2/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad83b8f9379176c841f8865884f3514d905bcd2a9a3b210eaa446e7d2223e4d", size = 196274, upload-time = "2026-03-06T06:01:20.728Z" }, - { url = "https://files.pythonhosted.org/packages/b2/07/c9f2cb0e46cb6d64fdcc4f95953747b843bb2181bda678dc4e699b8f0f9a/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:a118e2e0b5ae6b0120d5efa5f866e58f2bb826067a646431da4d6a2bdae7950e", size = 184715, upload-time = "2026-03-06T06:01:22.194Z" }, - { url = "https://files.pythonhosted.org/packages/36/64/6b0ca95c44fddf692cd06d642b28f63009d0ce325fad6e9b2b4d0ef86a52/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:754f96058e61a5e22e91483f823e07df16416ce76afa4ebf306f8e1d1296d43f", size = 193426, upload-time = "2026-03-06T06:01:23.795Z" }, - { url = "https://files.pythonhosted.org/packages/50/bc/a730690d726403743795ca3f5bb2baf67838c5fea78236098f324b965e40/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0c300cefd9b0970381a46394902cd18eaf2aa00163f999590ace991989dcd0fc", size = 191780, upload-time = "2026-03-06T06:01:25.053Z" }, - { url = "https://files.pythonhosted.org/packages/97/4f/6c0bc9af68222b22951552d73df4532b5be6447cee32d58e7e8c74ecbb7b/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c108f8619e504140569ee7de3f97d234f0fbae338a7f9f360455071ef9855a95", size = 185805, upload-time = "2026-03-06T06:01:26.294Z" }, - { url = "https://files.pythonhosted.org/packages/dd/b9/a523fb9b0ee90814b503452b2600e4cbc118cd68714d57041564886e7325/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d1028de43596a315e2720a9849ee79007ab742c06ad8b45a50db8cdb7ed4a82a", size = 208342, upload-time = "2026-03-06T06:01:27.55Z" }, - { url = "https://files.pythonhosted.org/packages/4d/61/c59e761dee4464050713e50e27b58266cc8e209e518c0b378c1580c959ba/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:19092dde50335accf365cce21998a1c6dd8eafd42c7b226eb54b2747cdce2fac", size = 193661, upload-time = "2026-03-06T06:01:29.051Z" }, - { url = "https://files.pythonhosted.org/packages/1c/43/729fa30aad69783f755c5ad8649da17ee095311ca42024742701e202dc59/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4354e401eb6dab9aed3c7b4030514328a6c748d05e1c3e19175008ca7de84fb1", size = 204819, upload-time = "2026-03-06T06:01:30.298Z" }, - { url = "https://files.pythonhosted.org/packages/87/33/d9b442ce5a91b96fc0840455a9e49a611bbadae6122778d0a6a79683dd31/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a68766a3c58fde7f9aaa22b3786276f62ab2f594efb02d0a1421b6282e852e98", size = 198080, upload-time = "2026-03-06T06:01:31.478Z" }, - { url = "https://files.pythonhosted.org/packages/56/5a/b8b5a23134978ee9885cee2d6995f4c27cc41f9baded0a9685eabc5338f0/charset_normalizer-3.4.5-cp312-cp312-win32.whl", hash = "sha256:1827734a5b308b65ac54e86a618de66f935a4f63a8a462ff1e19a6788d6c2262", size = 132630, upload-time = "2026-03-06T06:01:33.056Z" }, - { url = "https://files.pythonhosted.org/packages/70/53/e44a4c07e8904500aec95865dc3f6464dc3586a039ef0df606eb3ac38e35/charset_normalizer-3.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:728c6a963dfab66ef865f49286e45239384249672cd598576765acc2a640a636", size = 142856, upload-time = "2026-03-06T06:01:34.489Z" }, - { url = "https://files.pythonhosted.org/packages/ea/aa/c5628f7cad591b1cf45790b7a61483c3e36cf41349c98af7813c483fd6e8/charset_normalizer-3.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:75dfd1afe0b1647449e852f4fb428195a7ed0588947218f7ba929f6538487f02", size = 132982, upload-time = "2026-03-06T06:01:35.641Z" }, - { url = "https://files.pythonhosted.org/packages/f5/48/9f34ec4bb24aa3fdba1890c1bddb97c8a4be1bd84ef5c42ac2352563ad05/charset_normalizer-3.4.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ac59c15e3f1465f722607800c68713f9fbc2f672b9eb649fe831da4019ae9b23", size = 280788, upload-time = "2026-03-06T06:01:37.126Z" }, - { url = "https://files.pythonhosted.org/packages/0e/09/6003e7ffeb90cc0560da893e3208396a44c210c5ee42efff539639def59b/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:165c7b21d19365464e8f70e5ce5e12524c58b48c78c1f5a57524603c1ab003f8", size = 188890, upload-time = "2026-03-06T06:01:38.73Z" }, - { url = "https://files.pythonhosted.org/packages/42/1e/02706edf19e390680daa694d17e2b8eab4b5f7ac285e2a51168b4b22ee6b/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:28269983f25a4da0425743d0d257a2d6921ea7d9b83599d4039486ec5b9f911d", size = 206136, upload-time = "2026-03-06T06:01:40.016Z" }, - { url = "https://files.pythonhosted.org/packages/c7/87/942c3def1b37baf3cf786bad01249190f3ca3d5e63a84f831e704977de1f/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d27ce22ec453564770d29d03a9506d449efbb9fa13c00842262b2f6801c48cce", size = 202551, upload-time = "2026-03-06T06:01:41.522Z" }, - { url = "https://files.pythonhosted.org/packages/94/0a/af49691938dfe175d71b8a929bd7e4ace2809c0c5134e28bc535660d5262/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0625665e4ebdddb553ab185de5db7054393af8879fb0c87bd5690d14379d6819", size = 195572, upload-time = "2026-03-06T06:01:43.208Z" }, - { url = "https://files.pythonhosted.org/packages/20/ea/dfb1792a8050a8e694cfbde1570ff97ff74e48afd874152d38163d1df9ae/charset_normalizer-3.4.5-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:c23eb3263356d94858655b3e63f85ac5d50970c6e8febcdde7830209139cc37d", size = 184438, upload-time = "2026-03-06T06:01:44.755Z" }, - { url = "https://files.pythonhosted.org/packages/72/12/c281e2067466e3ddd0595bfaea58a6946765ace5c72dfa3edc2f5f118026/charset_normalizer-3.4.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e6302ca4ae283deb0af68d2fbf467474b8b6aedcd3dab4db187e07f94c109763", size = 193035, upload-time = "2026-03-06T06:01:46.051Z" }, - { url = "https://files.pythonhosted.org/packages/ba/4f/3792c056e7708e10464bad0438a44708886fb8f92e3c3d29ec5e2d964d42/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e51ae7d81c825761d941962450f50d041db028b7278e7b08930b4541b3e45cb9", size = 191340, upload-time = "2026-03-06T06:01:47.547Z" }, - { url = "https://files.pythonhosted.org/packages/e7/86/80ddba897127b5c7a9bccc481b0cd36c8fefa485d113262f0fe4332f0bf4/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:597d10dec876923e5c59e48dbd366e852eacb2b806029491d307daea6b917d7c", size = 185464, upload-time = "2026-03-06T06:01:48.764Z" }, - { url = "https://files.pythonhosted.org/packages/4d/00/b5eff85ba198faacab83e0e4b6f0648155f072278e3b392a82478f8b988b/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5cffde4032a197bd3b42fd0b9509ec60fb70918d6970e4cc773f20fc9180ca67", size = 208014, upload-time = "2026-03-06T06:01:50.371Z" }, - { url = "https://files.pythonhosted.org/packages/c8/11/d36f70be01597fd30850dde8a1269ebc8efadd23ba5785808454f2389bde/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2da4eedcb6338e2321e831a0165759c0c620e37f8cd044a263ff67493be8ffb3", size = 193297, upload-time = "2026-03-06T06:01:51.933Z" }, - { url = "https://files.pythonhosted.org/packages/1a/1d/259eb0a53d4910536c7c2abb9cb25f4153548efb42800c6a9456764649c0/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:65a126fb4b070d05340a84fc709dd9e7c75d9b063b610ece8a60197a291d0adf", size = 204321, upload-time = "2026-03-06T06:01:53.887Z" }, - { url = "https://files.pythonhosted.org/packages/84/31/faa6c5b9d3688715e1ed1bb9d124c384fe2fc1633a409e503ffe1c6398c1/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7a80a9242963416bd81f99349d5f3fce1843c303bd404f204918b6d75a75fd6", size = 197509, upload-time = "2026-03-06T06:01:56.439Z" }, - { url = "https://files.pythonhosted.org/packages/fd/a5/c7d9dd1503ffc08950b3260f5d39ec2366dd08254f0900ecbcf3a6197c7c/charset_normalizer-3.4.5-cp313-cp313-win32.whl", hash = "sha256:f1d725b754e967e648046f00c4facc42d414840f5ccc670c5670f59f83693e4f", size = 132284, upload-time = "2026-03-06T06:01:57.812Z" }, - { url = "https://files.pythonhosted.org/packages/b9/0f/57072b253af40c8aa6636e6de7d75985624c1eb392815b2f934199340a89/charset_normalizer-3.4.5-cp313-cp313-win_amd64.whl", hash = "sha256:e37bd100d2c5d3ba35db9c7c5ba5a9228cbcffe5c4778dc824b164e5257813d7", size = 142630, upload-time = "2026-03-06T06:01:59.062Z" }, - { url = "https://files.pythonhosted.org/packages/31/41/1c4b7cc9f13bd9d369ce3bc993e13d374ce25fa38a2663644283ecf422c1/charset_normalizer-3.4.5-cp313-cp313-win_arm64.whl", hash = "sha256:93b3b2cc5cf1b8743660ce77a4f45f3f6d1172068207c1defc779a36eea6bb36", size = 133254, upload-time = "2026-03-06T06:02:00.281Z" }, - { url = "https://files.pythonhosted.org/packages/43/be/0f0fd9bb4a7fa4fb5067fb7d9ac693d4e928d306f80a0d02bde43a7c4aee/charset_normalizer-3.4.5-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8197abe5ca1ffb7d91e78360f915eef5addff270f8a71c1fc5be24a56f3e4873", size = 280232, upload-time = "2026-03-06T06:02:01.508Z" }, - { url = "https://files.pythonhosted.org/packages/28/02/983b5445e4bef49cd8c9da73a8e029f0825f39b74a06d201bfaa2e55142a/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2aecdb364b8a1802afdc7f9327d55dad5366bc97d8502d0f5854e50712dbc5f", size = 189688, upload-time = "2026-03-06T06:02:02.857Z" }, - { url = "https://files.pythonhosted.org/packages/d0/88/152745c5166437687028027dc080e2daed6fe11cfa95a22f4602591c42db/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a66aa5022bf81ab4b1bebfb009db4fd68e0c6d4307a1ce5ef6a26e5878dfc9e4", size = 206833, upload-time = "2026-03-06T06:02:05.127Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0f/ebc15c8b02af2f19be9678d6eed115feeeccc45ce1f4b098d986c13e8769/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d77f97e515688bd615c1d1f795d540f32542d514242067adcb8ef532504cb9ee", size = 202879, upload-time = "2026-03-06T06:02:06.446Z" }, - { url = "https://files.pythonhosted.org/packages/38/9c/71336bff6934418dc8d1e8a1644176ac9088068bc571da612767619c97b3/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01a1ed54b953303ca7e310fafe0fe347aab348bd81834a0bcd602eb538f89d66", size = 195764, upload-time = "2026-03-06T06:02:08.763Z" }, - { url = "https://files.pythonhosted.org/packages/b7/95/ce92fde4f98615661871bc282a856cf9b8a15f686ba0af012984660d480b/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:b2d37d78297b39a9eb9eb92c0f6df98c706467282055419df141389b23f93362", size = 183728, upload-time = "2026-03-06T06:02:10.137Z" }, - { url = "https://files.pythonhosted.org/packages/1c/e7/f5b4588d94e747ce45ae680f0f242bc2d98dbd4eccfab73e6160b6893893/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e71bbb595973622b817c042bd943c3f3667e9c9983ce3d205f973f486fec98a7", size = 192937, upload-time = "2026-03-06T06:02:11.663Z" }, - { url = "https://files.pythonhosted.org/packages/f9/29/9d94ed6b929bf9f48bf6ede6e7474576499f07c4c5e878fb186083622716/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cd966c2559f501c6fd69294d082c2934c8dd4719deb32c22961a5ac6db0df1d", size = 192040, upload-time = "2026-03-06T06:02:13.489Z" }, - { url = "https://files.pythonhosted.org/packages/15/d2/1a093a1cf827957f9445f2fe7298bcc16f8fc5e05c1ed2ad1af0b239035e/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d5e52d127045d6ae01a1e821acfad2f3a1866c54d0e837828538fabe8d9d1bd6", size = 184107, upload-time = "2026-03-06T06:02:14.83Z" }, - { url = "https://files.pythonhosted.org/packages/0f/7d/82068ce16bd36135df7b97f6333c5d808b94e01d4599a682e2337ed5fd14/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:30a2b1a48478c3428d047ed9690d57c23038dac838a87ad624c85c0a78ebeb39", size = 208310, upload-time = "2026-03-06T06:02:16.165Z" }, - { url = "https://files.pythonhosted.org/packages/84/4e/4dfb52307bb6af4a5c9e73e482d171b81d36f522b21ccd28a49656baa680/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d8ed79b8f6372ca4254955005830fd61c1ccdd8c0fac6603e2c145c61dd95db6", size = 192918, upload-time = "2026-03-06T06:02:18.144Z" }, - { url = "https://files.pythonhosted.org/packages/08/a4/159ff7da662cf7201502ca89980b8f06acf3e887b278956646a8aeb178ab/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:c5af897b45fa606b12464ccbe0014bbf8c09191e0a66aab6aa9d5cf6e77e0c94", size = 204615, upload-time = "2026-03-06T06:02:19.821Z" }, - { url = "https://files.pythonhosted.org/packages/d6/62/0dd6172203cb6b429ffffc9935001fde42e5250d57f07b0c28c6046deb6b/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1088345bcc93c58d8d8f3d783eca4a6e7a7752bbff26c3eee7e73c597c191c2e", size = 197784, upload-time = "2026-03-06T06:02:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/c7/5e/1aab5cb737039b9c59e63627dc8bbc0d02562a14f831cc450e5f91d84ce1/charset_normalizer-3.4.5-cp314-cp314-win32.whl", hash = "sha256:ee57b926940ba00bca7ba7041e665cc956e55ef482f851b9b65acb20d867e7a2", size = 133009, upload-time = "2026-03-06T06:02:23.289Z" }, - { url = "https://files.pythonhosted.org/packages/40/65/e7c6c77d7aaa4c0d7974f2e403e17f0ed2cb0fc135f77d686b916bf1eead/charset_normalizer-3.4.5-cp314-cp314-win_amd64.whl", hash = "sha256:4481e6da1830c8a1cc0b746b47f603b653dadb690bcd851d039ffaefe70533aa", size = 143511, upload-time = "2026-03-06T06:02:26.195Z" }, - { url = "https://files.pythonhosted.org/packages/ba/91/52b0841c71f152f563b8e072896c14e3d83b195c188b338d3cc2e582d1d4/charset_normalizer-3.4.5-cp314-cp314-win_arm64.whl", hash = "sha256:97ab7787092eb9b50fb47fa04f24c75b768a606af1bcba1957f07f128a7219e4", size = 133775, upload-time = "2026-03-06T06:02:27.473Z" }, - { url = "https://files.pythonhosted.org/packages/c5/60/3a621758945513adfd4db86827a5bafcc615f913dbd0b4c2ed64a65731be/charset_normalizer-3.4.5-py3-none-any.whl", hash = "sha256:9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0", size = 55455, upload-time = "2026-03-06T06:03:17.827Z" }, +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, + { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, + { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, + { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, + { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, + { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, + { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, + { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, + { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, + { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, + { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, + { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, + { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, + { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, + { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, + { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, + { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, + { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, + { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, ] [[package]] name = "click" -version = "8.3.1" +version = "8.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/75/31212c6bf2503fdf920d87fee5d7a86a2e3bcf444984126f13d8e4016804/click-8.3.2.tar.gz", hash = "sha256:14162b8b3b3550a7d479eafa77dfd3c38d9dc8951f6f69c78913a8f9a7540fd5", size = 302856, upload-time = "2026-04-03T19:14:45.118Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, + { url = "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl", hash = "sha256:1924d2c27c5653561cd2cae4548d1406039cb79b858b747cfea24924bbc1616d", size = 108379, upload-time = "2026-04-03T19:14:43.505Z" }, ] [[package]] @@ -539,197 +392,104 @@ wheels = [ [[package]] name = "coverage" -version = "7.13.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/56/95b7e30fa389756cb56630faa728da46a27b8c6eb46f9d557c68fff12b65/coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91", size = 827239, upload-time = "2026-02-09T12:59:03.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/d4/7827d9ffa34d5d4d752eec907022aa417120936282fc488306f5da08c292/coverage-7.13.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fc31c787a84f8cd6027eba44010517020e0d18487064cd3d8968941856d1415", size = 219152, upload-time = "2026-02-09T12:56:11.974Z" }, - { url = "https://files.pythonhosted.org/packages/35/b0/d69df26607c64043292644dbb9dc54b0856fabaa2cbb1eeee3331cc9e280/coverage-7.13.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a32ebc02a1805adf637fc8dec324b5cdacd2e493515424f70ee33799573d661b", size = 219667, upload-time = "2026-02-09T12:56:13.33Z" }, - { url = "https://files.pythonhosted.org/packages/82/a4/c1523f7c9e47b2271dbf8c2a097e7a1f89ef0d66f5840bb59b7e8814157b/coverage-7.13.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e24f9156097ff9dc286f2f913df3a7f63c0e333dcafa3c196f2c18b4175ca09a", size = 246425, upload-time = "2026-02-09T12:56:14.552Z" }, - { url = "https://files.pythonhosted.org/packages/f8/02/aa7ec01d1a5023c4b680ab7257f9bfde9defe8fdddfe40be096ac19e8177/coverage-7.13.4-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8041b6c5bfdc03257666e9881d33b1abc88daccaf73f7b6340fb7946655cd10f", size = 248229, upload-time = "2026-02-09T12:56:16.31Z" }, - { url = "https://files.pythonhosted.org/packages/35/98/85aba0aed5126d896162087ef3f0e789a225697245256fc6181b95f47207/coverage-7.13.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a09cfa6a5862bc2fc6ca7c3def5b2926194a56b8ab78ffcf617d28911123012", size = 250106, upload-time = "2026-02-09T12:56:18.024Z" }, - { url = "https://files.pythonhosted.org/packages/96/72/1db59bd67494bc162e3e4cd5fbc7edba2c7026b22f7c8ef1496d58c2b94c/coverage-7.13.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:296f8b0af861d3970c2a4d8c91d48eb4dd4771bcef9baedec6a9b515d7de3def", size = 252021, upload-time = "2026-02-09T12:56:19.272Z" }, - { url = "https://files.pythonhosted.org/packages/9d/97/72899c59c7066961de6e3daa142d459d47d104956db43e057e034f015c8a/coverage-7.13.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e101609bcbbfb04605ea1027b10dc3735c094d12d40826a60f897b98b1c30256", size = 247114, upload-time = "2026-02-09T12:56:21.051Z" }, - { url = "https://files.pythonhosted.org/packages/39/1f/f1885573b5970235e908da4389176936c8933e86cb316b9620aab1585fa2/coverage-7.13.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aa3feb8db2e87ff5e6d00d7e1480ae241876286691265657b500886c98f38bda", size = 248143, upload-time = "2026-02-09T12:56:22.585Z" }, - { url = "https://files.pythonhosted.org/packages/a8/cf/e80390c5b7480b722fa3e994f8202807799b85bc562aa4f1dde209fbb7be/coverage-7.13.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4fc7fa81bbaf5a02801b65346c8b3e657f1d93763e58c0abdf7c992addd81a92", size = 246152, upload-time = "2026-02-09T12:56:23.748Z" }, - { url = "https://files.pythonhosted.org/packages/44/bf/f89a8350d85572f95412debb0fb9bb4795b1d5b5232bd652923c759e787b/coverage-7.13.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:33901f604424145c6e9c2398684b92e176c0b12df77d52db81c20abd48c3794c", size = 249959, upload-time = "2026-02-09T12:56:25.209Z" }, - { url = "https://files.pythonhosted.org/packages/f7/6e/612a02aece8178c818df273e8d1642190c4875402ca2ba74514394b27aba/coverage-7.13.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:bb28c0f2cf2782508a40cec377935829d5fcc3ad9a3681375af4e84eb34b6b58", size = 246416, upload-time = "2026-02-09T12:56:26.475Z" }, - { url = "https://files.pythonhosted.org/packages/cb/98/b5afc39af67c2fa6786b03c3a7091fc300947387ce8914b096db8a73d67a/coverage-7.13.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d107aff57a83222ddbd8d9ee705ede2af2cc926608b57abed8ef96b50b7e8f9", size = 247025, upload-time = "2026-02-09T12:56:27.727Z" }, - { url = "https://files.pythonhosted.org/packages/51/30/2bba8ef0682d5bd210c38fe497e12a06c9f8d663f7025e9f5c2c31ce847d/coverage-7.13.4-cp310-cp310-win32.whl", hash = "sha256:a6f94a7d00eb18f1b6d403c91a88fd58cfc92d4b16080dfdb774afc8294469bf", size = 221758, upload-time = "2026-02-09T12:56:29.051Z" }, - { url = "https://files.pythonhosted.org/packages/78/13/331f94934cf6c092b8ea59ff868eb587bc8fe0893f02c55bc6c0183a192e/coverage-7.13.4-cp310-cp310-win_amd64.whl", hash = "sha256:2cb0f1e000ebc419632bbe04366a8990b6e32c4e0b51543a6484ffe15eaeda95", size = 222693, upload-time = "2026-02-09T12:56:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/b4/ad/b59e5b451cf7172b8d1043dc0fa718f23aab379bc1521ee13d4bd9bfa960/coverage-7.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d490ba50c3f35dd7c17953c68f3270e7ccd1c6642e2d2afe2d8e720b98f5a053", size = 219278, upload-time = "2026-02-09T12:56:31.673Z" }, - { url = "https://files.pythonhosted.org/packages/f1/17/0cb7ca3de72e5f4ef2ec2fa0089beafbcaaaead1844e8b8a63d35173d77d/coverage-7.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:19bc3c88078789f8ef36acb014d7241961dbf883fd2533d18cb1e7a5b4e28b11", size = 219783, upload-time = "2026-02-09T12:56:33.104Z" }, - { url = "https://files.pythonhosted.org/packages/ab/63/325d8e5b11e0eaf6d0f6a44fad444ae58820929a9b0de943fa377fe73e85/coverage-7.13.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3998e5a32e62fdf410c0dbd3115df86297995d6e3429af80b8798aad894ca7aa", size = 250200, upload-time = "2026-02-09T12:56:34.474Z" }, - { url = "https://files.pythonhosted.org/packages/76/53/c16972708cbb79f2942922571a687c52bd109a7bd51175aeb7558dff2236/coverage-7.13.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e264226ec98e01a8e1054314af91ee6cde0eacac4f465cc93b03dbe0bce2fd7", size = 252114, upload-time = "2026-02-09T12:56:35.749Z" }, - { url = "https://files.pythonhosted.org/packages/eb/c2/7ab36d8b8cc412bec9ea2d07c83c48930eb4ba649634ba00cb7e4e0f9017/coverage-7.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3aa4e7b9e416774b21797365b358a6e827ffadaaca81b69ee02946852449f00", size = 254220, upload-time = "2026-02-09T12:56:37.796Z" }, - { url = "https://files.pythonhosted.org/packages/d6/4d/cf52c9a3322c89a0e6febdfbc83bb45c0ed3c64ad14081b9503adee702e7/coverage-7.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71ca20079dd8f27fcf808817e281e90220475cd75115162218d0e27549f95fef", size = 256164, upload-time = "2026-02-09T12:56:39.016Z" }, - { url = "https://files.pythonhosted.org/packages/78/e9/eb1dd17bd6de8289df3580e967e78294f352a5df8a57ff4671ee5fc3dcd0/coverage-7.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e2f25215f1a359ab17320b47bcdaca3e6e6356652e8256f2441e4ef972052903", size = 250325, upload-time = "2026-02-09T12:56:40.668Z" }, - { url = "https://files.pythonhosted.org/packages/71/07/8c1542aa873728f72267c07278c5cc0ec91356daf974df21335ccdb46368/coverage-7.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d65b2d373032411e86960604dc4edac91fdfb5dca539461cf2cbe78327d1e64f", size = 251913, upload-time = "2026-02-09T12:56:41.97Z" }, - { url = "https://files.pythonhosted.org/packages/74/d7/c62e2c5e4483a748e27868e4c32ad3daa9bdddbba58e1bc7a15e252baa74/coverage-7.13.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94eb63f9b363180aff17de3e7c8760c3ba94664ea2695c52f10111244d16a299", size = 249974, upload-time = "2026-02-09T12:56:43.323Z" }, - { url = "https://files.pythonhosted.org/packages/98/9f/4c5c015a6e98ced54efd0f5cf8d31b88e5504ecb6857585fc0161bb1e600/coverage-7.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e856bf6616714c3a9fbc270ab54103f4e685ba236fa98c054e8f87f266c93505", size = 253741, upload-time = "2026-02-09T12:56:45.155Z" }, - { url = "https://files.pythonhosted.org/packages/bd/59/0f4eef89b9f0fcd9633b5d350016f54126ab49426a70ff4c4e87446cabdc/coverage-7.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:65dfcbe305c3dfe658492df2d85259e0d79ead4177f9ae724b6fb245198f55d6", size = 249695, upload-time = "2026-02-09T12:56:46.636Z" }, - { url = "https://files.pythonhosted.org/packages/b5/2c/b7476f938deb07166f3eb281a385c262675d688ff4659ad56c6c6b8e2e70/coverage-7.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b507778ae8a4c915436ed5c2e05b4a6cecfa70f734e19c22a005152a11c7b6a9", size = 250599, upload-time = "2026-02-09T12:56:48.13Z" }, - { url = "https://files.pythonhosted.org/packages/b8/34/c3420709d9846ee3785b9f2831b4d94f276f38884032dca1457fa83f7476/coverage-7.13.4-cp311-cp311-win32.whl", hash = "sha256:784fc3cf8be001197b652d51d3fd259b1e2262888693a4636e18879f613a62a9", size = 221780, upload-time = "2026-02-09T12:56:50.479Z" }, - { url = "https://files.pythonhosted.org/packages/61/08/3d9c8613079d2b11c185b865de9a4c1a68850cfda2b357fae365cf609f29/coverage-7.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:2421d591f8ca05b308cf0092807308b2facbefe54af7c02ac22548b88b95c98f", size = 222715, upload-time = "2026-02-09T12:56:51.815Z" }, - { url = "https://files.pythonhosted.org/packages/18/1a/54c3c80b2f056164cc0a6cdcb040733760c7c4be9d780fe655f356f433e4/coverage-7.13.4-cp311-cp311-win_arm64.whl", hash = "sha256:79e73a76b854d9c6088fe5d8b2ebe745f8681c55f7397c3c0a016192d681045f", size = 221385, upload-time = "2026-02-09T12:56:53.194Z" }, - { url = "https://files.pythonhosted.org/packages/d1/81/4ce2fdd909c5a0ed1f6dedb88aa57ab79b6d1fbd9b588c1ac7ef45659566/coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459", size = 219449, upload-time = "2026-02-09T12:56:54.889Z" }, - { url = "https://files.pythonhosted.org/packages/5d/96/5238b1efc5922ddbdc9b0db9243152c09777804fb7c02ad1741eb18a11c0/coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3", size = 219810, upload-time = "2026-02-09T12:56:56.33Z" }, - { url = "https://files.pythonhosted.org/packages/78/72/2f372b726d433c9c35e56377cf1d513b4c16fe51841060d826b95caacec1/coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634", size = 251308, upload-time = "2026-02-09T12:56:57.858Z" }, - { url = "https://files.pythonhosted.org/packages/5d/a0/2ea570925524ef4e00bb6c82649f5682a77fac5ab910a65c9284de422600/coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3", size = 254052, upload-time = "2026-02-09T12:56:59.754Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ac/45dc2e19a1939098d783c846e130b8f862fbb50d09e0af663988f2f21973/coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa", size = 255165, upload-time = "2026-02-09T12:57:01.287Z" }, - { url = "https://files.pythonhosted.org/packages/2d/4d/26d236ff35abc3b5e63540d3386e4c3b192168c1d96da5cb2f43c640970f/coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3", size = 257432, upload-time = "2026-02-09T12:57:02.637Z" }, - { url = "https://files.pythonhosted.org/packages/ec/55/14a966c757d1348b2e19caf699415a2a4c4f7feaa4bbc6326a51f5c7dd1b/coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a", size = 251716, upload-time = "2026-02-09T12:57:04.056Z" }, - { url = "https://files.pythonhosted.org/packages/77/33/50116647905837c66d28b2af1321b845d5f5d19be9655cb84d4a0ea806b4/coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7", size = 253089, upload-time = "2026-02-09T12:57:05.503Z" }, - { url = "https://files.pythonhosted.org/packages/c2/b4/8efb11a46e3665d92635a56e4f2d4529de6d33f2cb38afd47d779d15fc99/coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc", size = 251232, upload-time = "2026-02-09T12:57:06.879Z" }, - { url = "https://files.pythonhosted.org/packages/51/24/8cd73dd399b812cc76bb0ac260e671c4163093441847ffe058ac9fda1e32/coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47", size = 255299, upload-time = "2026-02-09T12:57:08.245Z" }, - { url = "https://files.pythonhosted.org/packages/03/94/0a4b12f1d0e029ce1ccc1c800944a9984cbe7d678e470bb6d3c6bc38a0da/coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985", size = 250796, upload-time = "2026-02-09T12:57:10.142Z" }, - { url = "https://files.pythonhosted.org/packages/73/44/6002fbf88f6698ca034360ce474c406be6d5a985b3fdb3401128031eef6b/coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0", size = 252673, upload-time = "2026-02-09T12:57:12.197Z" }, - { url = "https://files.pythonhosted.org/packages/de/c6/a0279f7c00e786be75a749a5674e6fa267bcbd8209cd10c9a450c655dfa7/coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246", size = 221990, upload-time = "2026-02-09T12:57:14.085Z" }, - { url = "https://files.pythonhosted.org/packages/77/4e/c0a25a425fcf5557d9abd18419c95b63922e897bc86c1f327f155ef234a9/coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126", size = 222800, upload-time = "2026-02-09T12:57:15.944Z" }, - { url = "https://files.pythonhosted.org/packages/47/ac/92da44ad9a6f4e3a7debd178949d6f3769bedca33830ce9b1dcdab589a37/coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d", size = 221415, upload-time = "2026-02-09T12:57:17.497Z" }, - { url = "https://files.pythonhosted.org/packages/db/23/aad45061a31677d68e47499197a131eea55da4875d16c1f42021ab963503/coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9", size = 219474, upload-time = "2026-02-09T12:57:19.332Z" }, - { url = "https://files.pythonhosted.org/packages/a5/70/9b8b67a0945f3dfec1fd896c5cefb7c19d5a3a6d74630b99a895170999ae/coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac", size = 219844, upload-time = "2026-02-09T12:57:20.66Z" }, - { url = "https://files.pythonhosted.org/packages/97/fd/7e859f8fab324cef6c4ad7cff156ca7c489fef9179d5749b0c8d321281c2/coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea", size = 250832, upload-time = "2026-02-09T12:57:22.007Z" }, - { url = "https://files.pythonhosted.org/packages/e4/dc/b2442d10020c2f52617828862d8b6ee337859cd8f3a1f13d607dddda9cf7/coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b", size = 253434, upload-time = "2026-02-09T12:57:23.339Z" }, - { url = "https://files.pythonhosted.org/packages/5a/88/6728a7ad17428b18d836540630487231f5470fb82454871149502f5e5aa2/coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525", size = 254676, upload-time = "2026-02-09T12:57:24.774Z" }, - { url = "https://files.pythonhosted.org/packages/7c/bc/21244b1b8cedf0dff0a2b53b208015fe798d5f2a8d5348dbfece04224fff/coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242", size = 256807, upload-time = "2026-02-09T12:57:26.125Z" }, - { url = "https://files.pythonhosted.org/packages/97/a0/ddba7ed3251cff51006737a727d84e05b61517d1784a9988a846ba508877/coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148", size = 251058, upload-time = "2026-02-09T12:57:27.614Z" }, - { url = "https://files.pythonhosted.org/packages/9b/55/e289addf7ff54d3a540526f33751951bf0878f3809b47f6dfb3def69c6f7/coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a", size = 252805, upload-time = "2026-02-09T12:57:29.066Z" }, - { url = "https://files.pythonhosted.org/packages/13/4e/cc276b1fa4a59be56d96f1dabddbdc30f4ba22e3b1cd42504c37b3313255/coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23", size = 250766, upload-time = "2026-02-09T12:57:30.522Z" }, - { url = "https://files.pythonhosted.org/packages/94/44/1093b8f93018f8b41a8cf29636c9292502f05e4a113d4d107d14a3acd044/coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80", size = 254923, upload-time = "2026-02-09T12:57:31.946Z" }, - { url = "https://files.pythonhosted.org/packages/8b/55/ea2796da2d42257f37dbea1aab239ba9263b31bd91d5527cdd6db5efe174/coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea", size = 250591, upload-time = "2026-02-09T12:57:33.842Z" }, - { url = "https://files.pythonhosted.org/packages/d4/fa/7c4bb72aacf8af5020675aa633e59c1fbe296d22aed191b6a5b711eb2bc7/coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a", size = 252364, upload-time = "2026-02-09T12:57:35.743Z" }, - { url = "https://files.pythonhosted.org/packages/5c/38/a8d2ec0146479c20bbaa7181b5b455a0c41101eed57f10dd19a78ab44c80/coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d", size = 222010, upload-time = "2026-02-09T12:57:37.25Z" }, - { url = "https://files.pythonhosted.org/packages/e2/0c/dbfafbe90a185943dcfbc766fe0e1909f658811492d79b741523a414a6cc/coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd", size = 222818, upload-time = "2026-02-09T12:57:38.734Z" }, - { url = "https://files.pythonhosted.org/packages/04/d1/934918a138c932c90d78301f45f677fb05c39a3112b96fd2c8e60503cdc7/coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af", size = 221438, upload-time = "2026-02-09T12:57:40.223Z" }, - { url = "https://files.pythonhosted.org/packages/52/57/ee93ced533bcb3e6df961c0c6e42da2fc6addae53fb95b94a89b1e33ebd7/coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d", size = 220165, upload-time = "2026-02-09T12:57:41.639Z" }, - { url = "https://files.pythonhosted.org/packages/c5/e0/969fc285a6fbdda49d91af278488d904dcd7651b2693872f0ff94e40e84a/coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12", size = 220516, upload-time = "2026-02-09T12:57:44.215Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b8/9531944e16267e2735a30a9641ff49671f07e8138ecf1ca13db9fd2560c7/coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b", size = 261804, upload-time = "2026-02-09T12:57:45.989Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f3/e63df6d500314a2a60390d1989240d5f27318a7a68fa30ad3806e2a9323e/coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9", size = 263885, upload-time = "2026-02-09T12:57:47.42Z" }, - { url = "https://files.pythonhosted.org/packages/f3/67/7654810de580e14b37670b60a09c599fa348e48312db5b216d730857ffe6/coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092", size = 266308, upload-time = "2026-02-09T12:57:49.345Z" }, - { url = "https://files.pythonhosted.org/packages/37/6f/39d41eca0eab3cc82115953ad41c4e77935286c930e8fad15eaed1389d83/coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9", size = 267452, upload-time = "2026-02-09T12:57:50.811Z" }, - { url = "https://files.pythonhosted.org/packages/50/6d/39c0fbb8fc5cd4d2090811e553c2108cf5112e882f82505ee7495349a6bf/coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26", size = 261057, upload-time = "2026-02-09T12:57:52.447Z" }, - { url = "https://files.pythonhosted.org/packages/a4/a2/60010c669df5fa603bb5a97fb75407e191a846510da70ac657eb696b7fce/coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2", size = 263875, upload-time = "2026-02-09T12:57:53.938Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d9/63b22a6bdbd17f1f96e9ed58604c2a6b0e72a9133e37d663bef185877cf6/coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940", size = 261500, upload-time = "2026-02-09T12:57:56.012Z" }, - { url = "https://files.pythonhosted.org/packages/70/bf/69f86ba1ad85bc3ad240e4c0e57a2e620fbc0e1645a47b5c62f0e941ad7f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c", size = 265212, upload-time = "2026-02-09T12:57:57.5Z" }, - { url = "https://files.pythonhosted.org/packages/ae/f2/5f65a278a8c2148731831574c73e42f57204243d33bedaaf18fa79c5958f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0", size = 260398, upload-time = "2026-02-09T12:57:59.027Z" }, - { url = "https://files.pythonhosted.org/packages/ef/80/6e8280a350ee9fea92f14b8357448a242dcaa243cb2c72ab0ca591f66c8c/coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b", size = 262584, upload-time = "2026-02-09T12:58:01.129Z" }, - { url = "https://files.pythonhosted.org/packages/22/63/01ff182fc95f260b539590fb12c11ad3e21332c15f9799cb5e2386f71d9f/coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9", size = 222688, upload-time = "2026-02-09T12:58:02.736Z" }, - { url = "https://files.pythonhosted.org/packages/a9/43/89de4ef5d3cd53b886afa114065f7e9d3707bdb3e5efae13535b46ae483d/coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd", size = 223746, upload-time = "2026-02-09T12:58:05.362Z" }, - { url = "https://files.pythonhosted.org/packages/35/39/7cf0aa9a10d470a5309b38b289b9bb07ddeac5d61af9b664fe9775a4cb3e/coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997", size = 222003, upload-time = "2026-02-09T12:58:06.952Z" }, - { url = "https://files.pythonhosted.org/packages/92/11/a9cf762bb83386467737d32187756a42094927150c3e107df4cb078e8590/coverage-7.13.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:300deaee342f90696ed186e3a00c71b5b3d27bffe9e827677954f4ee56969601", size = 219522, upload-time = "2026-02-09T12:58:08.623Z" }, - { url = "https://files.pythonhosted.org/packages/d3/28/56e6d892b7b052236d67c95f1936b6a7cf7c3e2634bf27610b8cbd7f9c60/coverage-7.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29e3220258d682b6226a9b0925bc563ed9a1ebcff3cad30f043eceea7eaf2689", size = 219855, upload-time = "2026-02-09T12:58:10.176Z" }, - { url = "https://files.pythonhosted.org/packages/e5/69/233459ee9eb0c0d10fcc2fe425a029b3fa5ce0f040c966ebce851d030c70/coverage-7.13.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:391ee8f19bef69210978363ca930f7328081c6a0152f1166c91f0b5fdd2a773c", size = 250887, upload-time = "2026-02-09T12:58:12.503Z" }, - { url = "https://files.pythonhosted.org/packages/06/90/2cdab0974b9b5bbc1623f7876b73603aecac11b8d95b85b5b86b32de5eab/coverage-7.13.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0dd7ab8278f0d58a0128ba2fca25824321f05d059c1441800e934ff2efa52129", size = 253396, upload-time = "2026-02-09T12:58:14.615Z" }, - { url = "https://files.pythonhosted.org/packages/ac/15/ea4da0f85bf7d7b27635039e649e99deb8173fe551096ea15017f7053537/coverage-7.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78cdf0d578b15148b009ccf18c686aa4f719d887e76e6b40c38ffb61d264a552", size = 254745, upload-time = "2026-02-09T12:58:16.162Z" }, - { url = "https://files.pythonhosted.org/packages/99/11/bb356e86920c655ca4d61daee4e2bbc7258f0a37de0be32d233b561134ff/coverage-7.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:48685fee12c2eb3b27c62f2658e7ea21e9c3239cba5a8a242801a0a3f6a8c62a", size = 257055, upload-time = "2026-02-09T12:58:17.892Z" }, - { url = "https://files.pythonhosted.org/packages/c9/0f/9ae1f8cb17029e09da06ca4e28c9e1d5c1c0a511c7074592e37e0836c915/coverage-7.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4e83efc079eb39480e6346a15a1bcb3e9b04759c5202d157e1dd4303cd619356", size = 250911, upload-time = "2026-02-09T12:58:19.495Z" }, - { url = "https://files.pythonhosted.org/packages/89/3a/adfb68558fa815cbc29747b553bc833d2150228f251b127f1ce97e48547c/coverage-7.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecae9737b72408d6a950f7e525f30aca12d4bd8dd95e37342e5beb3a2a8c4f71", size = 252754, upload-time = "2026-02-09T12:58:21.064Z" }, - { url = "https://files.pythonhosted.org/packages/32/b1/540d0c27c4e748bd3cd0bd001076ee416eda993c2bae47a73b7cc9357931/coverage-7.13.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae4578f8528569d3cf303fef2ea569c7f4c4059a38c8667ccef15c6e1f118aa5", size = 250720, upload-time = "2026-02-09T12:58:22.622Z" }, - { url = "https://files.pythonhosted.org/packages/c7/95/383609462b3ffb1fe133014a7c84fc0dd01ed55ac6140fa1093b5af7ebb1/coverage-7.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6fdef321fdfbb30a197efa02d48fcd9981f0d8ad2ae8903ac318adc653f5df98", size = 254994, upload-time = "2026-02-09T12:58:24.548Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ba/1761138e86c81680bfc3c49579d66312865457f9fe405b033184e5793cb3/coverage-7.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b0f6ccf3dbe577170bebfce1318707d0e8c3650003cb4b3a9dd744575daa8b5", size = 250531, upload-time = "2026-02-09T12:58:26.271Z" }, - { url = "https://files.pythonhosted.org/packages/f8/8e/05900df797a9c11837ab59c4d6fe94094e029582aab75c3309a93e6fb4e3/coverage-7.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75fcd519f2a5765db3f0e391eb3b7d150cce1a771bf4c9f861aeab86c767a3c0", size = 252189, upload-time = "2026-02-09T12:58:27.807Z" }, - { url = "https://files.pythonhosted.org/packages/00/bd/29c9f2db9ea4ed2738b8a9508c35626eb205d51af4ab7bf56a21a2e49926/coverage-7.13.4-cp314-cp314-win32.whl", hash = "sha256:8e798c266c378da2bd819b0677df41ab46d78065fb2a399558f3f6cae78b2fbb", size = 222258, upload-time = "2026-02-09T12:58:29.441Z" }, - { url = "https://files.pythonhosted.org/packages/a7/4d/1f8e723f6829977410efeb88f73673d794075091c8c7c18848d273dc9d73/coverage-7.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:245e37f664d89861cf2329c9afa2c1fe9e6d4e1a09d872c947e70718aeeac505", size = 223073, upload-time = "2026-02-09T12:58:31.026Z" }, - { url = "https://files.pythonhosted.org/packages/51/5b/84100025be913b44e082ea32abcf1afbf4e872f5120b7a1cab1d331b1e13/coverage-7.13.4-cp314-cp314-win_arm64.whl", hash = "sha256:ad27098a189e5838900ce4c2a99f2fe42a0bf0c2093c17c69b45a71579e8d4a2", size = 221638, upload-time = "2026-02-09T12:58:32.599Z" }, - { url = "https://files.pythonhosted.org/packages/a7/e4/c884a405d6ead1370433dad1e3720216b4f9fd8ef5b64bfd984a2a60a11a/coverage-7.13.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:85480adfb35ffc32d40918aad81b89c69c9cc5661a9b8a81476d3e645321a056", size = 220246, upload-time = "2026-02-09T12:58:34.181Z" }, - { url = "https://files.pythonhosted.org/packages/81/5c/4d7ed8b23b233b0fffbc9dfec53c232be2e695468523242ea9fd30f97ad2/coverage-7.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:79be69cf7f3bf9b0deeeb062eab7ac7f36cd4cc4c4dd694bd28921ba4d8596cc", size = 220514, upload-time = "2026-02-09T12:58:35.704Z" }, - { url = "https://files.pythonhosted.org/packages/2f/6f/3284d4203fd2f28edd73034968398cd2d4cb04ab192abc8cff007ea35679/coverage-7.13.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:caa421e2684e382c5d8973ac55e4f36bed6821a9bad5c953494de960c74595c9", size = 261877, upload-time = "2026-02-09T12:58:37.864Z" }, - { url = "https://files.pythonhosted.org/packages/09/aa/b672a647bbe1556a85337dc95bfd40d146e9965ead9cc2fe81bde1e5cbce/coverage-7.13.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14375934243ee05f56c45393fe2ce81fe5cc503c07cee2bdf1725fb8bef3ffaf", size = 264004, upload-time = "2026-02-09T12:58:39.492Z" }, - { url = "https://files.pythonhosted.org/packages/79/a1/aa384dbe9181f98bba87dd23dda436f0c6cf2e148aecbb4e50fc51c1a656/coverage-7.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25a41c3104d08edb094d9db0d905ca54d0cd41c928bb6be3c4c799a54753af55", size = 266408, upload-time = "2026-02-09T12:58:41.852Z" }, - { url = "https://files.pythonhosted.org/packages/53/5e/5150bf17b4019bc600799f376bb9606941e55bd5a775dc1e096b6ffea952/coverage-7.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f01afcff62bf9a08fb32b2c1d6e924236c0383c02c790732b6537269e466a72", size = 267544, upload-time = "2026-02-09T12:58:44.093Z" }, - { url = "https://files.pythonhosted.org/packages/e0/ed/f1de5c675987a4a7a672250d2c5c9d73d289dbf13410f00ed7181d8017dd/coverage-7.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eb9078108fbf0bcdde37c3f4779303673c2fa1fe8f7956e68d447d0dd426d38a", size = 260980, upload-time = "2026-02-09T12:58:45.721Z" }, - { url = "https://files.pythonhosted.org/packages/b3/e3/fe758d01850aa172419a6743fe76ba8b92c29d181d4f676ffe2dae2ba631/coverage-7.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e086334e8537ddd17e5f16a344777c1ab8194986ec533711cbe6c41cde841b6", size = 263871, upload-time = "2026-02-09T12:58:47.334Z" }, - { url = "https://files.pythonhosted.org/packages/b6/76/b829869d464115e22499541def9796b25312b8cf235d3bb00b39f1675395/coverage-7.13.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:725d985c5ab621268b2edb8e50dfe57633dc69bda071abc470fed55a14935fd3", size = 261472, upload-time = "2026-02-09T12:58:48.995Z" }, - { url = "https://files.pythonhosted.org/packages/14/9e/caedb1679e73e2f6ad240173f55218488bfe043e38da577c4ec977489915/coverage-7.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3c06f0f1337c667b971ca2f975523347e63ec5e500b9aa5882d91931cd3ef750", size = 265210, upload-time = "2026-02-09T12:58:51.178Z" }, - { url = "https://files.pythonhosted.org/packages/3a/10/0dd02cb009b16ede425b49ec344aba13a6ae1dc39600840ea6abcb085ac4/coverage-7.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:590c0ed4bf8e85f745e6b805b2e1c457b2e33d5255dd9729743165253bc9ad39", size = 260319, upload-time = "2026-02-09T12:58:53.081Z" }, - { url = "https://files.pythonhosted.org/packages/92/8e/234d2c927af27c6d7a5ffad5bd2cf31634c46a477b4c7adfbfa66baf7ebb/coverage-7.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eb30bf180de3f632cd043322dad5751390e5385108b2807368997d1a92a509d0", size = 262638, upload-time = "2026-02-09T12:58:55.258Z" }, - { url = "https://files.pythonhosted.org/packages/2f/64/e5547c8ff6964e5965c35a480855911b61509cce544f4d442caa759a0702/coverage-7.13.4-cp314-cp314t-win32.whl", hash = "sha256:c4240e7eded42d131a2d2c4dec70374b781b043ddc79a9de4d55ca71f8e98aea", size = 223040, upload-time = "2026-02-09T12:58:56.936Z" }, - { url = "https://files.pythonhosted.org/packages/c7/96/38086d58a181aac86d503dfa9c47eb20715a79c3e3acbdf786e92e5c09a8/coverage-7.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4c7d3cc01e7350f2f0f6f7036caaf5673fb56b6998889ccfe9e1c1fe75a9c932", size = 224148, upload-time = "2026-02-09T12:58:58.645Z" }, - { url = "https://files.pythonhosted.org/packages/ce/72/8d10abd3740a0beb98c305e0c3faf454366221c0f37a8bcf8f60020bb65a/coverage-7.13.4-cp314-cp314t-win_arm64.whl", hash = "sha256:23e3f687cf945070d1c90f85db66d11e3025665d8dafa831301a0e0038f3db9b", size = 222172, upload-time = "2026-02-09T12:59:00.396Z" }, - { url = "https://files.pythonhosted.org/packages/0d/4a/331fe2caf6799d591109bb9c08083080f6de90a823695d412a935622abb2/coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0", size = 211242, upload-time = "2026-02-09T12:59:02.032Z" }, +version = "7.13.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967, upload-time = "2026-03-17T10:33:18.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/77/39703f0d1d4b478bfd30191d3c14f53caf596fac00efb3f8f6ee23646439/coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f", size = 219621, upload-time = "2026-03-17T10:32:08.589Z" }, + { url = "https://files.pythonhosted.org/packages/e2/3e/51dff36d99ae14639a133d9b164d63e628532e2974d8b1edb99dd1ebc733/coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e", size = 219953, upload-time = "2026-03-17T10:32:10.507Z" }, + { url = "https://files.pythonhosted.org/packages/6a/6c/1f1917b01eb647c2f2adc9962bd66c79eb978951cab61bdc1acab3290c07/coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a", size = 250992, upload-time = "2026-03-17T10:32:12.41Z" }, + { url = "https://files.pythonhosted.org/packages/22/e5/06b1f88f42a5a99df42ce61208bdec3bddb3d261412874280a19796fc09c/coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510", size = 253503, upload-time = "2026-03-17T10:32:14.449Z" }, + { url = "https://files.pythonhosted.org/packages/80/28/2a148a51e5907e504fa7b85490277734e6771d8844ebcc48764a15e28155/coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247", size = 254852, upload-time = "2026-03-17T10:32:16.56Z" }, + { url = "https://files.pythonhosted.org/packages/61/77/50e8d3d85cc0b7ebe09f30f151d670e302c7ff4a1bf6243f71dd8b0981fa/coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6", size = 257161, upload-time = "2026-03-17T10:32:19.004Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c4/b5fd1d4b7bf8d0e75d997afd3925c59ba629fc8616f1b3aae7605132e256/coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0", size = 251021, upload-time = "2026-03-17T10:32:21.344Z" }, + { url = "https://files.pythonhosted.org/packages/f8/66/6ea21f910e92d69ef0b1c3346ea5922a51bad4446c9126db2ae96ee24c4c/coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882", size = 252858, upload-time = "2026-03-17T10:32:23.506Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ea/879c83cb5d61aa2a35fb80e72715e92672daef8191b84911a643f533840c/coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740", size = 250823, upload-time = "2026-03-17T10:32:25.516Z" }, + { url = "https://files.pythonhosted.org/packages/8a/fb/616d95d3adb88b9803b275580bdeee8bd1b69a886d057652521f83d7322f/coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16", size = 255099, upload-time = "2026-03-17T10:32:27.944Z" }, + { url = "https://files.pythonhosted.org/packages/1c/93/25e6917c90ec1c9a56b0b26f6cad6408e5f13bb6b35d484a0d75c9cf000d/coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0", size = 250638, upload-time = "2026-03-17T10:32:29.914Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7b/dc1776b0464145a929deed214aef9fb1493f159b59ff3c7eeeedf91eddd0/coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0", size = 252295, upload-time = "2026-03-17T10:32:31.981Z" }, + { url = "https://files.pythonhosted.org/packages/ea/fb/99cbbc56a26e07762a2740713f3c8f9f3f3106e3a3dd8cc4474954bccd34/coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc", size = 222360, upload-time = "2026-03-17T10:32:34.233Z" }, + { url = "https://files.pythonhosted.org/packages/8d/b7/4758d4f73fb536347cc5e4ad63662f9d60ba9118cb6785e9616b2ce5d7fa/coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633", size = 223174, upload-time = "2026-03-17T10:32:36.369Z" }, + { url = "https://files.pythonhosted.org/packages/2c/f2/24d84e1dfe70f8ac9fdf30d338239860d0d1d5da0bda528959d0ebc9da28/coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8", size = 221739, upload-time = "2026-03-17T10:32:38.736Z" }, + { url = "https://files.pythonhosted.org/packages/60/5b/4a168591057b3668c2428bff25dd3ebc21b629d666d90bcdfa0217940e84/coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b", size = 220351, upload-time = "2026-03-17T10:32:41.196Z" }, + { url = "https://files.pythonhosted.org/packages/f5/21/1fd5c4dbfe4a58b6b99649125635df46decdfd4a784c3cd6d410d303e370/coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c", size = 220612, upload-time = "2026-03-17T10:32:43.204Z" }, + { url = "https://files.pythonhosted.org/packages/d6/fe/2a924b3055a5e7e4512655a9d4609781b0d62334fa0140c3e742926834e2/coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9", size = 261985, upload-time = "2026-03-17T10:32:45.514Z" }, + { url = "https://files.pythonhosted.org/packages/d7/0d/c8928f2bd518c45990fe1a2ab8db42e914ef9b726c975facc4282578c3eb/coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29", size = 264107, upload-time = "2026-03-17T10:32:47.971Z" }, + { url = "https://files.pythonhosted.org/packages/ef/ae/4ae35bbd9a0af9d820362751f0766582833c211224b38665c0f8de3d487f/coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607", size = 266513, upload-time = "2026-03-17T10:32:50.1Z" }, + { url = "https://files.pythonhosted.org/packages/9c/20/d326174c55af36f74eac6ae781612d9492f060ce8244b570bb9d50d9d609/coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90", size = 267650, upload-time = "2026-03-17T10:32:52.391Z" }, + { url = "https://files.pythonhosted.org/packages/7a/5e/31484d62cbd0eabd3412e30d74386ece4a0837d4f6c3040a653878bfc019/coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3", size = 261089, upload-time = "2026-03-17T10:32:54.544Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d8/49a72d6de146eebb0b7e48cc0f4bc2c0dd858e3d4790ab2b39a2872b62bd/coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab", size = 263982, upload-time = "2026-03-17T10:32:56.803Z" }, + { url = "https://files.pythonhosted.org/packages/06/3b/0351f1bd566e6e4dd39e978efe7958bde1d32f879e85589de147654f57bb/coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562", size = 261579, upload-time = "2026-03-17T10:32:59.466Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ce/796a2a2f4017f554d7810f5c573449b35b1e46788424a548d4d19201b222/coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2", size = 265316, upload-time = "2026-03-17T10:33:01.847Z" }, + { url = "https://files.pythonhosted.org/packages/3d/16/d5ae91455541d1a78bc90abf495be600588aff8f6db5c8b0dae739fa39c9/coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea", size = 260427, upload-time = "2026-03-17T10:33:03.945Z" }, + { url = "https://files.pythonhosted.org/packages/48/11/07f413dba62db21fb3fad5d0de013a50e073cc4e2dc4306e770360f6dfc8/coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a", size = 262745, upload-time = "2026-03-17T10:33:06.285Z" }, + { url = "https://files.pythonhosted.org/packages/91/15/d792371332eb4663115becf4bad47e047d16234b1aff687b1b18c58d60ae/coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215", size = 223146, upload-time = "2026-03-17T10:33:08.756Z" }, + { url = "https://files.pythonhosted.org/packages/db/51/37221f59a111dca5e85be7dbf09696323b5b9f13ff65e0641d535ed06ea8/coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43", size = 224254, upload-time = "2026-03-17T10:33:11.174Z" }, + { url = "https://files.pythonhosted.org/packages/54/83/6acacc889de8987441aa7d5adfbdbf33d288dad28704a67e574f1df9bcbb/coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45", size = 222276, upload-time = "2026-03-17T10:33:13.466Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" }, ] [[package]] name = "cryptography" -version = "46.0.5" +version = "46.0.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" }, - { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" }, - { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" }, - { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" }, - { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" }, - { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" }, - { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" }, - { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" }, - { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" }, - { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" }, - { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" }, - { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" }, - { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" }, - { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" }, - { url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287, upload-time = "2026-02-10T19:17:33.801Z" }, - { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" }, - { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" }, - { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload-time = "2026-02-10T19:17:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" }, - { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" }, - { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload-time = "2026-02-10T19:17:46.997Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" }, - { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" }, - { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" }, - { url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637, upload-time = "2026-02-10T19:17:52.997Z" }, - { url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487, upload-time = "2026-02-10T19:17:54.549Z" }, - { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" }, - { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" }, - { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" }, - { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" }, - { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" }, - { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" }, - { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" }, - { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" }, - { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" }, - { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" }, - { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" }, - { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" }, - { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" }, - { url = "https://files.pythonhosted.org/packages/eb/dd/2d9fdb07cebdf3d51179730afb7d5e576153c6744c3ff8fded23030c204e/cryptography-46.0.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c", size = 3476964, upload-time = "2026-02-10T19:18:20.687Z" }, - { url = "https://files.pythonhosted.org/packages/e9/6f/6cc6cc9955caa6eaf83660b0da2b077c7fe8ff9950a3c5e45d605038d439/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a", size = 4218321, upload-time = "2026-02-10T19:18:22.349Z" }, - { url = "https://files.pythonhosted.org/packages/3e/5d/c4da701939eeee699566a6c1367427ab91a8b7088cc2328c09dbee940415/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356", size = 4381786, upload-time = "2026-02-10T19:18:24.529Z" }, - { url = "https://files.pythonhosted.org/packages/ac/97/a538654732974a94ff96c1db621fa464f455c02d4bb7d2652f4edc21d600/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da", size = 4217990, upload-time = "2026-02-10T19:18:25.957Z" }, - { url = "https://files.pythonhosted.org/packages/ae/11/7e500d2dd3ba891197b9efd2da5454b74336d64a7cc419aa7327ab74e5f6/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257", size = 4381252, upload-time = "2026-02-10T19:18:27.496Z" }, - { url = "https://files.pythonhosted.org/packages/bc/58/6b3d24e6b9bc474a2dcdee65dfd1f008867015408a271562e4b690561a4d/cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7", size = 3407605, upload-time = "2026-02-10T19:18:29.233Z" }, -] - -[[package]] -name = "cssselect" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/2e/cdfd8b01c37cbf4f9482eefd455853a3cf9c995029a46acd31dfaa9c1dd6/cssselect-1.4.0.tar.gz", hash = "sha256:fdaf0a1425e17dfe8c5cf66191d211b357cf7872ae8afc4c6762ddd8ac47fc92", size = 40589, upload-time = "2026-01-29T07:00:26.701Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/0c/7bb51e3acfafd16c48875bf3db03607674df16f5b6ef8d056586af7e2b8b/cssselect-1.4.0-py3-none-any.whl", hash = "sha256:c0ec5c0191c8ee39fcc8afc1540331d8b55b0183478c50e9c8a79d44dbceb1d8", size = 18540, upload-time = "2026-01-29T07:00:24.994Z" }, -] - -[[package]] -name = "cssutils" -version = "2.11.1" +] +sdist = { url = "https://files.pythonhosted.org/packages/a4/ba/04b1bd4218cbc58dc90ce967106d51582371b898690f3ae0402876cc4f34/cryptography-46.0.6.tar.gz", hash = "sha256:27550628a518c5c6c903d84f637fbecf287f6cb9ced3804838a1295dc1fd0759", size = 750542, upload-time = "2026-03-25T23:34:53.396Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/23/9285e15e3bc57325b0a72e592921983a701efc1ee8f91c06c5f0235d86d9/cryptography-46.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:64235194bad039a10bb6d2d930ab3323baaec67e2ce36215fd0952fad0930ca8", size = 7176401, upload-time = "2026-03-25T23:33:22.096Z" }, + { url = "https://files.pythonhosted.org/packages/60/f8/e61f8f13950ab6195b31913b42d39f0f9afc7d93f76710f299b5ec286ae6/cryptography-46.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:26031f1e5ca62fcb9d1fcb34b2b60b390d1aacaa15dc8b895a9ed00968b97b30", size = 4275275, upload-time = "2026-03-25T23:33:23.844Z" }, + { url = "https://files.pythonhosted.org/packages/19/69/732a736d12c2631e140be2348b4ad3d226302df63ef64d30dfdb8db7ad1c/cryptography-46.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9a693028b9cbe51b5a1136232ee8f2bc242e4e19d456ded3fa7c86e43c713b4a", size = 4425320, upload-time = "2026-03-25T23:33:25.703Z" }, + { url = "https://files.pythonhosted.org/packages/d4/12/123be7292674abf76b21ac1fc0e1af50661f0e5b8f0ec8285faac18eb99e/cryptography-46.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:67177e8a9f421aa2d3a170c3e56eca4e0128883cf52a071a7cbf53297f18b175", size = 4278082, upload-time = "2026-03-25T23:33:27.423Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ba/d5e27f8d68c24951b0a484924a84c7cdaed7502bac9f18601cd357f8b1d2/cryptography-46.0.6-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:d9528b535a6c4f8ff37847144b8986a9a143585f0540fbcb1a98115b543aa463", size = 4926514, upload-time = "2026-03-25T23:33:29.206Z" }, + { url = "https://files.pythonhosted.org/packages/34/71/1ea5a7352ae516d5512d17babe7e1b87d9db5150b21f794b1377eac1edc0/cryptography-46.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:22259338084d6ae497a19bae5d4c66b7ca1387d3264d1c2c0e72d9e9b6a77b97", size = 4457766, upload-time = "2026-03-25T23:33:30.834Z" }, + { url = "https://files.pythonhosted.org/packages/01/59/562be1e653accee4fdad92c7a2e88fced26b3fdfce144047519bbebc299e/cryptography-46.0.6-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:760997a4b950ff00d418398ad73fbc91aa2894b5c1db7ccb45b4f68b42a63b3c", size = 3986535, upload-time = "2026-03-25T23:33:33.02Z" }, + { url = "https://files.pythonhosted.org/packages/d6/8b/b1ebfeb788bf4624d36e45ed2662b8bd43a05ff62157093c1539c1288a18/cryptography-46.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3dfa6567f2e9e4c5dceb8ccb5a708158a2a871052fa75c8b78cb0977063f1507", size = 4277618, upload-time = "2026-03-25T23:33:34.567Z" }, + { url = "https://files.pythonhosted.org/packages/dd/52/a005f8eabdb28df57c20f84c44d397a755782d6ff6d455f05baa2785bd91/cryptography-46.0.6-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:cdcd3edcbc5d55757e5f5f3d330dd00007ae463a7e7aa5bf132d1f22a4b62b19", size = 4890802, upload-time = "2026-03-25T23:33:37.034Z" }, + { url = "https://files.pythonhosted.org/packages/ec/4d/8e7d7245c79c617d08724e2efa397737715ca0ec830ecb3c91e547302555/cryptography-46.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:d4e4aadb7fc1f88687f47ca20bb7227981b03afaae69287029da08096853b738", size = 4457425, upload-time = "2026-03-25T23:33:38.904Z" }, + { url = "https://files.pythonhosted.org/packages/1d/5c/f6c3596a1430cec6f949085f0e1a970638d76f81c3ea56d93d564d04c340/cryptography-46.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2b417edbe8877cda9022dde3a008e2deb50be9c407eef034aeeb3a8b11d9db3c", size = 4405530, upload-time = "2026-03-25T23:33:40.842Z" }, + { url = "https://files.pythonhosted.org/packages/7e/c9/9f9cea13ee2dbde070424e0c4f621c091a91ffcc504ffea5e74f0e1daeff/cryptography-46.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:380343e0653b1c9d7e1f55b52aaa2dbb2fdf2730088d48c43ca1c7c0abb7cc2f", size = 4667896, upload-time = "2026-03-25T23:33:42.781Z" }, + { url = "https://files.pythonhosted.org/packages/ad/b5/1895bc0821226f129bc74d00eccfc6a5969e2028f8617c09790bf89c185e/cryptography-46.0.6-cp311-abi3-win32.whl", hash = "sha256:bcb87663e1f7b075e48c3be3ecb5f0b46c8fc50b50a97cf264e7f60242dca3f2", size = 3026348, upload-time = "2026-03-25T23:33:45.021Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f8/c9bcbf0d3e6ad288b9d9aa0b1dee04b063d19e8c4f871855a03ab3a297ab/cryptography-46.0.6-cp311-abi3-win_amd64.whl", hash = "sha256:6739d56300662c468fddb0e5e291f9b4d084bead381667b9e654c7dd81705124", size = 3483896, upload-time = "2026-03-25T23:33:46.649Z" }, + { url = "https://files.pythonhosted.org/packages/01/41/3a578f7fd5c70611c0aacba52cd13cb364a5dee895a5c1d467208a9380b0/cryptography-46.0.6-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:2ef9e69886cbb137c2aef9772c2e7138dc581fad4fcbcf13cc181eb5a3ab6275", size = 7117147, upload-time = "2026-03-25T23:33:48.249Z" }, + { url = "https://files.pythonhosted.org/packages/fa/87/887f35a6fca9dde90cad08e0de0c89263a8e59b2d2ff904fd9fcd8025b6f/cryptography-46.0.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7f417f034f91dcec1cb6c5c35b07cdbb2ef262557f701b4ecd803ee8cefed4f4", size = 4266221, upload-time = "2026-03-25T23:33:49.874Z" }, + { url = "https://files.pythonhosted.org/packages/aa/a8/0a90c4f0b0871e0e3d1ed126aed101328a8a57fd9fd17f00fb67e82a51ca/cryptography-46.0.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d24c13369e856b94892a89ddf70b332e0b70ad4a5c43cf3e9cb71d6d7ffa1f7b", size = 4408952, upload-time = "2026-03-25T23:33:52.128Z" }, + { url = "https://files.pythonhosted.org/packages/16/0b/b239701eb946523e4e9f329336e4ff32b1247e109cbab32d1a7b61da8ed7/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:aad75154a7ac9039936d50cf431719a2f8d4ed3d3c277ac03f3339ded1a5e707", size = 4270141, upload-time = "2026-03-25T23:33:54.11Z" }, + { url = "https://files.pythonhosted.org/packages/0f/a8/976acdd4f0f30df7b25605f4b9d3d89295351665c2091d18224f7ad5cdbf/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:3c21d92ed15e9cfc6eb64c1f5a0326db22ca9c2566ca46d845119b45b4400361", size = 4904178, upload-time = "2026-03-25T23:33:55.725Z" }, + { url = "https://files.pythonhosted.org/packages/b1/1b/bf0e01a88efd0e59679b69f42d4afd5bced8700bb5e80617b2d63a3741af/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:4668298aef7cddeaf5c6ecc244c2302a2b8e40f384255505c22875eebb47888b", size = 4441812, upload-time = "2026-03-25T23:33:57.364Z" }, + { url = "https://files.pythonhosted.org/packages/bb/8b/11df86de2ea389c65aa1806f331cae145f2ed18011f30234cc10ca253de8/cryptography-46.0.6-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:8ce35b77aaf02f3b59c90b2c8a05c73bac12cea5b4e8f3fbece1f5fddea5f0ca", size = 3963923, upload-time = "2026-03-25T23:33:59.361Z" }, + { url = "https://files.pythonhosted.org/packages/91/e0/207fb177c3a9ef6a8108f234208c3e9e76a6aa8cf20d51932916bd43bda0/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:c89eb37fae9216985d8734c1afd172ba4927f5a05cfd9bf0e4863c6d5465b013", size = 4269695, upload-time = "2026-03-25T23:34:00.909Z" }, + { url = "https://files.pythonhosted.org/packages/21/5e/19f3260ed1e95bced52ace7501fabcd266df67077eeb382b79c81729d2d3/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:ed418c37d095aeddf5336898a132fba01091f0ac5844e3e8018506f014b6d2c4", size = 4869785, upload-time = "2026-03-25T23:34:02.796Z" }, + { url = "https://files.pythonhosted.org/packages/10/38/cd7864d79aa1d92ef6f1a584281433419b955ad5a5ba8d1eb6c872165bcb/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:69cf0056d6947edc6e6760e5f17afe4bea06b56a9ac8a06de9d2bd6b532d4f3a", size = 4441404, upload-time = "2026-03-25T23:34:04.35Z" }, + { url = "https://files.pythonhosted.org/packages/09/0a/4fe7a8d25fed74419f91835cf5829ade6408fd1963c9eae9c4bce390ecbb/cryptography-46.0.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e7304c4f4e9490e11efe56af6713983460ee0780f16c63f219984dab3af9d2d", size = 4397549, upload-time = "2026-03-25T23:34:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a0/7d738944eac6513cd60a8da98b65951f4a3b279b93479a7e8926d9cd730b/cryptography-46.0.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b928a3ca837c77a10e81a814a693f2295200adb3352395fad024559b7be7a736", size = 4651874, upload-time = "2026-03-25T23:34:07.916Z" }, + { url = "https://files.pythonhosted.org/packages/cb/f1/c2326781ca05208845efca38bf714f76939ae446cd492d7613808badedf1/cryptography-46.0.6-cp314-cp314t-win32.whl", hash = "sha256:97c8115b27e19e592a05c45d0dd89c57f81f841cc9880e353e0d3bf25b2139ed", size = 3001511, upload-time = "2026-03-25T23:34:09.892Z" }, + { url = "https://files.pythonhosted.org/packages/c9/57/fe4a23eb549ac9d903bd4698ffda13383808ef0876cc912bcb2838799ece/cryptography-46.0.6-cp314-cp314t-win_amd64.whl", hash = "sha256:c797e2517cb7880f8297e2c0f43bb910e91381339336f75d2c1c2cbf811b70b4", size = 3471692, upload-time = "2026-03-25T23:34:11.613Z" }, + { url = "https://files.pythonhosted.org/packages/c4/cc/f330e982852403da79008552de9906804568ae9230da8432f7496ce02b71/cryptography-46.0.6-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:12cae594e9473bca1a7aceb90536060643128bb274fcea0fc459ab90f7d1ae7a", size = 7162776, upload-time = "2026-03-25T23:34:13.308Z" }, + { url = "https://files.pythonhosted.org/packages/49/b3/dc27efd8dcc4bff583b3f01d4a3943cd8b5821777a58b3a6a5f054d61b79/cryptography-46.0.6-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:639301950939d844a9e1c4464d7e07f902fe9a7f6b215bb0d4f28584729935d8", size = 4270529, upload-time = "2026-03-25T23:34:15.019Z" }, + { url = "https://files.pythonhosted.org/packages/e6/05/e8d0e6eb4f0d83365b3cb0e00eb3c484f7348db0266652ccd84632a3d58d/cryptography-46.0.6-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ed3775295fb91f70b4027aeba878d79b3e55c0b3e97eaa4de71f8f23a9f2eb77", size = 4414827, upload-time = "2026-03-25T23:34:16.604Z" }, + { url = "https://files.pythonhosted.org/packages/2f/97/daba0f5d2dc6d855e2dcb70733c812558a7977a55dd4a6722756628c44d1/cryptography-46.0.6-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8927ccfbe967c7df312ade694f987e7e9e22b2425976ddbf28271d7e58845290", size = 4271265, upload-time = "2026-03-25T23:34:18.586Z" }, + { url = "https://files.pythonhosted.org/packages/89/06/fe1fce39a37ac452e58d04b43b0855261dac320a2ebf8f5260dd55b201a9/cryptography-46.0.6-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b12c6b1e1651e42ab5de8b1e00dc3b6354fdfd778e7fa60541ddacc27cd21410", size = 4916800, upload-time = "2026-03-25T23:34:20.561Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8a/b14f3101fe9c3592603339eb5d94046c3ce5f7fc76d6512a2d40efd9724e/cryptography-46.0.6-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:063b67749f338ca9c5a0b7fe438a52c25f9526b851e24e6c9310e7195aad3b4d", size = 4448771, upload-time = "2026-03-25T23:34:22.406Z" }, + { url = "https://files.pythonhosted.org/packages/01/b3/0796998056a66d1973fd52ee89dc1bb3b6581960a91ad4ac705f182d398f/cryptography-46.0.6-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:02fad249cb0e090b574e30b276a3da6a149e04ee2f049725b1f69e7b8351ec70", size = 3978333, upload-time = "2026-03-25T23:34:24.281Z" }, + { url = "https://files.pythonhosted.org/packages/c5/3d/db200af5a4ffd08918cd55c08399dc6c9c50b0bc72c00a3246e099d3a849/cryptography-46.0.6-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:7e6142674f2a9291463e5e150090b95a8519b2fb6e6aaec8917dd8d094ce750d", size = 4271069, upload-time = "2026-03-25T23:34:25.895Z" }, + { url = "https://files.pythonhosted.org/packages/d7/18/61acfd5b414309d74ee838be321c636fe71815436f53c9f0334bf19064fa/cryptography-46.0.6-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:456b3215172aeefb9284550b162801d62f5f264a081049a3e94307fe20792cfa", size = 4878358, upload-time = "2026-03-25T23:34:27.67Z" }, + { url = "https://files.pythonhosted.org/packages/8b/65/5bf43286d566f8171917cae23ac6add941654ccf085d739195a4eacf1674/cryptography-46.0.6-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:341359d6c9e68834e204ceaf25936dffeafea3829ab80e9503860dcc4f4dac58", size = 4448061, upload-time = "2026-03-25T23:34:29.375Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/7e49c0fa7205cf3597e525d156a6bce5b5c9de1fd7e8cb01120e459f205a/cryptography-46.0.6-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9a9c42a2723999a710445bc0d974e345c32adfd8d2fac6d8a251fa829ad31cfb", size = 4399103, upload-time = "2026-03-25T23:34:32.036Z" }, + { url = "https://files.pythonhosted.org/packages/44/46/466269e833f1c4718d6cd496ffe20c56c9c8d013486ff66b4f69c302a68d/cryptography-46.0.6-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6617f67b1606dfd9fe4dbfa354a9508d4a6d37afe30306fe6c101b7ce3274b72", size = 4659255, upload-time = "2026-03-25T23:34:33.679Z" }, + { url = "https://files.pythonhosted.org/packages/0a/09/ddc5f630cc32287d2c953fc5d32705e63ec73e37308e5120955316f53827/cryptography-46.0.6-cp38-abi3-win32.whl", hash = "sha256:7f6690b6c55e9c5332c0b59b9c8a3fb232ebf059094c17f9019a51e9827df91c", size = 3010660, upload-time = "2026-03-25T23:34:35.418Z" }, + { url = "https://files.pythonhosted.org/packages/1b/82/ca4893968aeb2709aacfb57a30dec6fa2ab25b10fa9f064b8882ce33f599/cryptography-46.0.6-cp38-abi3-win_amd64.whl", hash = "sha256:79e865c642cfc5c0b3eb12af83c35c5aeff4fa5c672dc28c43721c2c9fdd2f0f", size = 3471160, upload-time = "2026-03-25T23:34:37.191Z" }, +] + +[[package]] +name = "dkimpy" +version = "1.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "more-itertools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/33/9f/329d26121fe165be44b1dfff21aa0dc348f04633931f1d20ed6cf448a236/cssutils-2.11.1.tar.gz", hash = "sha256:0563a76513b6af6eebbe788c3bf3d01c920e46b3f90c8416738c5cfc773ff8e2", size = 711657, upload-time = "2024-06-04T15:51:39.373Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/ec/bb273b7208c606890dc36540fe667d06ce840a6f62f9fae7e658fcdc90fb/cssutils-2.11.1-py3-none-any.whl", hash = "sha256:a67bfdfdff4f3867fab43698ec4897c1a828eca5973f4073321b3bccaf1199b1", size = 385747, upload-time = "2024-06-04T15:51:37.499Z" }, + { name = "dnspython" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/f0/6f/84e91828186bbfcedd7f9385ef5e0d369632444195c20e08951b7ffe0481/dkimpy-1.1.8.tar.gz", hash = "sha256:b5f60fb47bbf5d8d762f134bcea0c388eba6b498342a682a21f1686545094b77", size = 66979, upload-time = "2024-07-04T22:16:38.321Z" } [[package]] name = "dnspython" @@ -740,36 +500,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, ] -[[package]] -name = "docutils" -version = "0.21.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, -] - [[package]] name = "docutils" version = "0.22.4" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] sdist = { url = "https://files.pythonhosted.org/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968", size = 2291750, upload-time = "2025-12-18T19:00:26.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" }, @@ -780,8 +514,7 @@ name = "docutils-stubs" version = "0.0.22" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "docutils", version = "0.21.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "docutils" }, ] sdist = { url = "https://files.pythonhosted.org/packages/31/fb/3eda037eed8b98d6b2169e4198a8f12a03a461c4d4dc44de1a7790d0f7c7/docutils-stubs-0.0.22.tar.gz", hash = "sha256:1736d9650cfc20cff8c72582806c33a5c642694e2df9e430717e7da7e73efbdf", size = 43699, upload-time = "2022-01-02T11:13:17.499Z" } wheels = [ @@ -803,19 +536,16 @@ wheels = [ [[package]] name = "emails" -version = "0.6" +version = "1.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "chardet" }, - { name = "cssutils" }, - { name = "lxml" }, - { name = "premailer" }, + { name = "dkimpy" }, + { name = "puremagic" }, { name = "python-dateutil" }, - { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d3/f9/c1e315aa82ed9f037186c30109200fb4b4c51b5483b8065daa0ca836a336/emails-0.6.tar.gz", hash = "sha256:a4c2d67ea8b8831967a750d8edc6e77040d7693143fe280e6d2a367d9c36ff88", size = 44066, upload-time = "2020-06-19T11:20:41.644Z" } +sdist = { url = "https://files.pythonhosted.org/packages/47/a5/d5472729b4b56d3868776aef9b43b0803048cc53f8999f1a0f1b4d05c360/emails-1.1.1.tar.gz", hash = "sha256:f2ac9d73d84e83d7f1a3924837fa15b59c0bce9bf658ac3b0b80398bc6d8b57d", size = 37160, upload-time = "2026-04-02T17:26:44.807Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/7e/b648d640d88d31de49e566832aca9cce025c52d6349b0a0fc65e9df1f4c5/emails-0.6-py2.py3-none-any.whl", hash = "sha256:72c1e3198075709cc35f67e1b49e2da1a2bc087e9b444073db61a379adfb7f3c", size = 56250, upload-time = "2020-06-19T11:20:40.466Z" }, + { url = "https://files.pythonhosted.org/packages/32/60/fe7f7e4240446400a1cd3358d38887132e34c1abdfdb457ce5acfd108090/emails-1.1.1-py3-none-any.whl", hash = "sha256:927079dc5c8aec755d017171510c78c0ba56a9f5bf47b0ea82b785f700b43469", size = 42915, upload-time = "2026-04-02T17:26:43.314Z" }, ] [[package]] @@ -827,73 +557,64 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, ] -[[package]] -name = "exceptiongroup" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, -] - [[package]] name = "fastapi" -version = "0.115.14" +version = "0.135.3" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "annotated-doc" }, { name = "pydantic" }, { name = "starlette" }, { name = "typing-extensions" }, + { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ca/53/8c38a874844a8b0fa10dd8adf3836ac154082cf88d3f22b544e9ceea0a15/fastapi-0.115.14.tar.gz", hash = "sha256:b1de15cdc1c499a4da47914db35d0e4ef8f1ce62b624e94e0e5824421df99739", size = 296263, upload-time = "2025-06-26T15:29:08.21Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/e6/7adb4c5fa231e82c35b8f5741a9f2d055f520c29af5546fd70d3e8e1cd2e/fastapi-0.135.3.tar.gz", hash = "sha256:bd6d7caf1a2bdd8d676843cdcd2287729572a1ef524fc4d65c17ae002a1be654", size = 396524, upload-time = "2026-04-01T16:23:58.188Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/53/50/b1222562c6d270fea83e9c9075b8e8600b8479150a18e4516a6138b980d1/fastapi-0.115.14-py3-none-any.whl", hash = "sha256:6c0c8bf9420bd58f565e585036d971872472b4f7d3f6c73b698e10cffdefb3ca", size = 95514, upload-time = "2025-06-26T15:29:06.49Z" }, + { url = "https://files.pythonhosted.org/packages/84/a4/5caa2de7f917a04ada20018eccf60d6cc6145b0199d55ca3711b0fc08312/fastapi-0.135.3-py3-none-any.whl", hash = "sha256:9b0f590c813acd13d0ab43dd8494138eb58e484bfac405db1f3187cfc5810d98", size = 117734, upload-time = "2026-04-01T16:23:59.328Z" }, ] [package.optional-dependencies] -standard = [ +standard-no-fastapi-cloud-cli = [ { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, + { name = "fastapi-cli", extra = ["standard-no-fastapi-cloud-cli"] }, { name = "httpx" }, { name = "jinja2" }, + { name = "pydantic-extra-types" }, + { name = "pydantic-settings" }, { name = "python-multipart" }, { name = "uvicorn", extra = ["standard"] }, ] [[package]] name = "fastapi-cli" -version = "0.0.7" +version = "0.0.24" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "rich-toolkit" }, { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fe/73/82a5831fbbf8ed75905bacf5b2d9d3dfd6f04d6968b29fe6f72a5ae9ceb1/fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e", size = 16753, upload-time = "2024-12-15T14:28:10.028Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/58/74797ae9e4610cfa0c6b34c8309096d3b20bb29be3b8b5fbf1004d10fa5f/fastapi_cli-0.0.24.tar.gz", hash = "sha256:1afc9c9e21d7ebc8a3ca5e31790cd8d837742be7e4f8b9236e99cb3451f0de00", size = 19043, upload-time = "2026-02-24T10:45:10.476Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705, upload-time = "2024-12-15T14:28:06.18Z" }, + { url = "https://files.pythonhosted.org/packages/c7/4b/68f9fe268e535d79c76910519530026a4f994ce07189ac0dded45c6af825/fastapi_cli-0.0.24-py3-none-any.whl", hash = "sha256:4a1f78ed798f106b4fee85ca93b85d8fe33c0a3570f775964d37edb80b8f0edc", size = 12304, upload-time = "2026-02-24T10:45:09.552Z" }, ] [package.optional-dependencies] -standard = [ +standard-no-fastapi-cloud-cli = [ { name = "uvicorn", extra = ["standard"] }, ] [[package]] name = "google-auth" -version = "2.49.0" +version = "2.49.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, { name = "pyasn1-modules" }, - { name = "rsa" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7d/59/7371175bfd949abfb1170aa076352131d7281bd9449c0f978604fc4431c3/google_auth-2.49.0.tar.gz", hash = "sha256:9cc2d9259d3700d7a257681f81052db6737495a1a46b610597f4b8bafe5286ae", size = 333444, upload-time = "2026-03-06T21:53:06.07Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/80/6a696a07d3d3b0a92488933532f03dbefa4a24ab80fb231395b9a2a1be77/google_auth-2.49.1.tar.gz", hash = "sha256:16d40da1c3c5a0533f57d268fe72e0ebb0ae1cc3b567024122651c045d879b64", size = 333825, upload-time = "2026-03-12T19:30:58.135Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/37/45/de64b823b639103de4b63dd193480dce99526bd36be6530c2dba85bf7817/google_auth-2.49.0-py3-none-any.whl", hash = "sha256:f893ef7307f19cf53700b7e2f61b5a6affe3aa0edf9943b13788920ab92d8d87", size = 240676, upload-time = "2026-03-06T21:52:38.304Z" }, + { url = "https://files.pythonhosted.org/packages/e9/eb/c6c2478d8a8d633460be40e2a8a6f8f429171997a35a96f81d3b680dec83/google_auth-2.49.1-py3-none-any.whl", hash = "sha256:195ebe3dca18eddd1b3db5edc5189b76c13e96f29e73043b923ebcf3f1a860f7", size = 240737, upload-time = "2026-03-12T19:30:53.159Z" }, ] [[package]] @@ -902,37 +623,6 @@ version = "3.3.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a3/51/1664f6b78fc6ebbd98019a1fd730e83fa78f2db7058f72b1463d3612b8db/greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2", size = 188267, upload-time = "2026-02-20T20:54:15.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/3f/9859f655d11901e7b2996c6e3d33e0caa9a1d4572c3bc61ed0faa64b2f4c/greenlet-3.3.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9bc885b89709d901859cf95179ec9f6bb67a3d2bb1f0e88456461bd4b7f8fd0d", size = 277747, upload-time = "2026-02-20T20:16:21.325Z" }, - { url = "https://files.pythonhosted.org/packages/fb/07/cb284a8b5c6498dbd7cba35d31380bb123d7dceaa7907f606c8ff5993cbf/greenlet-3.3.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b568183cf65b94919be4438dc28416b234b678c608cafac8874dfeeb2a9bbe13", size = 579202, upload-time = "2026-02-20T20:47:28.955Z" }, - { url = "https://files.pythonhosted.org/packages/ed/45/67922992b3a152f726163b19f890a85129a992f39607a2a53155de3448b8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:527fec58dc9f90efd594b9b700662ed3fb2493c2122067ac9c740d98080a620e", size = 590620, upload-time = "2026-02-20T20:55:55.581Z" }, - { url = "https://files.pythonhosted.org/packages/ad/55/9f1ebb5a825215fadcc0f7d5073f6e79e3007e3282b14b22d6aba7ca6cb8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad0c8917dd42a819fe77e6bdfcb84e3379c0de956469301d9fd36427a1ca501f", size = 591729, upload-time = "2026-02-20T20:20:58.395Z" }, - { url = "https://files.pythonhosted.org/packages/24/b4/21f5455773d37f94b866eb3cf5caed88d6cea6dd2c6e1f9c34f463cba3ec/greenlet-3.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:97245cc10e5515dbc8c3104b2928f7f02b6813002770cfaffaf9a6e0fc2b94ef", size = 1551946, upload-time = "2026-02-20T20:49:31.102Z" }, - { url = "https://files.pythonhosted.org/packages/00/68/91f061a926abead128fe1a87f0b453ccf07368666bd59ffa46016627a930/greenlet-3.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8c1fdd7d1b309ff0da81d60a9688a8bd044ac4e18b250320a96fc68d31c209ca", size = 1618494, upload-time = "2026-02-20T20:21:06.541Z" }, - { url = "https://files.pythonhosted.org/packages/ac/78/f93e840cbaef8becaf6adafbaf1319682a6c2d8c1c20224267a5c6c8c891/greenlet-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:5d0e35379f93a6d0222de929a25ab47b5eb35b5ef4721c2b9cbcc4036129ff1f", size = 230092, upload-time = "2026-02-20T20:17:09.379Z" }, - { url = "https://files.pythonhosted.org/packages/f3/47/16400cb42d18d7a6bb46f0626852c1718612e35dcb0dffa16bbaffdf5dd2/greenlet-3.3.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:c56692189a7d1c7606cb794be0a8381470d95c57ce5be03fb3d0ef57c7853b86", size = 278890, upload-time = "2026-02-20T20:19:39.263Z" }, - { url = "https://files.pythonhosted.org/packages/a3/90/42762b77a5b6aa96cd8c0e80612663d39211e8ae8a6cd47c7f1249a66262/greenlet-3.3.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ebd458fa8285960f382841da585e02201b53a5ec2bac6b156fc623b5ce4499f", size = 581120, upload-time = "2026-02-20T20:47:30.161Z" }, - { url = "https://files.pythonhosted.org/packages/bf/6f/f3d64f4fa0a9c7b5c5b3c810ff1df614540d5aa7d519261b53fba55d4df9/greenlet-3.3.2-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a443358b33c4ec7b05b79a7c8b466f5d275025e750298be7340f8fc63dff2a55", size = 594363, upload-time = "2026-02-20T20:55:56.965Z" }, - { url = "https://files.pythonhosted.org/packages/72/83/3e06a52aca8128bdd4dcd67e932b809e76a96ab8c232a8b025b2850264c5/greenlet-3.3.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e2cd90d413acbf5e77ae41e5d3c9b3ac1d011a756d7284d7f3f2b806bbd6358", size = 594156, upload-time = "2026-02-20T20:20:59.955Z" }, - { url = "https://files.pythonhosted.org/packages/70/79/0de5e62b873e08fe3cef7dbe84e5c4bc0e8ed0c7ff131bccb8405cd107c8/greenlet-3.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:442b6057453c8cb29b4fb36a2ac689382fc71112273726e2423f7f17dc73bf99", size = 1554649, upload-time = "2026-02-20T20:49:32.293Z" }, - { url = "https://files.pythonhosted.org/packages/5a/00/32d30dee8389dc36d42170a9c66217757289e2afb0de59a3565260f38373/greenlet-3.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45abe8eb6339518180d5a7fa47fa01945414d7cca5ecb745346fc6a87d2750be", size = 1619472, upload-time = "2026-02-20T20:21:07.966Z" }, - { url = "https://files.pythonhosted.org/packages/f1/3a/efb2cf697fbccdf75b24e2c18025e7dfa54c4f31fab75c51d0fe79942cef/greenlet-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e692b2dae4cc7077cbb11b47d258533b48c8fde69a33d0d8a82e2fe8d8531d5", size = 230389, upload-time = "2026-02-20T20:17:18.772Z" }, - { url = "https://files.pythonhosted.org/packages/e1/a1/65bbc059a43a7e2143ec4fc1f9e3f673e04f9c7b371a494a101422ac4fd5/greenlet-3.3.2-cp311-cp311-win_arm64.whl", hash = "sha256:02b0a8682aecd4d3c6c18edf52bc8e51eacdd75c8eac52a790a210b06aa295fd", size = 229645, upload-time = "2026-02-20T20:18:18.695Z" }, - { url = "https://files.pythonhosted.org/packages/ea/ab/1608e5a7578e62113506740b88066bf09888322a311cff602105e619bd87/greenlet-3.3.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ac8d61d4343b799d1e526db579833d72f23759c71e07181c2d2944e429eb09cd", size = 280358, upload-time = "2026-02-20T20:17:43.971Z" }, - { url = "https://files.pythonhosted.org/packages/a5/23/0eae412a4ade4e6623ff7626e38998cb9b11e9ff1ebacaa021e4e108ec15/greenlet-3.3.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ceec72030dae6ac0c8ed7591b96b70410a8be370b6a477b1dbc072856ad02bd", size = 601217, upload-time = "2026-02-20T20:47:31.462Z" }, - { url = "https://files.pythonhosted.org/packages/f8/16/5b1678a9c07098ecb9ab2dd159fafaf12e963293e61ee8d10ecb55273e5e/greenlet-3.3.2-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2a5be83a45ce6188c045bcc44b0ee037d6a518978de9a5d97438548b953a1ac", size = 611792, upload-time = "2026-02-20T20:55:58.423Z" }, - { url = "https://files.pythonhosted.org/packages/50/1f/5155f55bd71cabd03765a4aac9ac446be129895271f73872c36ebd4b04b6/greenlet-3.3.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e99d1749147ac21dde49b99c9abffcbc1e2d55c67501465ef0930d6e78e070", size = 613875, upload-time = "2026-02-20T20:21:01.102Z" }, - { url = "https://files.pythonhosted.org/packages/fc/dd/845f249c3fcd69e32df80cdab059b4be8b766ef5830a3d0aa9d6cad55beb/greenlet-3.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c956a19350e2c37f2c48b336a3afb4bff120b36076d9d7fb68cb44e05d95b79", size = 1571467, upload-time = "2026-02-20T20:49:33.495Z" }, - { url = "https://files.pythonhosted.org/packages/2a/50/2649fe21fcc2b56659a452868e695634722a6655ba245d9f77f5656010bf/greenlet-3.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c6f8ba97d17a1e7d664151284cb3315fc5f8353e75221ed4324f84eb162b395", size = 1640001, upload-time = "2026-02-20T20:21:09.154Z" }, - { url = "https://files.pythonhosted.org/packages/9b/40/cc802e067d02af8b60b6771cea7d57e21ef5e6659912814babb42b864713/greenlet-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:34308836d8370bddadb41f5a7ce96879b72e2fdfb4e87729330c6ab52376409f", size = 231081, upload-time = "2026-02-20T20:17:28.121Z" }, - { url = "https://files.pythonhosted.org/packages/58/2e/fe7f36ff1982d6b10a60d5e0740c759259a7d6d2e1dc41da6d96de32fff6/greenlet-3.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:d3a62fa76a32b462a97198e4c9e99afb9ab375115e74e9a83ce180e7a496f643", size = 230331, upload-time = "2026-02-20T20:17:23.34Z" }, - { url = "https://files.pythonhosted.org/packages/ac/48/f8b875fa7dea7dd9b33245e37f065af59df6a25af2f9561efa8d822fde51/greenlet-3.3.2-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:aa6ac98bdfd716a749b84d4034486863fd81c3abde9aa3cf8eff9127981a4ae4", size = 279120, upload-time = "2026-02-20T20:19:01.9Z" }, - { url = "https://files.pythonhosted.org/packages/49/8d/9771d03e7a8b1ee456511961e1b97a6d77ae1dea4a34a5b98eee706689d3/greenlet-3.3.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab0c7e7901a00bc0a7284907273dc165b32e0d109a6713babd04471327ff7986", size = 603238, upload-time = "2026-02-20T20:47:32.873Z" }, - { url = "https://files.pythonhosted.org/packages/59/0e/4223c2bbb63cd5c97f28ffb2a8aee71bdfb30b323c35d409450f51b91e3e/greenlet-3.3.2-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d248d8c23c67d2291ffd47af766e2a3aa9fa1c6703155c099feb11f526c63a92", size = 614219, upload-time = "2026-02-20T20:55:59.817Z" }, - { url = "https://files.pythonhosted.org/packages/7a/34/259b28ea7a2a0c904b11cd36c79b8cef8019b26ee5dbe24e73b469dea347/greenlet-3.3.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6997d360a4e6a4e936c0f9625b1c20416b8a0ea18a8e19cabbefc712e7397ab", size = 616774, upload-time = "2026-02-20T20:21:02.454Z" }, - { url = "https://files.pythonhosted.org/packages/0a/03/996c2d1689d486a6e199cb0f1cf9e4aa940c500e01bdf201299d7d61fa69/greenlet-3.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64970c33a50551c7c50491671265d8954046cb6e8e2999aacdd60e439b70418a", size = 1571277, upload-time = "2026-02-20T20:49:34.795Z" }, - { url = "https://files.pythonhosted.org/packages/d9/c4/2570fc07f34a39f2caf0bf9f24b0a1a0a47bc2e8e465b2c2424821389dfc/greenlet-3.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1a9172f5bf6bd88e6ba5a84e0a68afeac9dc7b6b412b245dd64f52d83c81e55b", size = 1640455, upload-time = "2026-02-20T20:21:10.261Z" }, - { url = "https://files.pythonhosted.org/packages/91/39/5ef5aa23bc545aa0d31e1b9b55822b32c8da93ba657295840b6b34124009/greenlet-3.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:a7945dd0eab63ded0a48e4dcade82939783c172290a7903ebde9e184333ca124", size = 230961, upload-time = "2026-02-20T20:16:58.461Z" }, - { url = "https://files.pythonhosted.org/packages/62/6b/a89f8456dcb06becff288f563618e9f20deed8dd29beea14f9a168aef64b/greenlet-3.3.2-cp313-cp313-win_arm64.whl", hash = "sha256:394ead29063ee3515b4e775216cb756b2e3b4a7e55ae8fd884f17fa579e6b327", size = 230221, upload-time = "2026-02-20T20:17:37.152Z" }, { url = "https://files.pythonhosted.org/packages/3f/ae/8bffcbd373b57a5992cd077cbe8858fff39110480a9d50697091faea6f39/greenlet-3.3.2-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8d1658d7291f9859beed69a776c10822a0a799bc4bfe1bd4272bb60e62507dab", size = 279650, upload-time = "2026-02-20T20:18:00.783Z" }, { url = "https://files.pythonhosted.org/packages/d1/c0/45f93f348fa49abf32ac8439938726c480bd96b2a3c6f4d949ec0124b69f/greenlet-3.3.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18cb1b7337bca281915b3c5d5ae19f4e76d35e1df80f4ad3c1a7be91fadf1082", size = 650295, upload-time = "2026-02-20T20:47:34.036Z" }, { url = "https://files.pythonhosted.org/packages/b3/de/dd7589b3f2b8372069ab3e4763ea5329940fc7ad9dcd3e272a37516d7c9b/greenlet-3.3.2-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2e47408e8ce1c6f1ceea0dffcdf6ebb85cc09e55c7af407c99f1112016e45e9", size = 662163, upload-time = "2026-02-20T20:56:01.295Z" }, @@ -978,34 +668,6 @@ version = "0.7.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531, upload-time = "2025-10-10T03:54:20.887Z" }, - { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408, upload-time = "2025-10-10T03:54:22.455Z" }, - { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889, upload-time = "2025-10-10T03:54:23.753Z" }, - { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460, upload-time = "2025-10-10T03:54:25.313Z" }, - { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267, upload-time = "2025-10-10T03:54:26.81Z" }, - { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429, upload-time = "2025-10-10T03:54:28.174Z" }, - { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173, upload-time = "2025-10-10T03:54:29.5Z" }, - { url = "https://files.pythonhosted.org/packages/9c/08/17e07e8d89ab8f343c134616d72eebfe03798835058e2ab579dcc8353c06/httptools-0.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:474d3b7ab469fefcca3697a10d11a32ee2b9573250206ba1e50d5980910da657", size = 206521, upload-time = "2025-10-10T03:54:31.002Z" }, - { url = "https://files.pythonhosted.org/packages/aa/06/c9c1b41ff52f16aee526fd10fbda99fa4787938aa776858ddc4a1ea825ec/httptools-0.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3c3b7366bb6c7b96bd72d0dbe7f7d5eead261361f013be5f6d9590465ea1c70", size = 110375, upload-time = "2025-10-10T03:54:31.941Z" }, - { url = "https://files.pythonhosted.org/packages/cc/cc/10935db22fda0ee34c76f047590ca0a8bd9de531406a3ccb10a90e12ea21/httptools-0.7.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:379b479408b8747f47f3b253326183d7c009a3936518cdb70db58cffd369d9df", size = 456621, upload-time = "2025-10-10T03:54:33.176Z" }, - { url = "https://files.pythonhosted.org/packages/0e/84/875382b10d271b0c11aa5d414b44f92f8dd53e9b658aec338a79164fa548/httptools-0.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cad6b591a682dcc6cf1397c3900527f9affef1e55a06c4547264796bbd17cf5e", size = 454954, upload-time = "2025-10-10T03:54:34.226Z" }, - { url = "https://files.pythonhosted.org/packages/30/e1/44f89b280f7e46c0b1b2ccee5737d46b3bb13136383958f20b580a821ca0/httptools-0.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eb844698d11433d2139bbeeb56499102143beb582bd6c194e3ba69c22f25c274", size = 440175, upload-time = "2025-10-10T03:54:35.942Z" }, - { url = "https://files.pythonhosted.org/packages/6f/7e/b9287763159e700e335028bc1824359dc736fa9b829dacedace91a39b37e/httptools-0.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f65744d7a8bdb4bda5e1fa23e4ba16832860606fcc09d674d56e425e991539ec", size = 440310, upload-time = "2025-10-10T03:54:37.1Z" }, - { url = "https://files.pythonhosted.org/packages/b3/07/5b614f592868e07f5c94b1f301b5e14a21df4e8076215a3bccb830a687d8/httptools-0.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:135fbe974b3718eada677229312e97f3b31f8a9c8ffa3ae6f565bf808d5b6bcb", size = 86875, upload-time = "2025-10-10T03:54:38.421Z" }, - { url = "https://files.pythonhosted.org/packages/53/7f/403e5d787dc4942316e515e949b0c8a013d84078a915910e9f391ba9b3ed/httptools-0.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:38e0c83a2ea9746ebbd643bdfb521b9aa4a91703e2cd705c20443405d2fd16a5", size = 206280, upload-time = "2025-10-10T03:54:39.274Z" }, - { url = "https://files.pythonhosted.org/packages/2a/0d/7f3fd28e2ce311ccc998c388dd1c53b18120fda3b70ebb022b135dc9839b/httptools-0.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f25bbaf1235e27704f1a7b86cd3304eabc04f569c828101d94a0e605ef7205a5", size = 110004, upload-time = "2025-10-10T03:54:40.403Z" }, - { url = "https://files.pythonhosted.org/packages/84/a6/b3965e1e146ef5762870bbe76117876ceba51a201e18cc31f5703e454596/httptools-0.7.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c15f37ef679ab9ecc06bfc4e6e8628c32a8e4b305459de7cf6785acd57e4d03", size = 517655, upload-time = "2025-10-10T03:54:41.347Z" }, - { url = "https://files.pythonhosted.org/packages/11/7d/71fee6f1844e6fa378f2eddde6c3e41ce3a1fb4b2d81118dd544e3441ec0/httptools-0.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fe6e96090df46b36ccfaf746f03034e5ab723162bc51b0a4cf58305324036f2", size = 511440, upload-time = "2025-10-10T03:54:42.452Z" }, - { url = "https://files.pythonhosted.org/packages/22/a5/079d216712a4f3ffa24af4a0381b108aa9c45b7a5cc6eb141f81726b1823/httptools-0.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f72fdbae2dbc6e68b8239defb48e6a5937b12218e6ffc2c7846cc37befa84362", size = 495186, upload-time = "2025-10-10T03:54:43.937Z" }, - { url = "https://files.pythonhosted.org/packages/e9/9e/025ad7b65278745dee3bd0ebf9314934c4592560878308a6121f7f812084/httptools-0.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e99c7b90a29fd82fea9ef57943d501a16f3404d7b9ee81799d41639bdaae412c", size = 499192, upload-time = "2025-10-10T03:54:45.003Z" }, - { url = "https://files.pythonhosted.org/packages/6d/de/40a8f202b987d43afc4d54689600ff03ce65680ede2f31df348d7f368b8f/httptools-0.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:3e14f530fefa7499334a79b0cf7e7cd2992870eb893526fb097d51b4f2d0f321", size = 86694, upload-time = "2025-10-10T03:54:45.923Z" }, - { url = "https://files.pythonhosted.org/packages/09/8f/c77b1fcbfd262d422f12da02feb0d218fa228d52485b77b953832105bb90/httptools-0.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6babce6cfa2a99545c60bfef8bee0cc0545413cb0018f617c8059a30ad985de3", size = 202889, upload-time = "2025-10-10T03:54:47.089Z" }, - { url = "https://files.pythonhosted.org/packages/0a/1a/22887f53602feaa066354867bc49a68fc295c2293433177ee90870a7d517/httptools-0.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:601b7628de7504077dd3dcb3791c6b8694bbd967148a6d1f01806509254fb1ca", size = 108180, upload-time = "2025-10-10T03:54:48.052Z" }, - { url = "https://files.pythonhosted.org/packages/32/6a/6aaa91937f0010d288d3d124ca2946d48d60c3a5ee7ca62afe870e3ea011/httptools-0.7.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04c6c0e6c5fb0739c5b8a9eb046d298650a0ff38cf42537fc372b28dc7e4472c", size = 478596, upload-time = "2025-10-10T03:54:48.919Z" }, - { url = "https://files.pythonhosted.org/packages/6d/70/023d7ce117993107be88d2cbca566a7c1323ccbaf0af7eabf2064fe356f6/httptools-0.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69d4f9705c405ae3ee83d6a12283dc9feba8cc6aaec671b412917e644ab4fa66", size = 473268, upload-time = "2025-10-10T03:54:49.993Z" }, - { url = "https://files.pythonhosted.org/packages/32/4d/9dd616c38da088e3f436e9a616e1d0cc66544b8cdac405cc4e81c8679fc7/httptools-0.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44c8f4347d4b31269c8a9205d8a5ee2df5322b09bbbd30f8f862185bb6b05346", size = 455517, upload-time = "2025-10-10T03:54:51.066Z" }, - { url = "https://files.pythonhosted.org/packages/1d/3a/a6c595c310b7df958e739aae88724e24f9246a514d909547778d776799be/httptools-0.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:465275d76db4d554918aba40bf1cbebe324670f3dfc979eaffaa5d108e2ed650", size = 458337, upload-time = "2025-10-10T03:54:52.196Z" }, - { url = "https://files.pythonhosted.org/packages/fd/82/88e8d6d2c51edc1cc391b6e044c6c435b6aebe97b1abc33db1b0b24cd582/httptools-0.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:322d00c2068d125bd570f7bf78b2d367dad02b919d8581d7476d8b75b294e3e6", size = 85743, upload-time = "2025-10-10T03:54:53.448Z" }, { url = "https://files.pythonhosted.org/packages/34/50/9d095fcbb6de2d523e027a2f304d4551855c2f46e0b82befd718b8b20056/httptools-0.7.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c08fe65728b8d70b6923ce31e3956f859d5e1e8548e6f22ec520a962c6757270", size = 203619, upload-time = "2025-10-10T03:54:54.321Z" }, { url = "https://files.pythonhosted.org/packages/07/f0/89720dc5139ae54b03f861b5e2c55a37dba9a5da7d51e1e824a1f343627f/httptools-0.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7aea2e3c3953521c3c51106ee11487a910d45586e351202474d45472db7d72d3", size = 108714, upload-time = "2025-10-10T03:54:55.163Z" }, { url = "https://files.pythonhosted.org/packages/b3/cb/eea88506f191fb552c11787c23f9a405f4c7b0c5799bf73f2249cd4f5228/httptools-0.7.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0e68b8582f4ea9166be62926077a3334064d422cf08ab87d8b74664f8e9058e1", size = 472909, upload-time = "2025-10-10T03:54:56.056Z" }, @@ -1069,215 +731,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] -[[package]] -name = "librt" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/56/9c/b4b0c54d84da4a94b37bd44151e46d5e583c9534c7e02250b961b1b6d8a8/librt-0.8.1.tar.gz", hash = "sha256:be46a14693955b3bd96014ccbdb8339ee8c9346fbe11c1b78901b55125f14c73", size = 177471, upload-time = "2026-02-17T16:13:06.101Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/5f/63f5fa395c7a8a93558c0904ba8f1c8d1b997ca6a3de61bc7659970d66bf/librt-0.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:81fd938344fecb9373ba1b155968c8a329491d2ce38e7ddb76f30ffb938f12dc", size = 65697, upload-time = "2026-02-17T16:11:06.903Z" }, - { url = "https://files.pythonhosted.org/packages/ff/e0/0472cf37267b5920eff2f292ccfaede1886288ce35b7f3203d8de00abfe6/librt-0.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5db05697c82b3a2ec53f6e72b2ed373132b0c2e05135f0696784e97d7f5d48e7", size = 68376, upload-time = "2026-02-17T16:11:08.395Z" }, - { url = "https://files.pythonhosted.org/packages/c8/be/8bd1359fdcd27ab897cd5963294fa4a7c83b20a8564678e4fd12157e56a5/librt-0.8.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d56bc4011975f7460bea7b33e1ff425d2f1adf419935ff6707273c77f8a4ada6", size = 197084, upload-time = "2026-02-17T16:11:09.774Z" }, - { url = "https://files.pythonhosted.org/packages/e2/fe/163e33fdd091d0c2b102f8a60cc0a61fd730ad44e32617cd161e7cd67a01/librt-0.8.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdc0f588ff4b663ea96c26d2a230c525c6fc62b28314edaaaca8ed5af931ad0", size = 207337, upload-time = "2026-02-17T16:11:11.311Z" }, - { url = "https://files.pythonhosted.org/packages/01/99/f85130582f05dcf0c8902f3d629270231d2f4afdfc567f8305a952ac7f14/librt-0.8.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:97c2b54ff6717a7a563b72627990bec60d8029df17df423f0ed37d56a17a176b", size = 219980, upload-time = "2026-02-17T16:11:12.499Z" }, - { url = "https://files.pythonhosted.org/packages/6f/54/cb5e4d03659e043a26c74e08206412ac9a3742f0477d96f9761a55313b5f/librt-0.8.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8f1125e6bbf2f1657d9a2f3ccc4a2c9b0c8b176965bb565dd4d86be67eddb4b6", size = 212921, upload-time = "2026-02-17T16:11:14.484Z" }, - { url = "https://files.pythonhosted.org/packages/b1/81/a3a01e4240579c30f3487f6fed01eb4bc8ef0616da5b4ebac27ca19775f3/librt-0.8.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8f4bb453f408137d7581be309b2fbc6868a80e7ef60c88e689078ee3a296ae71", size = 221381, upload-time = "2026-02-17T16:11:17.459Z" }, - { url = "https://files.pythonhosted.org/packages/08/b0/fc2d54b4b1c6fb81e77288ff31ff25a2c1e62eaef4424a984f228839717b/librt-0.8.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c336d61d2fe74a3195edc1646d53ff1cddd3a9600b09fa6ab75e5514ba4862a7", size = 216714, upload-time = "2026-02-17T16:11:19.197Z" }, - { url = "https://files.pythonhosted.org/packages/96/96/85daa73ffbd87e1fb287d7af6553ada66bf25a2a6b0de4764344a05469f6/librt-0.8.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:eb5656019db7c4deacf0c1a55a898c5bb8f989be904597fcb5232a2f4828fa05", size = 214777, upload-time = "2026-02-17T16:11:20.443Z" }, - { url = "https://files.pythonhosted.org/packages/12/9c/c3aa7a2360383f4bf4f04d98195f2739a579128720c603f4807f006a4225/librt-0.8.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c25d9e338d5bed46c1632f851babf3d13c78f49a225462017cf5e11e845c5891", size = 237398, upload-time = "2026-02-17T16:11:22.083Z" }, - { url = "https://files.pythonhosted.org/packages/61/19/d350ea89e5274665185dabc4bbb9c3536c3411f862881d316c8b8e00eb66/librt-0.8.1-cp310-cp310-win32.whl", hash = "sha256:aaab0e307e344cb28d800957ef3ec16605146ef0e59e059a60a176d19543d1b7", size = 54285, upload-time = "2026-02-17T16:11:23.27Z" }, - { url = "https://files.pythonhosted.org/packages/4f/d6/45d587d3d41c112e9543a0093d883eb57a24a03e41561c127818aa2a6bcc/librt-0.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:56e04c14b696300d47b3bc5f1d10a00e86ae978886d0cee14e5714fafb5df5d2", size = 61352, upload-time = "2026-02-17T16:11:24.207Z" }, - { url = "https://files.pythonhosted.org/packages/1d/01/0e748af5e4fee180cf7cd12bd12b0513ad23b045dccb2a83191bde82d168/librt-0.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:681dc2451d6d846794a828c16c22dc452d924e9f700a485b7ecb887a30aad1fd", size = 65315, upload-time = "2026-02-17T16:11:25.152Z" }, - { url = "https://files.pythonhosted.org/packages/9d/4d/7184806efda571887c798d573ca4134c80ac8642dcdd32f12c31b939c595/librt-0.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3b4350b13cc0e6f5bec8fa7caf29a8fb8cdc051a3bae45cfbfd7ce64f009965", size = 68021, upload-time = "2026-02-17T16:11:26.129Z" }, - { url = "https://files.pythonhosted.org/packages/ae/88/c3c52d2a5d5101f28d3dc89298444626e7874aa904eed498464c2af17627/librt-0.8.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ac1e7817fd0ed3d14fd7c5df91daed84c48e4c2a11ee99c0547f9f62fdae13da", size = 194500, upload-time = "2026-02-17T16:11:27.177Z" }, - { url = "https://files.pythonhosted.org/packages/d6/5d/6fb0a25b6a8906e85b2c3b87bee1d6ed31510be7605b06772f9374ca5cb3/librt-0.8.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:747328be0c5b7075cde86a0e09d7a9196029800ba75a1689332348e998fb85c0", size = 205622, upload-time = "2026-02-17T16:11:28.242Z" }, - { url = "https://files.pythonhosted.org/packages/b2/a6/8006ae81227105476a45691f5831499e4d936b1c049b0c1feb17c11b02d1/librt-0.8.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0af2bd2bc204fa27f3d6711d0f360e6b8c684a035206257a81673ab924aa11e", size = 218304, upload-time = "2026-02-17T16:11:29.344Z" }, - { url = "https://files.pythonhosted.org/packages/ee/19/60e07886ad16670aae57ef44dada41912c90906a6fe9f2b9abac21374748/librt-0.8.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d480de377f5b687b6b1bc0c0407426da556e2a757633cc7e4d2e1a057aa688f3", size = 211493, upload-time = "2026-02-17T16:11:30.445Z" }, - { url = "https://files.pythonhosted.org/packages/9c/cf/f666c89d0e861d05600438213feeb818c7514d3315bae3648b1fc145d2b6/librt-0.8.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d0ee06b5b5291f609ddb37b9750985b27bc567791bc87c76a569b3feed8481ac", size = 219129, upload-time = "2026-02-17T16:11:32.021Z" }, - { url = "https://files.pythonhosted.org/packages/8f/ef/f1bea01e40b4a879364c031476c82a0dc69ce068daad67ab96302fed2d45/librt-0.8.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9e2c6f77b9ad48ce5603b83b7da9ee3e36b3ab425353f695cba13200c5d96596", size = 213113, upload-time = "2026-02-17T16:11:33.192Z" }, - { url = "https://files.pythonhosted.org/packages/9b/80/cdab544370cc6bc1b72ea369525f547a59e6938ef6863a11ab3cd24759af/librt-0.8.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:439352ba9373f11cb8e1933da194dcc6206daf779ff8df0ed69c5e39113e6a99", size = 212269, upload-time = "2026-02-17T16:11:34.373Z" }, - { url = "https://files.pythonhosted.org/packages/9d/9c/48d6ed8dac595654f15eceab2035131c136d1ae9a1e3548e777bb6dbb95d/librt-0.8.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:82210adabbc331dbb65d7868b105185464ef13f56f7f76688565ad79f648b0fe", size = 234673, upload-time = "2026-02-17T16:11:36.063Z" }, - { url = "https://files.pythonhosted.org/packages/16/01/35b68b1db517f27a01be4467593292eb5315def8900afad29fabf56304ba/librt-0.8.1-cp311-cp311-win32.whl", hash = "sha256:52c224e14614b750c0a6d97368e16804a98c684657c7518752c356834fff83bb", size = 54597, upload-time = "2026-02-17T16:11:37.544Z" }, - { url = "https://files.pythonhosted.org/packages/71/02/796fe8f02822235966693f257bf2c79f40e11337337a657a8cfebba5febc/librt-0.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:c00e5c884f528c9932d278d5c9cbbea38a6b81eb62c02e06ae53751a83a4d52b", size = 61733, upload-time = "2026-02-17T16:11:38.691Z" }, - { url = "https://files.pythonhosted.org/packages/28/ad/232e13d61f879a42a4e7117d65e4984bb28371a34bb6fb9ca54ec2c8f54e/librt-0.8.1-cp311-cp311-win_arm64.whl", hash = "sha256:f7cdf7f26c2286ffb02e46d7bac56c94655540b26347673bea15fa52a6af17e9", size = 52273, upload-time = "2026-02-17T16:11:40.308Z" }, - { url = "https://files.pythonhosted.org/packages/95/21/d39b0a87ac52fc98f621fb6f8060efb017a767ebbbac2f99fbcbc9ddc0d7/librt-0.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a28f2612ab566b17f3698b0da021ff9960610301607c9a5e8eaca62f5e1c350a", size = 66516, upload-time = "2026-02-17T16:11:41.604Z" }, - { url = "https://files.pythonhosted.org/packages/69/f1/46375e71441c43e8ae335905e069f1c54febee63a146278bcee8782c84fd/librt-0.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60a78b694c9aee2a0f1aaeaa7d101cf713e92e8423a941d2897f4fa37908dab9", size = 68634, upload-time = "2026-02-17T16:11:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/0a/33/c510de7f93bf1fa19e13423a606d8189a02624a800710f6e6a0a0f0784b3/librt-0.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:758509ea3f1eba2a57558e7e98f4659d0ea7670bff49673b0dde18a3c7e6c0eb", size = 198941, upload-time = "2026-02-17T16:11:44.28Z" }, - { url = "https://files.pythonhosted.org/packages/dd/36/e725903416409a533d92398e88ce665476f275081d0d7d42f9c4951999e5/librt-0.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:039b9f2c506bd0ab0f8725aa5ba339c6f0cd19d3b514b50d134789809c24285d", size = 209991, upload-time = "2026-02-17T16:11:45.462Z" }, - { url = "https://files.pythonhosted.org/packages/30/7a/8d908a152e1875c9f8eac96c97a480df425e657cdb47854b9efaa4998889/librt-0.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bb54f1205a3a6ab41a6fd71dfcdcbd278670d3a90ca502a30d9da583105b6f7", size = 224476, upload-time = "2026-02-17T16:11:46.542Z" }, - { url = "https://files.pythonhosted.org/packages/a8/b8/a22c34f2c485b8903a06f3fe3315341fe6876ef3599792344669db98fcff/librt-0.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:05bd41cdee35b0c59c259f870f6da532a2c5ca57db95b5f23689fcb5c9e42440", size = 217518, upload-time = "2026-02-17T16:11:47.746Z" }, - { url = "https://files.pythonhosted.org/packages/79/6f/5c6fea00357e4f82ba44f81dbfb027921f1ab10e320d4a64e1c408d035d9/librt-0.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adfab487facf03f0d0857b8710cf82d0704a309d8ffc33b03d9302b4c64e91a9", size = 225116, upload-time = "2026-02-17T16:11:49.298Z" }, - { url = "https://files.pythonhosted.org/packages/f2/a0/95ced4e7b1267fe1e2720a111685bcddf0e781f7e9e0ce59d751c44dcfe5/librt-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:153188fe98a72f206042be10a2c6026139852805215ed9539186312d50a8e972", size = 217751, upload-time = "2026-02-17T16:11:50.49Z" }, - { url = "https://files.pythonhosted.org/packages/93/c2/0517281cb4d4101c27ab59472924e67f55e375bc46bedae94ac6dc6e1902/librt-0.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dd3c41254ee98604b08bd5b3af5bf0a89740d4ee0711de95b65166bf44091921", size = 218378, upload-time = "2026-02-17T16:11:51.783Z" }, - { url = "https://files.pythonhosted.org/packages/43/e8/37b3ac108e8976888e559a7b227d0ceac03c384cfd3e7a1c2ee248dbae79/librt-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e0d138c7ae532908cbb342162b2611dbd4d90c941cd25ab82084aaf71d2c0bd0", size = 241199, upload-time = "2026-02-17T16:11:53.561Z" }, - { url = "https://files.pythonhosted.org/packages/4b/5b/35812d041c53967fedf551a39399271bbe4257e681236a2cf1a69c8e7fa1/librt-0.8.1-cp312-cp312-win32.whl", hash = "sha256:43353b943613c5d9c49a25aaffdba46f888ec354e71e3529a00cca3f04d66a7a", size = 54917, upload-time = "2026-02-17T16:11:54.758Z" }, - { url = "https://files.pythonhosted.org/packages/de/d1/fa5d5331b862b9775aaf2a100f5ef86854e5d4407f71bddf102f4421e034/librt-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff8baf1f8d3f4b6b7257fcb75a501f2a5499d0dda57645baa09d4d0d34b19444", size = 62017, upload-time = "2026-02-17T16:11:55.748Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7c/c614252f9acda59b01a66e2ddfd243ed1c7e1deab0293332dfbccf862808/librt-0.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f2ae3725904f7377e11cc37722d5d401e8b3d5851fb9273d7f4fe04f6b3d37d", size = 52441, upload-time = "2026-02-17T16:11:56.801Z" }, - { url = "https://files.pythonhosted.org/packages/c5/3c/f614c8e4eaac7cbf2bbdf9528790b21d89e277ee20d57dc6e559c626105f/librt-0.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e6bad1cd94f6764e1e21950542f818a09316645337fd5ab9a7acc45d99a8f35", size = 66529, upload-time = "2026-02-17T16:11:57.809Z" }, - { url = "https://files.pythonhosted.org/packages/ab/96/5836544a45100ae411eda07d29e3d99448e5258b6e9c8059deb92945f5c2/librt-0.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cf450f498c30af55551ba4f66b9123b7185362ec8b625a773b3d39aa1a717583", size = 68669, upload-time = "2026-02-17T16:11:58.843Z" }, - { url = "https://files.pythonhosted.org/packages/06/53/f0b992b57af6d5531bf4677d75c44f095f2366a1741fb695ee462ae04b05/librt-0.8.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eca45e982fa074090057132e30585a7e8674e9e885d402eae85633e9f449ce6c", size = 199279, upload-time = "2026-02-17T16:11:59.862Z" }, - { url = "https://files.pythonhosted.org/packages/f3/ad/4848cc16e268d14280d8168aee4f31cea92bbd2b79ce33d3e166f2b4e4fc/librt-0.8.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c3811485fccfda840861905b8c70bba5ec094e02825598bb9d4ca3936857a04", size = 210288, upload-time = "2026-02-17T16:12:00.954Z" }, - { url = "https://files.pythonhosted.org/packages/52/05/27fdc2e95de26273d83b96742d8d3b7345f2ea2bdbd2405cc504644f2096/librt-0.8.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e4af413908f77294605e28cfd98063f54b2c790561383971d2f52d113d9c363", size = 224809, upload-time = "2026-02-17T16:12:02.108Z" }, - { url = "https://files.pythonhosted.org/packages/7a/d0/78200a45ba3240cb042bc597d6f2accba9193a2c57d0356268cbbe2d0925/librt-0.8.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5212a5bd7fae98dae95710032902edcd2ec4dc994e883294f75c857b83f9aba0", size = 218075, upload-time = "2026-02-17T16:12:03.631Z" }, - { url = "https://files.pythonhosted.org/packages/af/72/a210839fa74c90474897124c064ffca07f8d4b347b6574d309686aae7ca6/librt-0.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e692aa2d1d604e6ca12d35e51fdc36f4cda6345e28e36374579f7ef3611b3012", size = 225486, upload-time = "2026-02-17T16:12:04.725Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c1/a03cc63722339ddbf087485f253493e2b013039f5b707e8e6016141130fa/librt-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4be2a5c926b9770c9e08e717f05737a269b9d0ebc5d2f0060f0fe3fe9ce47acb", size = 218219, upload-time = "2026-02-17T16:12:05.828Z" }, - { url = "https://files.pythonhosted.org/packages/58/f5/fff6108af0acf941c6f274a946aea0e484bd10cd2dc37610287ce49388c5/librt-0.8.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fd1a720332ea335ceb544cf0a03f81df92abd4bb887679fd1e460976b0e6214b", size = 218750, upload-time = "2026-02-17T16:12:07.09Z" }, - { url = "https://files.pythonhosted.org/packages/71/67/5a387bfef30ec1e4b4f30562c8586566faf87e47d696768c19feb49e3646/librt-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2af9e01e0ef80d95ae3c720be101227edae5f2fe7e3dc63d8857fadfc5a1d", size = 241624, upload-time = "2026-02-17T16:12:08.43Z" }, - { url = "https://files.pythonhosted.org/packages/d4/be/24f8502db11d405232ac1162eb98069ca49c3306c1d75c6ccc61d9af8789/librt-0.8.1-cp313-cp313-win32.whl", hash = "sha256:086a32dbb71336627e78cc1d6ee305a68d038ef7d4c39aaff41ae8c9aa46e91a", size = 54969, upload-time = "2026-02-17T16:12:09.633Z" }, - { url = "https://files.pythonhosted.org/packages/5c/73/c9fdf6cb2a529c1a092ce769a12d88c8cca991194dfe641b6af12fa964d2/librt-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:e11769a1dbda4da7b00a76cfffa67aa47cfa66921d2724539eee4b9ede780b79", size = 62000, upload-time = "2026-02-17T16:12:10.632Z" }, - { url = "https://files.pythonhosted.org/packages/d3/97/68f80ca3ac4924f250cdfa6e20142a803e5e50fca96ef5148c52ee8c10ea/librt-0.8.1-cp313-cp313-win_arm64.whl", hash = "sha256:924817ab3141aca17893386ee13261f1d100d1ef410d70afe4389f2359fea4f0", size = 52495, upload-time = "2026-02-17T16:12:11.633Z" }, - { url = "https://files.pythonhosted.org/packages/c9/6a/907ef6800f7bca71b525a05f1839b21f708c09043b1c6aa77b6b827b3996/librt-0.8.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6cfa7fe54fd4d1f47130017351a959fe5804bda7a0bc7e07a2cdbc3fdd28d34f", size = 66081, upload-time = "2026-02-17T16:12:12.766Z" }, - { url = "https://files.pythonhosted.org/packages/1b/18/25e991cd5640c9fb0f8d91b18797b29066b792f17bf8493da183bf5caabe/librt-0.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:228c2409c079f8c11fb2e5d7b277077f694cb93443eb760e00b3b83cb8b3176c", size = 68309, upload-time = "2026-02-17T16:12:13.756Z" }, - { url = "https://files.pythonhosted.org/packages/a4/36/46820d03f058cfb5a9de5940640ba03165ed8aded69e0733c417bb04df34/librt-0.8.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7aae78ab5e3206181780e56912d1b9bb9f90a7249ce12f0e8bf531d0462dd0fc", size = 196804, upload-time = "2026-02-17T16:12:14.818Z" }, - { url = "https://files.pythonhosted.org/packages/59/18/5dd0d3b87b8ff9c061849fbdb347758d1f724b9a82241aa908e0ec54ccd0/librt-0.8.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:172d57ec04346b047ca6af181e1ea4858086c80bdf455f61994c4aa6fc3f866c", size = 206907, upload-time = "2026-02-17T16:12:16.513Z" }, - { url = "https://files.pythonhosted.org/packages/d1/96/ef04902aad1424fd7299b62d1890e803e6ab4018c3044dca5922319c4b97/librt-0.8.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b1977c4ea97ce5eb7755a78fae68d87e4102e4aaf54985e8b56806849cc06a3", size = 221217, upload-time = "2026-02-17T16:12:17.906Z" }, - { url = "https://files.pythonhosted.org/packages/6d/ff/7e01f2dda84a8f5d280637a2e5827210a8acca9a567a54507ef1c75b342d/librt-0.8.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10c42e1f6fd06733ef65ae7bebce2872bcafd8d6e6b0a08fe0a05a23b044fb14", size = 214622, upload-time = "2026-02-17T16:12:19.108Z" }, - { url = "https://files.pythonhosted.org/packages/1e/8c/5b093d08a13946034fed57619742f790faf77058558b14ca36a6e331161e/librt-0.8.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c8dfa264b9193c4ee19113c985c95f876fae5e51f731494fc4e0cf594990ba7", size = 221987, upload-time = "2026-02-17T16:12:20.331Z" }, - { url = "https://files.pythonhosted.org/packages/d3/cc/86b0b3b151d40920ad45a94ce0171dec1aebba8a9d72bb3fa00c73ab25dd/librt-0.8.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:01170b6729a438f0dedc4a26ed342e3dc4f02d1000b4b19f980e1877f0c297e6", size = 215132, upload-time = "2026-02-17T16:12:21.54Z" }, - { url = "https://files.pythonhosted.org/packages/fc/be/8588164a46edf1e69858d952654e216a9a91174688eeefb9efbb38a9c799/librt-0.8.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:7b02679a0d783bdae30d443025b94465d8c3dc512f32f5b5031f93f57ac32071", size = 215195, upload-time = "2026-02-17T16:12:23.073Z" }, - { url = "https://files.pythonhosted.org/packages/f5/f2/0b9279bea735c734d69344ecfe056c1ba211694a72df10f568745c899c76/librt-0.8.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:190b109bb69592a3401fe1ffdea41a2e73370ace2ffdc4a0e8e2b39cdea81b78", size = 237946, upload-time = "2026-02-17T16:12:24.275Z" }, - { url = "https://files.pythonhosted.org/packages/e9/cc/5f2a34fbc8aeb35314a3641f9956fa9051a947424652fad9882be7a97949/librt-0.8.1-cp314-cp314-win32.whl", hash = "sha256:e70a57ecf89a0f64c24e37f38d3fe217a58169d2fe6ed6d70554964042474023", size = 50689, upload-time = "2026-02-17T16:12:25.766Z" }, - { url = "https://files.pythonhosted.org/packages/a0/76/cd4d010ab2147339ca2b93e959c3686e964edc6de66ddacc935c325883d7/librt-0.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:7e2f3edca35664499fbb36e4770650c4bd4a08abc1f4458eab9df4ec56389730", size = 57875, upload-time = "2026-02-17T16:12:27.465Z" }, - { url = "https://files.pythonhosted.org/packages/84/0f/2143cb3c3ca48bd3379dcd11817163ca50781927c4537345d608b5045998/librt-0.8.1-cp314-cp314-win_arm64.whl", hash = "sha256:0d2f82168e55ddefd27c01c654ce52379c0750ddc31ee86b4b266bcf4d65f2a3", size = 48058, upload-time = "2026-02-17T16:12:28.556Z" }, - { url = "https://files.pythonhosted.org/packages/d2/0e/9b23a87e37baf00311c3efe6b48d6b6c168c29902dfc3f04c338372fd7db/librt-0.8.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c74a2da57a094bd48d03fa5d196da83d2815678385d2978657499063709abe1", size = 68313, upload-time = "2026-02-17T16:12:29.659Z" }, - { url = "https://files.pythonhosted.org/packages/db/9a/859c41e5a4f1c84200a7d2b92f586aa27133c8243b6cac9926f6e54d01b9/librt-0.8.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a355d99c4c0d8e5b770313b8b247411ed40949ca44e33e46a4789b9293a907ee", size = 70994, upload-time = "2026-02-17T16:12:31.516Z" }, - { url = "https://files.pythonhosted.org/packages/4c/28/10605366ee599ed34223ac2bf66404c6fb59399f47108215d16d5ad751a8/librt-0.8.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2eb345e8b33fb748227409c9f1233d4df354d6e54091f0e8fc53acdb2ffedeb7", size = 220770, upload-time = "2026-02-17T16:12:33.294Z" }, - { url = "https://files.pythonhosted.org/packages/af/8d/16ed8fd452dafae9c48d17a6bc1ee3e818fd40ef718d149a8eff2c9f4ea2/librt-0.8.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9be2f15e53ce4e83cc08adc29b26fb5978db62ef2a366fbdf716c8a6c8901040", size = 235409, upload-time = "2026-02-17T16:12:35.443Z" }, - { url = "https://files.pythonhosted.org/packages/89/1b/7bdf3e49349c134b25db816e4a3db6b94a47ac69d7d46b1e682c2c4949be/librt-0.8.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:785ae29c1f5c6e7c2cde2c7c0e148147f4503da3abc5d44d482068da5322fd9e", size = 246473, upload-time = "2026-02-17T16:12:36.656Z" }, - { url = "https://files.pythonhosted.org/packages/4e/8a/91fab8e4fd2a24930a17188c7af5380eb27b203d72101c9cc000dbdfd95a/librt-0.8.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d3a7da44baf692f0c6aeb5b2a09c5e6fc7a703bca9ffa337ddd2e2da53f7732", size = 238866, upload-time = "2026-02-17T16:12:37.849Z" }, - { url = "https://files.pythonhosted.org/packages/b9/e0/c45a098843fc7c07e18a7f8a24ca8496aecbf7bdcd54980c6ca1aaa79a8e/librt-0.8.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fc48998000cbc39ec0d5311312dda93ecf92b39aaf184c5e817d5d440b29624", size = 250248, upload-time = "2026-02-17T16:12:39.445Z" }, - { url = "https://files.pythonhosted.org/packages/82/30/07627de23036640c952cce0c1fe78972e77d7d2f8fd54fa5ef4554ff4a56/librt-0.8.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e96baa6820280077a78244b2e06e416480ed859bbd8e5d641cf5742919d8beb4", size = 240629, upload-time = "2026-02-17T16:12:40.889Z" }, - { url = "https://files.pythonhosted.org/packages/fb/c1/55bfe1ee3542eba055616f9098eaf6eddb966efb0ca0f44eaa4aba327307/librt-0.8.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31362dbfe297b23590530007062c32c6f6176f6099646bb2c95ab1b00a57c382", size = 239615, upload-time = "2026-02-17T16:12:42.446Z" }, - { url = "https://files.pythonhosted.org/packages/2b/39/191d3d28abc26c9099b19852e6c99f7f6d400b82fa5a4e80291bd3803e19/librt-0.8.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc3656283d11540ab0ea01978378e73e10002145117055e03722417aeab30994", size = 263001, upload-time = "2026-02-17T16:12:43.627Z" }, - { url = "https://files.pythonhosted.org/packages/b9/eb/7697f60fbe7042ab4e88f4ee6af496b7f222fffb0a4e3593ef1f29f81652/librt-0.8.1-cp314-cp314t-win32.whl", hash = "sha256:738f08021b3142c2918c03692608baed43bc51144c29e35807682f8070ee2a3a", size = 51328, upload-time = "2026-02-17T16:12:45.148Z" }, - { url = "https://files.pythonhosted.org/packages/7c/72/34bf2eb7a15414a23e5e70ecb9440c1d3179f393d9349338a91e2781c0fb/librt-0.8.1-cp314-cp314t-win_amd64.whl", hash = "sha256:89815a22daf9c51884fb5dbe4f1ef65ee6a146e0b6a8df05f753e2e4a9359bf4", size = 58722, upload-time = "2026-02-17T16:12:46.85Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c8/d148e041732d631fc76036f8b30fae4e77b027a1e95b7a84bb522481a940/librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61", size = 48755, upload-time = "2026-02-17T16:12:47.943Z" }, -] - -[[package]] -name = "lxml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589, upload-time = "2025-09-22T04:00:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671, upload-time = "2025-09-22T04:00:15.411Z" }, - { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961, upload-time = "2025-09-22T04:00:17.619Z" }, - { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087, upload-time = "2025-09-22T04:00:19.868Z" }, - { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620, upload-time = "2025-09-22T04:00:21.877Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664, upload-time = "2025-09-22T04:00:23.714Z" }, - { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397, upload-time = "2025-09-22T04:00:25.544Z" }, - { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178, upload-time = "2025-09-22T04:00:27.602Z" }, - { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148, upload-time = "2025-09-22T04:00:29.323Z" }, - { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035, upload-time = "2025-09-22T04:00:31.061Z" }, - { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111, upload-time = "2025-09-22T04:00:33.11Z" }, - { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662, upload-time = "2025-09-22T04:00:35.237Z" }, - { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973, upload-time = "2025-09-22T04:00:37.086Z" }, - { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953, upload-time = "2025-09-22T04:00:39.224Z" }, - { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695, upload-time = "2025-09-22T04:00:41.402Z" }, - { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051, upload-time = "2025-09-22T04:00:43.525Z" }, - { url = "https://files.pythonhosted.org/packages/77/d5/becbe1e2569b474a23f0c672ead8a29ac50b2dc1d5b9de184831bda8d14c/lxml-6.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13e35cbc684aadf05d8711a5d1b5857c92e5e580efa9a0d2be197199c8def607", size = 8634365, upload-time = "2025-09-22T04:00:45.672Z" }, - { url = "https://files.pythonhosted.org/packages/28/66/1ced58f12e804644426b85d0bb8a4478ca77bc1761455da310505f1a3526/lxml-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1675e096e17c6fe9c0e8c81434f5736c0739ff9ac6123c87c2d452f48fc938", size = 4650793, upload-time = "2025-09-22T04:00:47.783Z" }, - { url = "https://files.pythonhosted.org/packages/11/84/549098ffea39dfd167e3f174b4ce983d0eed61f9d8d25b7bf2a57c3247fc/lxml-6.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac6e5811ae2870953390452e3476694196f98d447573234592d30488147404d", size = 4944362, upload-time = "2025-09-22T04:00:49.845Z" }, - { url = "https://files.pythonhosted.org/packages/ac/bd/f207f16abf9749d2037453d56b643a7471d8fde855a231a12d1e095c4f01/lxml-6.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5aa0fc67ae19d7a64c3fe725dc9a1bb11f80e01f78289d05c6f62545affec438", size = 5083152, upload-time = "2025-09-22T04:00:51.709Z" }, - { url = "https://files.pythonhosted.org/packages/15/ae/bd813e87d8941d52ad5b65071b1affb48da01c4ed3c9c99e40abb266fbff/lxml-6.0.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de496365750cc472b4e7902a485d3f152ecf57bd3ba03ddd5578ed8ceb4c5964", size = 5023539, upload-time = "2025-09-22T04:00:53.593Z" }, - { url = "https://files.pythonhosted.org/packages/02/cd/9bfef16bd1d874fbe0cb51afb00329540f30a3283beb9f0780adbb7eec03/lxml-6.0.2-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:200069a593c5e40b8f6fc0d84d86d970ba43138c3e68619ffa234bc9bb806a4d", size = 5344853, upload-time = "2025-09-22T04:00:55.524Z" }, - { url = "https://files.pythonhosted.org/packages/b8/89/ea8f91594bc5dbb879734d35a6f2b0ad50605d7fb419de2b63d4211765cc/lxml-6.0.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d2de809c2ee3b888b59f995625385f74629707c9355e0ff856445cdcae682b7", size = 5225133, upload-time = "2025-09-22T04:00:57.269Z" }, - { url = "https://files.pythonhosted.org/packages/b9/37/9c735274f5dbec726b2db99b98a43950395ba3d4a1043083dba2ad814170/lxml-6.0.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:b2c3da8d93cf5db60e8858c17684c47d01fee6405e554fb55018dd85fc23b178", size = 4677944, upload-time = "2025-09-22T04:00:59.052Z" }, - { url = "https://files.pythonhosted.org/packages/20/28/7dfe1ba3475d8bfca3878365075abe002e05d40dfaaeb7ec01b4c587d533/lxml-6.0.2-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:442de7530296ef5e188373a1ea5789a46ce90c4847e597856570439621d9c553", size = 5284535, upload-time = "2025-09-22T04:01:01.335Z" }, - { url = "https://files.pythonhosted.org/packages/e7/cf/5f14bc0de763498fc29510e3532bf2b4b3a1c1d5d0dff2e900c16ba021ef/lxml-6.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2593c77efde7bfea7f6389f1ab249b15ed4aa5bc5cb5131faa3b843c429fbedb", size = 5067343, upload-time = "2025-09-22T04:01:03.13Z" }, - { url = "https://files.pythonhosted.org/packages/1c/b0/bb8275ab5472f32b28cfbbcc6db7c9d092482d3439ca279d8d6fa02f7025/lxml-6.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3e3cb08855967a20f553ff32d147e14329b3ae70ced6edc2f282b94afbc74b2a", size = 4725419, upload-time = "2025-09-22T04:01:05.013Z" }, - { url = "https://files.pythonhosted.org/packages/25/4c/7c222753bc72edca3b99dbadba1b064209bc8ed4ad448af990e60dcce462/lxml-6.0.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ed6c667fcbb8c19c6791bbf40b7268ef8ddf5a96940ba9404b9f9a304832f6c", size = 5275008, upload-time = "2025-09-22T04:01:07.327Z" }, - { url = "https://files.pythonhosted.org/packages/6c/8c/478a0dc6b6ed661451379447cdbec77c05741a75736d97e5b2b729687828/lxml-6.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b8f18914faec94132e5b91e69d76a5c1d7b0c73e2489ea8929c4aaa10b76bbf7", size = 5248906, upload-time = "2025-09-22T04:01:09.452Z" }, - { url = "https://files.pythonhosted.org/packages/2d/d9/5be3a6ab2784cdf9accb0703b65e1b64fcdd9311c9f007630c7db0cfcce1/lxml-6.0.2-cp311-cp311-win32.whl", hash = "sha256:6605c604e6daa9e0d7f0a2137bdc47a2e93b59c60a65466353e37f8272f47c46", size = 3610357, upload-time = "2025-09-22T04:01:11.102Z" }, - { url = "https://files.pythonhosted.org/packages/e2/7d/ca6fb13349b473d5732fb0ee3eec8f6c80fc0688e76b7d79c1008481bf1f/lxml-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5867f2651016a3afd8dd2c8238baa66f1e2802f44bc17e236f547ace6647078", size = 4036583, upload-time = "2025-09-22T04:01:12.766Z" }, - { url = "https://files.pythonhosted.org/packages/ab/a2/51363b5ecd3eab46563645f3a2c3836a2fc67d01a1b87c5017040f39f567/lxml-6.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:4197fb2534ee05fd3e7afaab5d8bfd6c2e186f65ea7f9cd6a82809c887bd1285", size = 3680591, upload-time = "2025-09-22T04:01:14.874Z" }, - { url = "https://files.pythonhosted.org/packages/f3/c8/8ff2bc6b920c84355146cd1ab7d181bc543b89241cfb1ebee824a7c81457/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456", size = 8661887, upload-time = "2025-09-22T04:01:17.265Z" }, - { url = "https://files.pythonhosted.org/packages/37/6f/9aae1008083bb501ef63284220ce81638332f9ccbfa53765b2b7502203cf/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924", size = 4667818, upload-time = "2025-09-22T04:01:19.688Z" }, - { url = "https://files.pythonhosted.org/packages/f1/ca/31fb37f99f37f1536c133476674c10b577e409c0a624384147653e38baf2/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f", size = 4950807, upload-time = "2025-09-22T04:01:21.487Z" }, - { url = "https://files.pythonhosted.org/packages/da/87/f6cb9442e4bada8aab5ae7e1046264f62fdbeaa6e3f6211b93f4c0dd97f1/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534", size = 5109179, upload-time = "2025-09-22T04:01:23.32Z" }, - { url = "https://files.pythonhosted.org/packages/c8/20/a7760713e65888db79bbae4f6146a6ae5c04e4a204a3c48896c408cd6ed2/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564", size = 5023044, upload-time = "2025-09-22T04:01:25.118Z" }, - { url = "https://files.pythonhosted.org/packages/a2/b0/7e64e0460fcb36471899f75831509098f3fd7cd02a3833ac517433cb4f8f/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f", size = 5359685, upload-time = "2025-09-22T04:01:27.398Z" }, - { url = "https://files.pythonhosted.org/packages/b9/e1/e5df362e9ca4e2f48ed6411bd4b3a0ae737cc842e96877f5bf9428055ab4/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0", size = 5654127, upload-time = "2025-09-22T04:01:29.629Z" }, - { url = "https://files.pythonhosted.org/packages/c6/d1/232b3309a02d60f11e71857778bfcd4acbdb86c07db8260caf7d008b08f8/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192", size = 5253958, upload-time = "2025-09-22T04:01:31.535Z" }, - { url = "https://files.pythonhosted.org/packages/35/35/d955a070994725c4f7d80583a96cab9c107c57a125b20bb5f708fe941011/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0", size = 4711541, upload-time = "2025-09-22T04:01:33.801Z" }, - { url = "https://files.pythonhosted.org/packages/1e/be/667d17363b38a78c4bd63cfd4b4632029fd68d2c2dc81f25ce9eb5224dd5/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092", size = 5267426, upload-time = "2025-09-22T04:01:35.639Z" }, - { url = "https://files.pythonhosted.org/packages/ea/47/62c70aa4a1c26569bc958c9ca86af2bb4e1f614e8c04fb2989833874f7ae/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f", size = 5064917, upload-time = "2025-09-22T04:01:37.448Z" }, - { url = "https://files.pythonhosted.org/packages/bd/55/6ceddaca353ebd0f1908ef712c597f8570cc9c58130dbb89903198e441fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8", size = 4788795, upload-time = "2025-09-22T04:01:39.165Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e8/fd63e15da5e3fd4c2146f8bbb3c14e94ab850589beab88e547b2dbce22e1/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f", size = 5676759, upload-time = "2025-09-22T04:01:41.506Z" }, - { url = "https://files.pythonhosted.org/packages/76/47/b3ec58dc5c374697f5ba37412cd2728f427d056315d124dd4b61da381877/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6", size = 5255666, upload-time = "2025-09-22T04:01:43.363Z" }, - { url = "https://files.pythonhosted.org/packages/19/93/03ba725df4c3d72afd9596eef4a37a837ce8e4806010569bedfcd2cb68fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322", size = 5277989, upload-time = "2025-09-22T04:01:45.215Z" }, - { url = "https://files.pythonhosted.org/packages/c6/80/c06de80bfce881d0ad738576f243911fccf992687ae09fd80b734712b39c/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849", size = 3611456, upload-time = "2025-09-22T04:01:48.243Z" }, - { url = "https://files.pythonhosted.org/packages/f7/d7/0cdfb6c3e30893463fb3d1e52bc5f5f99684a03c29a0b6b605cfae879cd5/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f", size = 4011793, upload-time = "2025-09-22T04:01:50.042Z" }, - { url = "https://files.pythonhosted.org/packages/ea/7b/93c73c67db235931527301ed3785f849c78991e2e34f3fd9a6663ffda4c5/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6", size = 3672836, upload-time = "2025-09-22T04:01:52.145Z" }, - { url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" }, - { url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" }, - { url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" }, - { url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" }, - { url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" }, - { url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" }, - { url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" }, - { url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" }, - { url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" }, - { url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" }, - { url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" }, - { url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" }, - { url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" }, - { url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" }, - { url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" }, - { url = "https://files.pythonhosted.org/packages/03/15/d4a377b385ab693ce97b472fe0c77c2b16ec79590e688b3ccc71fba19884/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe", size = 8659801, upload-time = "2025-09-22T04:02:30.113Z" }, - { url = "https://files.pythonhosted.org/packages/c8/e8/c128e37589463668794d503afaeb003987373c5f94d667124ffd8078bbd9/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d", size = 4659403, upload-time = "2025-09-22T04:02:32.119Z" }, - { url = "https://files.pythonhosted.org/packages/00/ce/74903904339decdf7da7847bb5741fc98a5451b42fc419a86c0c13d26fe2/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d", size = 4966974, upload-time = "2025-09-22T04:02:34.155Z" }, - { url = "https://files.pythonhosted.org/packages/1f/d3/131dec79ce61c5567fecf82515bd9bc36395df42501b50f7f7f3bd065df0/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5", size = 5102953, upload-time = "2025-09-22T04:02:36.054Z" }, - { url = "https://files.pythonhosted.org/packages/3a/ea/a43ba9bb750d4ffdd885f2cd333572f5bb900cd2408b67fdda07e85978a0/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0", size = 5055054, upload-time = "2025-09-22T04:02:38.154Z" }, - { url = "https://files.pythonhosted.org/packages/60/23/6885b451636ae286c34628f70a7ed1fcc759f8d9ad382d132e1c8d3d9bfd/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba", size = 5352421, upload-time = "2025-09-22T04:02:40.413Z" }, - { url = "https://files.pythonhosted.org/packages/48/5b/fc2ddfc94ddbe3eebb8e9af6e3fd65e2feba4967f6a4e9683875c394c2d8/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0", size = 5673684, upload-time = "2025-09-22T04:02:42.288Z" }, - { url = "https://files.pythonhosted.org/packages/29/9c/47293c58cc91769130fbf85531280e8cc7868f7fbb6d92f4670071b9cb3e/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d", size = 5252463, upload-time = "2025-09-22T04:02:44.165Z" }, - { url = "https://files.pythonhosted.org/packages/9b/da/ba6eceb830c762b48e711ded880d7e3e89fc6c7323e587c36540b6b23c6b/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37", size = 4698437, upload-time = "2025-09-22T04:02:46.524Z" }, - { url = "https://files.pythonhosted.org/packages/a5/24/7be3f82cb7990b89118d944b619e53c656c97dc89c28cfb143fdb7cd6f4d/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9", size = 5269890, upload-time = "2025-09-22T04:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/1b/bd/dcfb9ea1e16c665efd7538fc5d5c34071276ce9220e234217682e7d2c4a5/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917", size = 5097185, upload-time = "2025-09-22T04:02:50.746Z" }, - { url = "https://files.pythonhosted.org/packages/21/04/a60b0ff9314736316f28316b694bccbbabe100f8483ad83852d77fc7468e/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f", size = 4745895, upload-time = "2025-09-22T04:02:52.968Z" }, - { url = "https://files.pythonhosted.org/packages/d6/bd/7d54bd1846e5a310d9c715921c5faa71cf5c0853372adf78aee70c8d7aa2/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8", size = 5695246, upload-time = "2025-09-22T04:02:54.798Z" }, - { url = "https://files.pythonhosted.org/packages/fd/32/5643d6ab947bc371da21323acb2a6e603cedbe71cb4c99c8254289ab6f4e/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a", size = 5260797, upload-time = "2025-09-22T04:02:57.058Z" }, - { url = "https://files.pythonhosted.org/packages/33/da/34c1ec4cff1eea7d0b4cd44af8411806ed943141804ac9c5d565302afb78/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c", size = 5277404, upload-time = "2025-09-22T04:02:58.966Z" }, - { url = "https://files.pythonhosted.org/packages/82/57/4eca3e31e54dc89e2c3507e1cd411074a17565fa5ffc437c4ae0a00d439e/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b", size = 3670072, upload-time = "2025-09-22T04:03:38.05Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e0/c96cf13eccd20c9421ba910304dae0f619724dcf1702864fd59dd386404d/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed", size = 4080617, upload-time = "2025-09-22T04:03:39.835Z" }, - { url = "https://files.pythonhosted.org/packages/d5/5d/b3f03e22b3d38d6f188ef044900a9b29b2fe0aebb94625ce9fe244011d34/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8", size = 3754930, upload-time = "2025-09-22T04:03:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5c/42c2c4c03554580708fc738d13414801f340c04c3eff90d8d2d227145275/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d", size = 8910380, upload-time = "2025-09-22T04:03:01.645Z" }, - { url = "https://files.pythonhosted.org/packages/bf/4f/12df843e3e10d18d468a7557058f8d3733e8b6e12401f30b1ef29360740f/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba", size = 4775632, upload-time = "2025-09-22T04:03:03.814Z" }, - { url = "https://files.pythonhosted.org/packages/e4/0c/9dc31e6c2d0d418483cbcb469d1f5a582a1cd00a1f4081953d44051f3c50/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601", size = 4975171, upload-time = "2025-09-22T04:03:05.651Z" }, - { url = "https://files.pythonhosted.org/packages/e7/2b/9b870c6ca24c841bdd887504808f0417aa9d8d564114689266f19ddf29c8/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed", size = 5110109, upload-time = "2025-09-22T04:03:07.452Z" }, - { url = "https://files.pythonhosted.org/packages/bf/0c/4f5f2a4dd319a178912751564471355d9019e220c20d7db3fb8307ed8582/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37", size = 5041061, upload-time = "2025-09-22T04:03:09.297Z" }, - { url = "https://files.pythonhosted.org/packages/12/64/554eed290365267671fe001a20d72d14f468ae4e6acef1e179b039436967/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338", size = 5306233, upload-time = "2025-09-22T04:03:11.651Z" }, - { url = "https://files.pythonhosted.org/packages/7a/31/1d748aa275e71802ad9722df32a7a35034246b42c0ecdd8235412c3396ef/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9", size = 5604739, upload-time = "2025-09-22T04:03:13.592Z" }, - { url = "https://files.pythonhosted.org/packages/8f/41/2c11916bcac09ed561adccacceaedd2bf0e0b25b297ea92aab99fd03d0fa/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd", size = 5225119, upload-time = "2025-09-22T04:03:15.408Z" }, - { url = "https://files.pythonhosted.org/packages/99/05/4e5c2873d8f17aa018e6afde417c80cc5d0c33be4854cce3ef5670c49367/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d", size = 4633665, upload-time = "2025-09-22T04:03:17.262Z" }, - { url = "https://files.pythonhosted.org/packages/0f/c9/dcc2da1bebd6275cdc723b515f93edf548b82f36a5458cca3578bc899332/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9", size = 5234997, upload-time = "2025-09-22T04:03:19.14Z" }, - { url = "https://files.pythonhosted.org/packages/9c/e2/5172e4e7468afca64a37b81dba152fc5d90e30f9c83c7c3213d6a02a5ce4/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e", size = 5090957, upload-time = "2025-09-22T04:03:21.436Z" }, - { url = "https://files.pythonhosted.org/packages/a5/b3/15461fd3e5cd4ddcb7938b87fc20b14ab113b92312fc97afe65cd7c85de1/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d", size = 4764372, upload-time = "2025-09-22T04:03:23.27Z" }, - { url = "https://files.pythonhosted.org/packages/05/33/f310b987c8bf9e61c4dd8e8035c416bd3230098f5e3cfa69fc4232de7059/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec", size = 5634653, upload-time = "2025-09-22T04:03:25.767Z" }, - { url = "https://files.pythonhosted.org/packages/70/ff/51c80e75e0bc9382158133bdcf4e339b5886c6ee2418b5199b3f1a61ed6d/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272", size = 5233795, upload-time = "2025-09-22T04:03:27.62Z" }, - { url = "https://files.pythonhosted.org/packages/56/4d/4856e897df0d588789dd844dbed9d91782c4ef0b327f96ce53c807e13128/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f", size = 5257023, upload-time = "2025-09-22T04:03:30.056Z" }, - { url = "https://files.pythonhosted.org/packages/0f/85/86766dfebfa87bea0ab78e9ff7a4b4b45225df4b4d3b8cc3c03c5cd68464/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312", size = 3911420, upload-time = "2025-09-22T04:03:32.198Z" }, - { url = "https://files.pythonhosted.org/packages/fe/1a/b248b355834c8e32614650b8008c69ffeb0ceb149c793961dd8c0b991bb3/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca", size = 4406837, upload-time = "2025-09-22T04:03:34.027Z" }, - { url = "https://files.pythonhosted.org/packages/92/aa/df863bcc39c5e0946263454aba394de8a9084dbaff8ad143846b0d844739/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c", size = 3822205, upload-time = "2025-09-22T04:03:36.249Z" }, - { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264, upload-time = "2025-09-22T04:04:32.892Z" }, - { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435, upload-time = "2025-09-22T04:04:34.907Z" }, - { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913, upload-time = "2025-09-22T04:04:37.205Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357, upload-time = "2025-09-22T04:04:39.322Z" }, - { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295, upload-time = "2025-09-22T04:04:41.647Z" }, - { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913, upload-time = "2025-09-22T04:04:43.602Z" }, - { url = "https://files.pythonhosted.org/packages/0b/11/29d08bc103a62c0eba8016e7ed5aeebbf1e4312e83b0b1648dd203b0e87d/lxml-6.0.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c06035eafa8404b5cf475bb37a9f6088b0aca288d4ccc9d69389750d5543700", size = 3949829, upload-time = "2025-09-22T04:04:45.608Z" }, - { url = "https://files.pythonhosted.org/packages/12/b3/52ab9a3b31e5ab8238da241baa19eec44d2ab426532441ee607165aebb52/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c7d13103045de1bdd6fe5d61802565f1a3537d70cd3abf596aa0af62761921ee", size = 4226277, upload-time = "2025-09-22T04:04:47.754Z" }, - { url = "https://files.pythonhosted.org/packages/a0/33/1eaf780c1baad88224611df13b1c2a9dfa460b526cacfe769103ff50d845/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a3c150a95fbe5ac91de323aa756219ef9cf7fde5a3f00e2281e30f33fa5fa4f", size = 4330433, upload-time = "2025-09-22T04:04:49.907Z" }, - { url = "https://files.pythonhosted.org/packages/7a/c1/27428a2ff348e994ab4f8777d3a0ad510b6b92d37718e5887d2da99952a2/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60fa43be34f78bebb27812ed90f1925ec99560b0fa1decdb7d12b84d857d31e9", size = 4272119, upload-time = "2025-09-22T04:04:51.801Z" }, - { url = "https://files.pythonhosted.org/packages/f0/d0/3020fa12bcec4ab62f97aab026d57c2f0cfd480a558758d9ca233bb6a79d/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21c73b476d3cfe836be731225ec3421fa2f048d84f6df6a8e70433dff1376d5a", size = 4417314, upload-time = "2025-09-22T04:04:55.024Z" }, - { url = "https://files.pythonhosted.org/packages/6c/77/d7f491cbc05303ac6801651aabeb262d43f319288c1ea96c66b1d2692ff3/lxml-6.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:27220da5be049e936c3aca06f174e8827ca6445a4353a1995584311487fc4e3e", size = 3518768, upload-time = "2025-09-22T04:04:57.097Z" }, -] - [[package]] name = "mako" version = "1.3.10" @@ -1290,41 +743,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, ] -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "mdurl", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - [[package]] name = "markdown-it-py" version = "4.0.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] dependencies = [ - { name = "mdurl", marker = "python_full_version >= '3.11'" }, + { name = "mdurl" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } wheels = [ @@ -1337,61 +761,6 @@ version = "3.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, - { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, - { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, - { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, - { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, - { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, - { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, - { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, - { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, - { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, - { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, - { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, - { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, - { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, - { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, - { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, - { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, - { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, - { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, - { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, - { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, - { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, - { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, - { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, - { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, - { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, - { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, - { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, - { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, - { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, - { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, - { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, - { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, - { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, - { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, - { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, - { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, - { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, - { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, - { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, - { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, - { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, - { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, - { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, - { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, - { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, - { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, - { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, - { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, @@ -1421,8 +790,7 @@ name = "mdit-py-plugins" version = "0.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "markdown-it-py" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b2/fd/a756d36c0bfba5f6e39a1cdbdbfdd448dc02692467d83816dff4592a1ebc/mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6", size = 44655, upload-time = "2025-08-11T07:25:49.083Z" } wheels = [ @@ -1438,116 +806,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] -[[package]] -name = "more-itertools" -version = "10.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, -] - -[[package]] -name = "mypy" -version = "1.19.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, - { name = "mypy-extensions" }, - { name = "pathspec" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/63/e499890d8e39b1ff2df4c0c6ce5d371b6844ee22b8250687a99fd2f657a8/mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec", size = 13101333, upload-time = "2025-12-15T05:03:03.28Z" }, - { url = "https://files.pythonhosted.org/packages/72/4b/095626fc136fba96effc4fd4a82b41d688ab92124f8c4f7564bffe5cf1b0/mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b", size = 12164102, upload-time = "2025-12-15T05:02:33.611Z" }, - { url = "https://files.pythonhosted.org/packages/0c/5b/952928dd081bf88a83a5ccd49aaecfcd18fd0d2710c7ff07b8fb6f7032b9/mypy-1.19.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee4c11e460685c3e0c64a4c5de82ae143622410950d6be863303a1c4ba0e36d6", size = 12765799, upload-time = "2025-12-15T05:03:28.44Z" }, - { url = "https://files.pythonhosted.org/packages/2a/0d/93c2e4a287f74ef11a66fb6d49c7a9f05e47b0a4399040e6719b57f500d2/mypy-1.19.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de759aafbae8763283b2ee5869c7255391fbc4de3ff171f8f030b5ec48381b74", size = 13522149, upload-time = "2025-12-15T05:02:36.011Z" }, - { url = "https://files.pythonhosted.org/packages/7b/0e/33a294b56aaad2b338d203e3a1d8b453637ac36cb278b45005e0901cf148/mypy-1.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ab43590f9cd5108f41aacf9fca31841142c786827a74ab7cc8a2eacb634e09a1", size = 13810105, upload-time = "2025-12-15T05:02:40.327Z" }, - { url = "https://files.pythonhosted.org/packages/0e/fd/3e82603a0cb66b67c5e7abababce6bf1a929ddf67bf445e652684af5c5a0/mypy-1.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:2899753e2f61e571b3971747e302d5f420c3fd09650e1951e99f823bc3089dac", size = 10057200, upload-time = "2025-12-15T05:02:51.012Z" }, - { url = "https://files.pythonhosted.org/packages/ef/47/6b3ebabd5474d9cdc170d1342fbf9dddc1b0ec13ec90bf9004ee6f391c31/mypy-1.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288", size = 13028539, upload-time = "2025-12-15T05:03:44.129Z" }, - { url = "https://files.pythonhosted.org/packages/5c/a6/ac7c7a88a3c9c54334f53a941b765e6ec6c4ebd65d3fe8cdcfbe0d0fd7db/mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab", size = 12083163, upload-time = "2025-12-15T05:03:37.679Z" }, - { url = "https://files.pythonhosted.org/packages/67/af/3afa9cf880aa4a2c803798ac24f1d11ef72a0c8079689fac5cfd815e2830/mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6", size = 12687629, upload-time = "2025-12-15T05:02:31.526Z" }, - { url = "https://files.pythonhosted.org/packages/2d/46/20f8a7114a56484ab268b0ab372461cb3a8f7deed31ea96b83a4e4cfcfca/mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331", size = 13436933, upload-time = "2025-12-15T05:03:15.606Z" }, - { url = "https://files.pythonhosted.org/packages/5b/f8/33b291ea85050a21f15da910002460f1f445f8007adb29230f0adea279cb/mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925", size = 13661754, upload-time = "2025-12-15T05:02:26.731Z" }, - { url = "https://files.pythonhosted.org/packages/fd/a3/47cbd4e85bec4335a9cd80cf67dbc02be21b5d4c9c23ad6b95d6c5196bac/mypy-1.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042", size = 10055772, upload-time = "2025-12-15T05:03:26.179Z" }, - { url = "https://files.pythonhosted.org/packages/06/8a/19bfae96f6615aa8a0604915512e0289b1fad33d5909bf7244f02935d33a/mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1", size = 13206053, upload-time = "2025-12-15T05:03:46.622Z" }, - { url = "https://files.pythonhosted.org/packages/a5/34/3e63879ab041602154ba2a9f99817bb0c85c4df19a23a1443c8986e4d565/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e", size = 12219134, upload-time = "2025-12-15T05:03:24.367Z" }, - { url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" }, - { url = "https://files.pythonhosted.org/packages/00/be/dd56c1fd4807bc1eba1cf18b2a850d0de7bacb55e158755eb79f77c41f8e/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8", size = 13620847, upload-time = "2025-12-15T05:03:39.633Z" }, - { url = "https://files.pythonhosted.org/packages/6d/42/332951aae42b79329f743bf1da088cd75d8d4d9acc18fbcbd84f26c1af4e/mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a", size = 13834976, upload-time = "2025-12-15T05:03:08.786Z" }, - { url = "https://files.pythonhosted.org/packages/6f/63/e7493e5f90e1e085c562bb06e2eb32cae27c5057b9653348d38b47daaecc/mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13", size = 10118104, upload-time = "2025-12-15T05:03:10.834Z" }, - { url = "https://files.pythonhosted.org/packages/de/9f/a6abae693f7a0c697dbb435aac52e958dc8da44e92e08ba88d2e42326176/mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250", size = 13201927, upload-time = "2025-12-15T05:02:29.138Z" }, - { url = "https://files.pythonhosted.org/packages/9a/a4/45c35ccf6e1c65afc23a069f50e2c66f46bd3798cbe0d680c12d12935caa/mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b", size = 12206730, upload-time = "2025-12-15T05:03:01.325Z" }, - { url = "https://files.pythonhosted.org/packages/05/bb/cdcf89678e26b187650512620eec8368fded4cfd99cfcb431e4cdfd19dec/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e", size = 12724581, upload-time = "2025-12-15T05:03:20.087Z" }, - { url = "https://files.pythonhosted.org/packages/d1/32/dd260d52babf67bad8e6770f8e1102021877ce0edea106e72df5626bb0ec/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef", size = 13616252, upload-time = "2025-12-15T05:02:49.036Z" }, - { url = "https://files.pythonhosted.org/packages/71/d0/5e60a9d2e3bd48432ae2b454b7ef2b62a960ab51292b1eda2a95edd78198/mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75", size = 13840848, upload-time = "2025-12-15T05:02:55.95Z" }, - { url = "https://files.pythonhosted.org/packages/98/76/d32051fa65ecf6cc8c6610956473abdc9b4c43301107476ac03559507843/mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd", size = 10135510, upload-time = "2025-12-15T05:02:58.438Z" }, - { url = "https://files.pythonhosted.org/packages/de/eb/b83e75f4c820c4247a58580ef86fcd35165028f191e7e1ba57128c52782d/mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1", size = 13199744, upload-time = "2025-12-15T05:03:30.823Z" }, - { url = "https://files.pythonhosted.org/packages/94/28/52785ab7bfa165f87fcbb61547a93f98bb20e7f82f90f165a1f69bce7b3d/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718", size = 12215815, upload-time = "2025-12-15T05:02:42.323Z" }, - { url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" }, - { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" }, - { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" }, - { url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" }, -] - -[[package]] -name = "mypy-extensions" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, -] - -[[package]] -name = "myst-parser" -version = "4.0.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "docutils", version = "0.21.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "jinja2", marker = "python_full_version < '3.11'" }, - { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "mdit-py-plugins", marker = "python_full_version < '3.11'" }, - { name = "pyyaml", marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/a5/9626ba4f73555b3735ad86247a8077d4603aa8628537687c839ab08bfe44/myst_parser-4.0.1.tar.gz", hash = "sha256:5cfea715e4f3574138aecbf7d54132296bfd72bb614d31168f48c477a830a7c4", size = 93985, upload-time = "2025-02-12T10:53:03.833Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/df/76d0321c3797b54b60fef9ec3bd6f4cfd124b9e422182156a1dd418722cf/myst_parser-4.0.1-py3-none-any.whl", hash = "sha256:9134e88959ec3b5780aedf8a99680ea242869d012e8821db3126d427edc9c95d", size = 84579, upload-time = "2025-02-12T10:53:02.078Z" }, -] - [[package]] name = "myst-parser" version = "5.0.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] dependencies = [ - { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "jinja2", marker = "python_full_version >= '3.11'" }, - { name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "mdit-py-plugins", marker = "python_full_version >= '3.11'" }, - { name = "pyyaml", marker = "python_full_version >= '3.11'" }, - { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, - { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "docutils" }, + { name = "jinja2" }, + { name = "markdown-it-py" }, + { name = "mdit-py-plugins" }, + { name = "pyyaml" }, + { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/fa/7b45eef11b7971f0beb29d27b7bfe0d747d063aa29e170d9edd004733c8a/myst_parser-5.0.0.tar.gz", hash = "sha256:f6f231452c56e8baa662cc352c548158f6a16fcbd6e3800fc594978002b94f3a", size = 98535, upload-time = "2026-01-15T09:08:18.036Z" } wheels = [ @@ -1556,160 +825,31 @@ wheels = [ [[package]] name = "numpy" -version = "2.2.6" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, - { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, - { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, - { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, - { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, - { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, - { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, - { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, - { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, - { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, - { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, - { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, - { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, - { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, - { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, - { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, - { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, - { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, - { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, - { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, - { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, - { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, - { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, - { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, - { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, - { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, - { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, - { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, - { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, - { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, - { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, - { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, - { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, - { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, - { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, - { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, - { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, - { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, - { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, - { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, - { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, - { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, - { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, - { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, - { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, -] - -[[package]] -name = "numpy" -version = "2.4.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -sdist = { url = "https://files.pythonhosted.org/packages/10/8b/c265f4823726ab832de836cdd184d0986dcf94480f81e8739692a7ac7af2/numpy-2.4.3.tar.gz", hash = "sha256:483a201202b73495f00dbc83796c6ae63137a9bdade074f7648b3e32613412dd", size = 20727743, upload-time = "2026-03-09T07:58:53.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/51/5093a2df15c4dc19da3f79d1021e891f5dcf1d9d1db6ba38891d5590f3fe/numpy-2.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:33b3bf58ee84b172c067f56aeadc7ee9ab6de69c5e800ab5b10295d54c581adb", size = 16957183, upload-time = "2026-03-09T07:55:57.774Z" }, - { url = "https://files.pythonhosted.org/packages/b5/7c/c061f3de0630941073d2598dc271ac2f6cbcf5c83c74a5870fea07488333/numpy-2.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ba7b51e71c05aa1f9bc3641463cd82308eab40ce0d5c7e1fd4038cbf9938147", size = 14968734, upload-time = "2026-03-09T07:56:00.494Z" }, - { url = "https://files.pythonhosted.org/packages/ef/27/d26c85cbcd86b26e4f125b0668e7a7c0542d19dd7d23ee12e87b550e95b5/numpy-2.4.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a1988292870c7cb9d0ebb4cc96b4d447513a9644801de54606dc7aabf2b7d920", size = 5475288, upload-time = "2026-03-09T07:56:02.857Z" }, - { url = "https://files.pythonhosted.org/packages/2b/09/3c4abbc1dcd8010bf1a611d174c7aa689fc505585ec806111b4406f6f1b1/numpy-2.4.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:23b46bb6d8ecb68b58c09944483c135ae5f0e9b8d8858ece5e4ead783771d2a9", size = 6805253, upload-time = "2026-03-09T07:56:04.53Z" }, - { url = "https://files.pythonhosted.org/packages/21/bc/e7aa3f6817e40c3f517d407742337cbb8e6fc4b83ce0b55ab780c829243b/numpy-2.4.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a016db5c5dba78fa8fe9f5d80d6708f9c42ab087a739803c0ac83a43d686a470", size = 15969479, upload-time = "2026-03-09T07:56:06.638Z" }, - { url = "https://files.pythonhosted.org/packages/78/51/9f5d7a41f0b51649ddf2f2320595e15e122a40610b233d51928dd6c92353/numpy-2.4.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:715de7f82e192e8cae5a507a347d97ad17598f8e026152ca97233e3666daaa71", size = 16901035, upload-time = "2026-03-09T07:56:09.405Z" }, - { url = "https://files.pythonhosted.org/packages/64/6e/b221dd847d7181bc5ee4857bfb026182ef69499f9305eb1371cbb1aea626/numpy-2.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2ddb7919366ee468342b91dea2352824c25b55814a987847b6c52003a7c97f15", size = 17325657, upload-time = "2026-03-09T07:56:12.067Z" }, - { url = "https://files.pythonhosted.org/packages/eb/b8/8f3fd2da596e1063964b758b5e3c970aed1949a05200d7e3d46a9d46d643/numpy-2.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a315e5234d88067f2d97e1f2ef670a7569df445d55400f1e33d117418d008d52", size = 18635512, upload-time = "2026-03-09T07:56:14.629Z" }, - { url = "https://files.pythonhosted.org/packages/5c/24/2993b775c37e39d2f8ab4125b44337ab0b2ba106c100980b7c274a22bee7/numpy-2.4.3-cp311-cp311-win32.whl", hash = "sha256:2b3f8d2c4589b1a2028d2a770b0fc4d1f332fb5e01521f4de3199a896d158ddd", size = 6238100, upload-time = "2026-03-09T07:56:17.243Z" }, - { url = "https://files.pythonhosted.org/packages/76/1d/edccf27adedb754db7c4511d5eac8b83f004ae948fe2d3509e8b78097d4c/numpy-2.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:77e76d932c49a75617c6d13464e41203cd410956614d0a0e999b25e9e8d27eec", size = 12609816, upload-time = "2026-03-09T07:56:19.089Z" }, - { url = "https://files.pythonhosted.org/packages/92/82/190b99153480076c8dce85f4cfe7d53ea84444145ffa54cb58dcd460d66b/numpy-2.4.3-cp311-cp311-win_arm64.whl", hash = "sha256:eb610595dd91560905c132c709412b512135a60f1851ccbd2c959e136431ff67", size = 10485757, upload-time = "2026-03-09T07:56:21.753Z" }, - { url = "https://files.pythonhosted.org/packages/a9/ed/6388632536f9788cea23a3a1b629f25b43eaacd7d7377e5d6bc7b9deb69b/numpy-2.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:61b0cbabbb6126c8df63b9a3a0c4b1f44ebca5e12ff6997b80fcf267fb3150ef", size = 16669628, upload-time = "2026-03-09T07:56:24.252Z" }, - { url = "https://files.pythonhosted.org/packages/74/1b/ee2abfc68e1ce728b2958b6ba831d65c62e1b13ce3017c13943f8f9b5b2e/numpy-2.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7395e69ff32526710748f92cd8c9849b361830968ea3e24a676f272653e8983e", size = 14696872, upload-time = "2026-03-09T07:56:26.991Z" }, - { url = "https://files.pythonhosted.org/packages/ba/d1/780400e915ff5638166f11ca9dc2c5815189f3d7cf6f8759a1685e586413/numpy-2.4.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:abdce0f71dcb4a00e4e77f3faf05e4616ceccfe72ccaa07f47ee79cda3b7b0f4", size = 5203489, upload-time = "2026-03-09T07:56:29.414Z" }, - { url = "https://files.pythonhosted.org/packages/0b/bb/baffa907e9da4cc34a6e556d6d90e032f6d7a75ea47968ea92b4858826c4/numpy-2.4.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:48da3a4ee1336454b07497ff7ec83903efa5505792c4e6d9bf83d99dc07a1e18", size = 6550814, upload-time = "2026-03-09T07:56:32.225Z" }, - { url = "https://files.pythonhosted.org/packages/7b/12/8c9f0c6c95f76aeb20fc4a699c33e9f827fa0d0f857747c73bb7b17af945/numpy-2.4.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32e3bef222ad6b052280311d1d60db8e259e4947052c3ae7dd6817451fc8a4c5", size = 15666601, upload-time = "2026-03-09T07:56:34.461Z" }, - { url = "https://files.pythonhosted.org/packages/bd/79/cc665495e4d57d0aa6fbcc0aa57aa82671dfc78fbf95fe733ed86d98f52a/numpy-2.4.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7dd01a46700b1967487141a66ac1a3cf0dd8ebf1f08db37d46389401512ca97", size = 16621358, upload-time = "2026-03-09T07:56:36.852Z" }, - { url = "https://files.pythonhosted.org/packages/a8/40/b4ecb7224af1065c3539f5ecfff879d090de09608ad1008f02c05c770cb3/numpy-2.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:76f0f283506c28b12bba319c0fab98217e9f9b54e6160e9c79e9f7348ba32e9c", size = 17016135, upload-time = "2026-03-09T07:56:39.337Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b1/6a88e888052eed951afed7a142dcdf3b149a030ca59b4c71eef085858e43/numpy-2.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737f630a337364665aba3b5a77e56a68cc42d350edd010c345d65a3efa3addcc", size = 18345816, upload-time = "2026-03-09T07:56:42.31Z" }, - { url = "https://files.pythonhosted.org/packages/f3/8f/103a60c5f8c3d7fc678c19cd7b2476110da689ccb80bc18050efbaeae183/numpy-2.4.3-cp312-cp312-win32.whl", hash = "sha256:26952e18d82a1dbbc2f008d402021baa8d6fc8e84347a2072a25e08b46d698b9", size = 5960132, upload-time = "2026-03-09T07:56:44.851Z" }, - { url = "https://files.pythonhosted.org/packages/d7/7c/f5ee1bf6ed888494978046a809df2882aad35d414b622893322df7286879/numpy-2.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:65f3c2455188f09678355f5cae1f959a06b778bc66d535da07bf2ef20cd319d5", size = 12316144, upload-time = "2026-03-09T07:56:47.057Z" }, - { url = "https://files.pythonhosted.org/packages/71/46/8d1cb3f7a00f2fb6394140e7e6623696e54c6318a9d9691bb4904672cf42/numpy-2.4.3-cp312-cp312-win_arm64.whl", hash = "sha256:2abad5c7fef172b3377502bde47892439bae394a71bc329f31df0fd829b41a9e", size = 10220364, upload-time = "2026-03-09T07:56:49.849Z" }, - { url = "https://files.pythonhosted.org/packages/b6/d0/1fe47a98ce0df229238b77611340aff92d52691bcbc10583303181abf7fc/numpy-2.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b346845443716c8e542d54112966383b448f4a3ba5c66409771b8c0889485dd3", size = 16665297, upload-time = "2026-03-09T07:56:52.296Z" }, - { url = "https://files.pythonhosted.org/packages/27/d9/4e7c3f0e68dfa91f21c6fb6cf839bc829ec920688b1ce7ec722b1a6202fb/numpy-2.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2629289168f4897a3c4e23dc98d6f1731f0fc0fe52fb9db19f974041e4cc12b9", size = 14691853, upload-time = "2026-03-09T07:56:54.992Z" }, - { url = "https://files.pythonhosted.org/packages/3a/66/bd096b13a87549683812b53ab211e6d413497f84e794fb3c39191948da97/numpy-2.4.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bb2e3cf95854233799013779216c57e153c1ee67a0bf92138acca0e429aefaee", size = 5198435, upload-time = "2026-03-09T07:56:57.184Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2f/687722910b5a5601de2135c891108f51dfc873d8e43c8ed9f4ebb440b4a2/numpy-2.4.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:7f3408ff897f8ab07a07fbe2823d7aee6ff644c097cc1f90382511fe982f647f", size = 6546347, upload-time = "2026-03-09T07:56:59.531Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ec/7971c4e98d86c564750393fab8d7d83d0a9432a9d78bb8a163a6dc59967a/numpy-2.4.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:decb0eb8a53c3b009b0962378065589685d66b23467ef5dac16cbe818afde27f", size = 15664626, upload-time = "2026-03-09T07:57:01.385Z" }, - { url = "https://files.pythonhosted.org/packages/7e/eb/7daecbea84ec935b7fc732e18f532073064a3816f0932a40a17f3349185f/numpy-2.4.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5f51900414fc9204a0e0da158ba2ac52b75656e7dce7e77fb9f84bfa343b4cc", size = 16608916, upload-time = "2026-03-09T07:57:04.008Z" }, - { url = "https://files.pythonhosted.org/packages/df/58/2a2b4a817ffd7472dca4421d9f0776898b364154e30c95f42195041dc03b/numpy-2.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6bd06731541f89cdc01b261ba2c9e037f1543df7472517836b78dfb15bd6e476", size = 17015824, upload-time = "2026-03-09T07:57:06.347Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ca/627a828d44e78a418c55f82dd4caea8ea4a8ef24e5144d9e71016e52fb40/numpy-2.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:22654fe6be0e5206f553a9250762c653d3698e46686eee53b399ab90da59bd92", size = 18334581, upload-time = "2026-03-09T07:57:09.114Z" }, - { url = "https://files.pythonhosted.org/packages/cd/c0/76f93962fc79955fcba30a429b62304332345f22d4daec1cb33653425643/numpy-2.4.3-cp313-cp313-win32.whl", hash = "sha256:d71e379452a2f670ccb689ec801b1218cd3983e253105d6e83780967e899d687", size = 5958618, upload-time = "2026-03-09T07:57:11.432Z" }, - { url = "https://files.pythonhosted.org/packages/b1/3c/88af0040119209b9b5cb59485fa48b76f372c73068dbf9254784b975ac53/numpy-2.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:0a60e17a14d640f49146cb38e3f105f571318db7826d9b6fef7e4dce758faecd", size = 12312824, upload-time = "2026-03-09T07:57:13.586Z" }, - { url = "https://files.pythonhosted.org/packages/58/ce/3d07743aced3d173f877c3ef6a454c2174ba42b584ab0b7e6d99374f51ed/numpy-2.4.3-cp313-cp313-win_arm64.whl", hash = "sha256:c9619741e9da2059cd9c3f206110b97583c7152c1dc9f8aafd4beb450ac1c89d", size = 10221218, upload-time = "2026-03-09T07:57:16.183Z" }, - { url = "https://files.pythonhosted.org/packages/62/09/d96b02a91d09e9d97862f4fc8bfebf5400f567d8eb1fe4b0cc4795679c15/numpy-2.4.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7aa4e54f6469300ebca1d9eb80acd5253cdfa36f2c03d79a35883687da430875", size = 14819570, upload-time = "2026-03-09T07:57:18.564Z" }, - { url = "https://files.pythonhosted.org/packages/b5/ca/0b1aba3905fdfa3373d523b2b15b19029f4f3031c87f4066bd9d20ef6c6b/numpy-2.4.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d1b90d840b25874cf5cd20c219af10bac3667db3876d9a495609273ebe679070", size = 5326113, upload-time = "2026-03-09T07:57:21.052Z" }, - { url = "https://files.pythonhosted.org/packages/c0/63/406e0fd32fcaeb94180fd6a4c41e55736d676c54346b7efbce548b94a914/numpy-2.4.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a749547700de0a20a6718293396ec237bb38218049cfce788e08fcb716e8cf73", size = 6646370, upload-time = "2026-03-09T07:57:22.804Z" }, - { url = "https://files.pythonhosted.org/packages/b6/d0/10f7dc157d4b37af92720a196be6f54f889e90dcd30dce9dc657ed92c257/numpy-2.4.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f3c4a151a2e529adf49c1d54f0f57ff8f9b233ee4d44af623a81553ab86368", size = 15723499, upload-time = "2026-03-09T07:57:24.693Z" }, - { url = "https://files.pythonhosted.org/packages/66/f1/d1c2bf1161396629701bc284d958dc1efa3a5a542aab83cf11ee6eb4cba5/numpy-2.4.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22c31dc07025123aedf7f2db9e91783df13f1776dc52c6b22c620870dc0fab22", size = 16657164, upload-time = "2026-03-09T07:57:27.676Z" }, - { url = "https://files.pythonhosted.org/packages/1a/be/cca19230b740af199ac47331a21c71e7a3d0ba59661350483c1600d28c37/numpy-2.4.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:148d59127ac95979d6f07e4d460f934ebdd6eed641db9c0db6c73026f2b2101a", size = 17081544, upload-time = "2026-03-09T07:57:30.664Z" }, - { url = "https://files.pythonhosted.org/packages/b9/c5/9602b0cbb703a0936fb40f8a95407e8171935b15846de2f0776e08af04c7/numpy-2.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a97cbf7e905c435865c2d939af3d93f99d18eaaa3cabe4256f4304fb51604349", size = 18380290, upload-time = "2026-03-09T07:57:33.763Z" }, - { url = "https://files.pythonhosted.org/packages/ed/81/9f24708953cd30be9ee36ec4778f4b112b45165812f2ada4cc5ea1c1f254/numpy-2.4.3-cp313-cp313t-win32.whl", hash = "sha256:be3b8487d725a77acccc9924f65fd8bce9af7fac8c9820df1049424a2115af6c", size = 6082814, upload-time = "2026-03-09T07:57:36.491Z" }, - { url = "https://files.pythonhosted.org/packages/e2/9e/52f6eaa13e1a799f0ab79066c17f7016a4a8ae0c1aefa58c82b4dab690b4/numpy-2.4.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1ec84fd7c8e652b0f4aaaf2e6e9cc8eaa9b1b80a537e06b2e3a2fb176eedcb26", size = 12452673, upload-time = "2026-03-09T07:57:38.281Z" }, - { url = "https://files.pythonhosted.org/packages/c4/04/b8cece6ead0b30c9fbd99bb835ad7ea0112ac5f39f069788c5558e3b1ab2/numpy-2.4.3-cp313-cp313t-win_arm64.whl", hash = "sha256:120df8c0a81ebbf5b9020c91439fccd85f5e018a927a39f624845be194a2be02", size = 10290907, upload-time = "2026-03-09T07:57:40.747Z" }, - { url = "https://files.pythonhosted.org/packages/70/ae/3936f79adebf8caf81bd7a599b90a561334a658be4dcc7b6329ebf4ee8de/numpy-2.4.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5884ce5c7acfae1e4e1b6fde43797d10aa506074d25b531b4f54bde33c0c31d4", size = 16664563, upload-time = "2026-03-09T07:57:43.817Z" }, - { url = "https://files.pythonhosted.org/packages/9b/62/760f2b55866b496bb1fa7da2a6db076bef908110e568b02fcfc1422e2a3a/numpy-2.4.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:297837823f5bc572c5f9379b0c9f3a3365f08492cbdc33bcc3af174372ebb168", size = 14702161, upload-time = "2026-03-09T07:57:46.169Z" }, - { url = "https://files.pythonhosted.org/packages/32/af/a7a39464e2c0a21526fb4fb76e346fb172ebc92f6d1c7a07c2c139cc17b1/numpy-2.4.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:a111698b4a3f8dcbe54c64a7708f049355abd603e619013c346553c1fd4ca90b", size = 5208738, upload-time = "2026-03-09T07:57:48.506Z" }, - { url = "https://files.pythonhosted.org/packages/29/8c/2a0cf86a59558fa078d83805589c2de490f29ed4fb336c14313a161d358a/numpy-2.4.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:4bd4741a6a676770e0e97fe9ab2e51de01183df3dcbcec591d26d331a40de950", size = 6543618, upload-time = "2026-03-09T07:57:50.591Z" }, - { url = "https://files.pythonhosted.org/packages/aa/b8/612ce010c0728b1c363fa4ea3aa4c22fe1c5da1de008486f8c2f5cb92fae/numpy-2.4.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:54f29b877279d51e210e0c80709ee14ccbbad647810e8f3d375561c45ef613dd", size = 15680676, upload-time = "2026-03-09T07:57:52.34Z" }, - { url = "https://files.pythonhosted.org/packages/a9/7e/4f120ecc54ba26ddf3dc348eeb9eb063f421de65c05fc961941798feea18/numpy-2.4.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:679f2a834bae9020f81534671c56fd0cc76dd7e5182f57131478e23d0dc59e24", size = 16613492, upload-time = "2026-03-09T07:57:54.91Z" }, - { url = "https://files.pythonhosted.org/packages/2c/86/1b6020db73be330c4b45d5c6ee4295d59cfeef0e3ea323959d053e5a6909/numpy-2.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d84f0f881cb2225c2dfd7f78a10a5645d487a496c6668d6cc39f0f114164f3d0", size = 17031789, upload-time = "2026-03-09T07:57:57.641Z" }, - { url = "https://files.pythonhosted.org/packages/07/3a/3b90463bf41ebc21d1b7e06079f03070334374208c0f9a1f05e4ae8455e7/numpy-2.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d213c7e6e8d211888cc359bab7199670a00f5b82c0978b9d1c75baf1eddbeac0", size = 18339941, upload-time = "2026-03-09T07:58:00.577Z" }, - { url = "https://files.pythonhosted.org/packages/a8/74/6d736c4cd962259fd8bae9be27363eb4883a2f9069763747347544c2a487/numpy-2.4.3-cp314-cp314-win32.whl", hash = "sha256:52077feedeff7c76ed7c9f1a0428558e50825347b7545bbb8523da2cd55c547a", size = 6007503, upload-time = "2026-03-09T07:58:03.331Z" }, - { url = "https://files.pythonhosted.org/packages/48/39/c56ef87af669364356bb011922ef0734fc49dad51964568634c72a009488/numpy-2.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:0448e7f9caefb34b4b7dd2b77f21e8906e5d6f0365ad525f9f4f530b13df2afc", size = 12444915, upload-time = "2026-03-09T07:58:06.353Z" }, - { url = "https://files.pythonhosted.org/packages/9d/1f/ab8528e38d295fd349310807496fabb7cf9fe2e1f70b97bc20a483ea9d4a/numpy-2.4.3-cp314-cp314-win_arm64.whl", hash = "sha256:b44fd60341c4d9783039598efadd03617fa28d041fc37d22b62d08f2027fa0e7", size = 10494875, upload-time = "2026-03-09T07:58:08.734Z" }, - { url = "https://files.pythonhosted.org/packages/e6/ef/b7c35e4d5ef141b836658ab21a66d1a573e15b335b1d111d31f26c8ef80f/numpy-2.4.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0a195f4216be9305a73c0e91c9b026a35f2161237cf1c6de9b681637772ea657", size = 14822225, upload-time = "2026-03-09T07:58:11.034Z" }, - { url = "https://files.pythonhosted.org/packages/cd/8d/7730fa9278cf6648639946cc816e7cc89f0d891602584697923375f801ed/numpy-2.4.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:cd32fbacb9fd1bf041bf8e89e4576b6f00b895f06d00914820ae06a616bdfef7", size = 5328769, upload-time = "2026-03-09T07:58:13.67Z" }, - { url = "https://files.pythonhosted.org/packages/47/01/d2a137317c958b074d338807c1b6a383406cdf8b8e53b075d804cc3d211d/numpy-2.4.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:2e03c05abaee1f672e9d67bc858f300b5ccba1c21397211e8d77d98350972093", size = 6649461, upload-time = "2026-03-09T07:58:15.912Z" }, - { url = "https://files.pythonhosted.org/packages/5c/34/812ce12bc0f00272a4b0ec0d713cd237cb390666eb6206323d1cc9cedbb2/numpy-2.4.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d1ce23cce91fcea443320a9d0ece9b9305d4368875bab09538f7a5b4131938a", size = 15725809, upload-time = "2026-03-09T07:58:17.787Z" }, - { url = "https://files.pythonhosted.org/packages/25/c0/2aed473a4823e905e765fee3dc2cbf504bd3e68ccb1150fbdabd5c39f527/numpy-2.4.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c59020932feb24ed49ffd03704fbab89f22aa9c0d4b180ff45542fe8918f5611", size = 16655242, upload-time = "2026-03-09T07:58:20.476Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c8/7e052b2fc87aa0e86de23f20e2c42bd261c624748aa8efd2c78f7bb8d8c6/numpy-2.4.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9684823a78a6cd6ad7511fc5e25b07947d1d5b5e2812c93fe99d7d4195130720", size = 17080660, upload-time = "2026-03-09T07:58:23.067Z" }, - { url = "https://files.pythonhosted.org/packages/f3/3d/0876746044db2adcb11549f214d104f2e1be00f07a67edbb4e2812094847/numpy-2.4.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0200b25c687033316fb39f0ff4e3e690e8957a2c3c8d22499891ec58c37a3eb5", size = 18380384, upload-time = "2026-03-09T07:58:25.839Z" }, - { url = "https://files.pythonhosted.org/packages/07/12/8160bea39da3335737b10308df4f484235fd297f556745f13092aa039d3b/numpy-2.4.3-cp314-cp314t-win32.whl", hash = "sha256:5e10da9e93247e554bb1d22f8edc51847ddd7dde52d85ce31024c1b4312bfba0", size = 6154547, upload-time = "2026-03-09T07:58:28.289Z" }, - { url = "https://files.pythonhosted.org/packages/42/f3/76534f61f80d74cc9cdf2e570d3d4eeb92c2280a27c39b0aaf471eda7b48/numpy-2.4.3-cp314-cp314t-win_amd64.whl", hash = "sha256:45f003dbdffb997a03da2d1d0cb41fbd24a87507fb41605c0420a3db5bd4667b", size = 12633645, upload-time = "2026-03-09T07:58:30.384Z" }, - { url = "https://files.pythonhosted.org/packages/1f/b6/7c0d4334c15983cec7f92a69e8ce9b1e6f31857e5ee3a413ac424e6bd63d/numpy-2.4.3-cp314-cp314t-win_arm64.whl", hash = "sha256:4d382735cecd7bcf090172489a525cd7d4087bc331f7df9f60ddc9a296cf208e", size = 10565454, upload-time = "2026-03-09T07:58:33.031Z" }, - { url = "https://files.pythonhosted.org/packages/64/e4/4dab9fb43c83719c29241c535d9e07be73bea4bc0c6686c5816d8e1b6689/numpy-2.4.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c6b124bfcafb9e8d3ed09130dbee44848c20b3e758b6bbf006e641778927c028", size = 16834892, upload-time = "2026-03-09T07:58:35.334Z" }, - { url = "https://files.pythonhosted.org/packages/c9/29/f8b6d4af90fed3dfda84ebc0df06c9833d38880c79ce954e5b661758aa31/numpy-2.4.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:76dbb9d4e43c16cf9aa711fcd8de1e2eeb27539dcefb60a1d5e9f12fae1d1ed8", size = 14893070, upload-time = "2026-03-09T07:58:37.7Z" }, - { url = "https://files.pythonhosted.org/packages/9a/04/a19b3c91dbec0a49269407f15d5753673a09832daed40c45e8150e6fa558/numpy-2.4.3-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:29363fbfa6f8ee855d7569c96ce524845e3d726d6c19b29eceec7dd555dab152", size = 5399609, upload-time = "2026-03-09T07:58:39.853Z" }, - { url = "https://files.pythonhosted.org/packages/79/34/4d73603f5420eab89ea8a67097b31364bf7c30f811d4dd84b1659c7476d9/numpy-2.4.3-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:bc71942c789ef415a37f0d4eab90341425a00d538cd0642445d30b41023d3395", size = 6714355, upload-time = "2026-03-09T07:58:42.365Z" }, - { url = "https://files.pythonhosted.org/packages/58/ad/1100d7229bb248394939a12a8074d485b655e8ed44207d328fdd7fcebc7b/numpy-2.4.3-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e58765ad74dcebd3ef0208a5078fba32dc8ec3578fe84a604432950cd043d79", size = 15800434, upload-time = "2026-03-09T07:58:44.837Z" }, - { url = "https://files.pythonhosted.org/packages/0c/fd/16d710c085d28ba4feaf29ac60c936c9d662e390344f94a6beaa2ac9899b/numpy-2.4.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e236dbda4e1d319d681afcbb136c0c4a8e0f1a5c58ceec2adebb547357fe857", size = 16729409, upload-time = "2026-03-09T07:58:47.972Z" }, - { url = "https://files.pythonhosted.org/packages/57/a7/b35835e278c18b85206834b3aa3abe68e77a98769c59233d1f6300284781/numpy-2.4.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4b42639cdde6d24e732ff823a3fa5b701d8acad89c4142bc1d0bd6dc85200ba5", size = 12504685, upload-time = "2026-03-09T07:58:50.525Z" }, +version = "2.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0", size = 20731587, upload-time = "2026-03-29T13:22:01.298Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/06/c54062f85f673dd5c04cbe2f14c3acb8c8b95e3384869bb8cc9bff8cb9df/numpy-2.4.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f169b9a863d34f5d11b8698ead99febeaa17a13ca044961aa8e2662a6c7766a0", size = 16684353, upload-time = "2026-03-29T13:20:29.504Z" }, + { url = "https://files.pythonhosted.org/packages/4c/39/8a320264a84404c74cc7e79715de85d6130fa07a0898f67fb5cd5bd79908/numpy-2.4.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2483e4584a1cb3092da4470b38866634bafb223cbcd551ee047633fd2584599a", size = 14704914, upload-time = "2026-03-29T13:20:33.547Z" }, + { url = "https://files.pythonhosted.org/packages/91/fb/287076b2614e1d1044235f50f03748f31fa287e3dbe6abeb35cdfa351eca/numpy-2.4.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:2d19e6e2095506d1736b7d80595e0f252d76b89f5e715c35e06e937679ea7d7a", size = 5210005, upload-time = "2026-03-29T13:20:36.45Z" }, + { url = "https://files.pythonhosted.org/packages/63/eb/fcc338595309910de6ecabfcef2419a9ce24399680bfb149421fa2df1280/numpy-2.4.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:6a246d5914aa1c820c9443ddcee9c02bec3e203b0c080349533fae17727dfd1b", size = 6544974, upload-time = "2026-03-29T13:20:39.014Z" }, + { url = "https://files.pythonhosted.org/packages/44/5d/e7e9044032a716cdfaa3fba27a8e874bf1c5f1912a1ddd4ed071bf8a14a6/numpy-2.4.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:989824e9faf85f96ec9c7761cd8d29c531ad857bfa1daa930cba85baaecf1a9a", size = 15684591, upload-time = "2026-03-29T13:20:42.146Z" }, + { url = "https://files.pythonhosted.org/packages/98/7c/21252050676612625449b4807d6b695b9ce8a7c9e1c197ee6216c8a65c7c/numpy-2.4.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:27a8d92cd10f1382a67d7cf4db7ce18341b66438bdd9f691d7b0e48d104c2a9d", size = 16637700, upload-time = "2026-03-29T13:20:46.204Z" }, + { url = "https://files.pythonhosted.org/packages/b1/29/56d2bbef9465db24ef25393383d761a1af4f446a1df9b8cded4fe3a5a5d7/numpy-2.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e44319a2953c738205bf3354537979eaa3998ed673395b964c1176083dd46252", size = 17035781, upload-time = "2026-03-29T13:20:50.242Z" }, + { url = "https://files.pythonhosted.org/packages/e3/2b/a35a6d7589d21f44cea7d0a98de5ddcbb3d421b2622a5c96b1edf18707c3/numpy-2.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e892aff75639bbef0d2a2cfd55535510df26ff92f63c92cd84ef8d4ba5a5557f", size = 18362959, upload-time = "2026-03-29T13:20:54.019Z" }, + { url = "https://files.pythonhosted.org/packages/64/c9/d52ec581f2390e0f5f85cbfd80fb83d965fc15e9f0e1aec2195faa142cde/numpy-2.4.4-cp314-cp314-win32.whl", hash = "sha256:1378871da56ca8943c2ba674530924bb8ca40cd228358a3b5f302ad60cf875fc", size = 6008768, upload-time = "2026-03-29T13:20:56.912Z" }, + { url = "https://files.pythonhosted.org/packages/fa/22/4cc31a62a6c7b74a8730e31a4274c5dc80e005751e277a2ce38e675e4923/numpy-2.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:715d1c092715954784bc79e1174fc2a90093dc4dc84ea15eb14dad8abdcdeb74", size = 12449181, upload-time = "2026-03-29T13:20:59.548Z" }, + { url = "https://files.pythonhosted.org/packages/70/2e/14cda6f4d8e396c612d1bf97f22958e92148801d7e4f110cabebdc0eef4b/numpy-2.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:2c194dd721e54ecad9ad387c1d35e63dce5c4450c6dc7dd5611283dda239aabb", size = 10496035, upload-time = "2026-03-29T13:21:02.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e8/8fed8c8d848d7ecea092dc3469643f9d10bc3a134a815a3b033da1d2039b/numpy-2.4.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2aa0613a5177c264ff5921051a5719d20095ea586ca88cc802c5c218d1c67d3e", size = 14824958, upload-time = "2026-03-29T13:21:05.671Z" }, + { url = "https://files.pythonhosted.org/packages/05/1a/d8007a5138c179c2bf33ef44503e83d70434d2642877ee8fbb230e7c0548/numpy-2.4.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:42c16925aa5a02362f986765f9ebabf20de75cdefdca827d14315c568dcab113", size = 5330020, upload-time = "2026-03-29T13:21:08.635Z" }, + { url = "https://files.pythonhosted.org/packages/99/64/ffb99ac6ae93faf117bcbd5c7ba48a7f45364a33e8e458545d3633615dda/numpy-2.4.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:874f200b2a981c647340f841730fc3a2b54c9d940566a3c4149099591e2c4c3d", size = 6650758, upload-time = "2026-03-29T13:21:10.949Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6e/795cc078b78a384052e73b2f6281ff7a700e9bf53bcce2ee579d4f6dd879/numpy-2.4.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9b39d38a9bd2ae1becd7eac1303d031c5c110ad31f2b319c6e7d98b135c934d", size = 15729948, upload-time = "2026-03-29T13:21:14.047Z" }, + { url = "https://files.pythonhosted.org/packages/5f/86/2acbda8cc2af5f3d7bfc791192863b9e3e19674da7b5e533fded124d1299/numpy-2.4.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b268594bccac7d7cf5844c7732e3f20c50921d94e36d7ec9b79e9857694b1b2f", size = 16679325, upload-time = "2026-03-29T13:21:17.561Z" }, + { url = "https://files.pythonhosted.org/packages/bc/59/cafd83018f4aa55e0ac6fa92aa066c0a1877b77a615ceff1711c260ffae8/numpy-2.4.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ac6b31e35612a26483e20750126d30d0941f949426974cace8e6b5c58a3657b0", size = 17084883, upload-time = "2026-03-29T13:21:21.106Z" }, + { url = "https://files.pythonhosted.org/packages/f0/85/a42548db84e65ece46ab2caea3d3f78b416a47af387fcbb47ec28e660dc2/numpy-2.4.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8e3ed142f2728df44263aaf5fb1f5b0b99f4070c553a0d7f033be65338329150", size = 18403474, upload-time = "2026-03-29T13:21:24.828Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ad/483d9e262f4b831000062e5d8a45e342166ec8aaa1195264982bca267e62/numpy-2.4.4-cp314-cp314t-win32.whl", hash = "sha256:dddbbd259598d7240b18c9d87c56a9d2fb3b02fe266f49a7c101532e78c1d871", size = 6155500, upload-time = "2026-03-29T13:21:28.205Z" }, + { url = "https://files.pythonhosted.org/packages/c7/03/2fc4e14c7bd4ff2964b74ba90ecb8552540b6315f201df70f137faa5c589/numpy-2.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a7164afb23be6e37ad90b2f10426149fd75aee07ca55653d2aa41e66c4ef697e", size = 12637755, upload-time = "2026-03-29T13:21:31.107Z" }, + { url = "https://files.pythonhosted.org/packages/58/78/548fb8e07b1a341746bfbecb32f2c268470f45fa028aacdbd10d9bc73aab/numpy-2.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:ba203255017337d39f89bdd58417f03c4426f12beed0440cfd933cb15f8669c7", size = 10566643, upload-time = "2026-03-29T13:21:34.339Z" }, ] [[package]] @@ -1735,149 +875,31 @@ wheels = [ [[package]] name = "pandas" -version = "2.3.3" +version = "3.0.2" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "python-dateutil", marker = "python_full_version < '3.11'" }, - { name = "pytz", marker = "python_full_version < '3.11'" }, - { name = "tzdata", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763, upload-time = "2025-09-29T23:16:53.287Z" }, - { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217, upload-time = "2025-09-29T23:17:04.522Z" }, - { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791, upload-time = "2025-09-29T23:17:18.444Z" }, - { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373, upload-time = "2025-09-29T23:17:35.846Z" }, - { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444, upload-time = "2025-09-29T23:17:49.341Z" }, - { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459, upload-time = "2025-09-29T23:18:03.722Z" }, - { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086, upload-time = "2025-09-29T23:18:18.505Z" }, - { url = "https://files.pythonhosted.org/packages/c1/fa/7ac648108144a095b4fb6aa3de1954689f7af60a14cf25583f4960ecb878/pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523", size = 11578790, upload-time = "2025-09-29T23:18:30.065Z" }, - { url = "https://files.pythonhosted.org/packages/9b/35/74442388c6cf008882d4d4bdfc4109be87e9b8b7ccd097ad1e7f006e2e95/pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45", size = 10833831, upload-time = "2025-09-29T23:38:56.071Z" }, - { url = "https://files.pythonhosted.org/packages/fe/e4/de154cbfeee13383ad58d23017da99390b91d73f8c11856f2095e813201b/pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66", size = 12199267, upload-time = "2025-09-29T23:18:41.627Z" }, - { url = "https://files.pythonhosted.org/packages/bf/c9/63f8d545568d9ab91476b1818b4741f521646cbdd151c6efebf40d6de6f7/pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b", size = 12789281, upload-time = "2025-09-29T23:18:56.834Z" }, - { url = "https://files.pythonhosted.org/packages/f2/00/a5ac8c7a0e67fd1a6059e40aa08fa1c52cc00709077d2300e210c3ce0322/pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791", size = 13240453, upload-time = "2025-09-29T23:19:09.247Z" }, - { url = "https://files.pythonhosted.org/packages/27/4d/5c23a5bc7bd209231618dd9e606ce076272c9bc4f12023a70e03a86b4067/pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151", size = 13890361, upload-time = "2025-09-29T23:19:25.342Z" }, - { url = "https://files.pythonhosted.org/packages/8e/59/712db1d7040520de7a4965df15b774348980e6df45c129b8c64d0dbe74ef/pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c", size = 11348702, upload-time = "2025-09-29T23:19:38.296Z" }, - { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" }, - { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" }, - { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" }, - { url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" }, - { url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" }, - { url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" }, - { url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671, upload-time = "2025-09-29T23:21:05.024Z" }, - { url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807, upload-time = "2025-09-29T23:21:15.979Z" }, - { url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872, upload-time = "2025-09-29T23:21:27.165Z" }, - { url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371, upload-time = "2025-09-29T23:21:40.532Z" }, - { url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333, upload-time = "2025-09-29T23:21:55.77Z" }, - { url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120, upload-time = "2025-09-29T23:22:10.109Z" }, - { url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991, upload-time = "2025-09-29T23:25:04.889Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227, upload-time = "2025-09-29T23:22:24.343Z" }, - { url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056, upload-time = "2025-09-29T23:22:37.762Z" }, - { url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189, upload-time = "2025-09-29T23:22:51.688Z" }, - { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" }, - { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" }, - { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" }, - { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" }, - { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" }, - { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" }, - { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" }, - { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" }, - { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" }, - { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" }, - { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" }, - { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" }, - { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" }, - { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" }, - { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" }, -] - -[[package]] -name = "pandas" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, ] -dependencies = [ - { name = "numpy", version = "2.4.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "python-dateutil", marker = "python_full_version >= '3.11'" }, - { name = "tzdata", marker = "(python_full_version >= '3.11' and sys_platform == 'emscripten') or (python_full_version >= '3.11' and sys_platform == 'win32')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2e/0c/b28ed414f080ee0ad153f848586d61d1878f91689950f037f976ce15f6c8/pandas-3.0.1.tar.gz", hash = "sha256:4186a699674af418f655dbd420ed87f50d56b4cd6603784279d9eef6627823c8", size = 4641901, upload-time = "2026-02-17T22:20:16.434Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/07/c7087e003ceee9b9a82539b40414ec557aa795b584a1a346e89180853d79/pandas-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:de09668c1bf3b925c07e5762291602f0d789eca1b3a781f99c1c78f6cac0e7ea", size = 10323380, upload-time = "2026-02-17T22:18:16.133Z" }, - { url = "https://files.pythonhosted.org/packages/c1/27/90683c7122febeefe84a56f2cde86a9f05f68d53885cebcc473298dfc33e/pandas-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:24ba315ba3d6e5806063ac6eb717504e499ce30bd8c236d8693a5fd3f084c796", size = 9923455, upload-time = "2026-02-17T22:18:19.13Z" }, - { url = "https://files.pythonhosted.org/packages/0e/f1/ed17d927f9950643bc7631aa4c99ff0cc83a37864470bc419345b656a41f/pandas-3.0.1-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:406ce835c55bac912f2a0dcfaf27c06d73c6b04a5dde45f1fd3169ce31337389", size = 10753464, upload-time = "2026-02-17T22:18:21.134Z" }, - { url = "https://files.pythonhosted.org/packages/2e/7c/870c7e7daec2a6c7ff2ac9e33b23317230d4e4e954b35112759ea4a924a7/pandas-3.0.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:830994d7e1f31dd7e790045235605ab61cff6c94defc774547e8b7fdfbff3dc7", size = 11255234, upload-time = "2026-02-17T22:18:24.175Z" }, - { url = "https://files.pythonhosted.org/packages/5c/39/3653fe59af68606282b989c23d1a543ceba6e8099cbcc5f1d506a7bae2aa/pandas-3.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a64ce8b0f2de1d2efd2ae40b0abe7f8ae6b29fbfb3812098ed5a6f8e235ad9bf", size = 11767299, upload-time = "2026-02-17T22:18:26.824Z" }, - { url = "https://files.pythonhosted.org/packages/9b/31/1daf3c0c94a849c7a8dab8a69697b36d313b229918002ba3e409265c7888/pandas-3.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9832c2c69da24b602c32e0c7b1b508a03949c18ba08d4d9f1c1033426685b447", size = 12333292, upload-time = "2026-02-17T22:18:28.996Z" }, - { url = "https://files.pythonhosted.org/packages/1f/67/af63f83cd6ca603a00fe8530c10a60f0879265b8be00b5930e8e78c5b30b/pandas-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:84f0904a69e7365f79a0c77d3cdfccbfb05bf87847e3a51a41e1426b0edb9c79", size = 9892176, upload-time = "2026-02-17T22:18:31.79Z" }, - { url = "https://files.pythonhosted.org/packages/79/ab/9c776b14ac4b7b4140788eca18468ea39894bc7340a408f1d1e379856a6b/pandas-3.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:4a68773d5a778afb31d12e34f7dd4612ab90de8c6fb1d8ffe5d4a03b955082a1", size = 9151328, upload-time = "2026-02-17T22:18:35.721Z" }, - { url = "https://files.pythonhosted.org/packages/37/51/b467209c08dae2c624873d7491ea47d2b47336e5403309d433ea79c38571/pandas-3.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:476f84f8c20c9f5bc47252b66b4bb25e1a9fc2fa98cead96744d8116cb85771d", size = 10344357, upload-time = "2026-02-17T22:18:38.262Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f1/e2567ffc8951ab371db2e40b2fe068e36b81d8cf3260f06ae508700e5504/pandas-3.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0ab749dfba921edf641d4036c4c21c0b3ea70fea478165cb98a998fb2a261955", size = 9884543, upload-time = "2026-02-17T22:18:41.476Z" }, - { url = "https://files.pythonhosted.org/packages/d7/39/327802e0b6d693182403c144edacbc27eb82907b57062f23ef5a4c4a5ea7/pandas-3.0.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8e36891080b87823aff3640c78649b91b8ff6eea3c0d70aeabd72ea43ab069b", size = 10396030, upload-time = "2026-02-17T22:18:43.822Z" }, - { url = "https://files.pythonhosted.org/packages/3d/fe/89d77e424365280b79d99b3e1e7d606f5165af2f2ecfaf0c6d24c799d607/pandas-3.0.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:532527a701281b9dd371e2f582ed9094f4c12dd9ffb82c0c54ee28d8ac9520c4", size = 10876435, upload-time = "2026-02-17T22:18:45.954Z" }, - { url = "https://files.pythonhosted.org/packages/b5/a6/2a75320849dd154a793f69c951db759aedb8d1dd3939eeacda9bdcfa1629/pandas-3.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:356e5c055ed9b0da1580d465657bc7d00635af4fd47f30afb23025352ba764d1", size = 11405133, upload-time = "2026-02-17T22:18:48.533Z" }, - { url = "https://files.pythonhosted.org/packages/58/53/1d68fafb2e02d7881df66aa53be4cd748d25cbe311f3b3c85c93ea5d30ca/pandas-3.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9d810036895f9ad6345b8f2a338dd6998a74e8483847403582cab67745bff821", size = 11932065, upload-time = "2026-02-17T22:18:50.837Z" }, - { url = "https://files.pythonhosted.org/packages/75/08/67cc404b3a966b6df27b38370ddd96b3b023030b572283d035181854aac5/pandas-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:536232a5fe26dd989bd633e7a0c450705fdc86a207fec7254a55e9a22950fe43", size = 9741627, upload-time = "2026-02-17T22:18:53.905Z" }, - { url = "https://files.pythonhosted.org/packages/86/4f/caf9952948fb00d23795f09b893d11f1cacb384e666854d87249530f7cbe/pandas-3.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f463ebfd8de7f326d38037c7363c6dacb857c5881ab8961fb387804d6daf2f7", size = 9052483, upload-time = "2026-02-17T22:18:57.31Z" }, - { url = "https://files.pythonhosted.org/packages/0b/48/aad6ec4f8d007534c091e9a7172b3ec1b1ee6d99a9cbb936b5eab6c6cf58/pandas-3.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5272627187b5d9c20e55d27caf5f2cd23e286aba25cadf73c8590e432e2b7262", size = 10317509, upload-time = "2026-02-17T22:18:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/a8/14/5990826f779f79148ae9d3a2c39593dc04d61d5d90541e71b5749f35af95/pandas-3.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:661e0f665932af88c7877f31da0dc743fe9c8f2524bdffe23d24fdcb67ef9d56", size = 9860561, upload-time = "2026-02-17T22:19:02.265Z" }, - { url = "https://files.pythonhosted.org/packages/fa/80/f01ff54664b6d70fed71475543d108a9b7c888e923ad210795bef04ffb7d/pandas-3.0.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75e6e292ff898679e47a2199172593d9f6107fd2dd3617c22c2946e97d5df46e", size = 10365506, upload-time = "2026-02-17T22:19:05.017Z" }, - { url = "https://files.pythonhosted.org/packages/f2/85/ab6d04733a7d6ff32bfc8382bf1b07078228f5d6ebec5266b91bfc5c4ff7/pandas-3.0.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1ff8cf1d2896e34343197685f432450ec99a85ba8d90cce2030c5eee2ef98791", size = 10873196, upload-time = "2026-02-17T22:19:07.204Z" }, - { url = "https://files.pythonhosted.org/packages/48/a9/9301c83d0b47c23ac5deab91c6b39fd98d5b5db4d93b25df8d381451828f/pandas-3.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eca8b4510f6763f3d37359c2105df03a7a221a508f30e396a51d0713d462e68a", size = 11370859, upload-time = "2026-02-17T22:19:09.436Z" }, - { url = "https://files.pythonhosted.org/packages/59/fe/0c1fc5bd2d29c7db2ab372330063ad555fb83e08422829c785f5ec2176ca/pandas-3.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:06aff2ad6f0b94a17822cf8b83bbb563b090ed82ff4fe7712db2ce57cd50d9b8", size = 11924584, upload-time = "2026-02-17T22:19:11.562Z" }, - { url = "https://files.pythonhosted.org/packages/d6/7d/216a1588b65a7aa5f4535570418a599d943c85afb1d95b0876fc00aa1468/pandas-3.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9fea306c783e28884c29057a1d9baa11a349bbf99538ec1da44c8476563d1b25", size = 9742769, upload-time = "2026-02-17T22:19:13.926Z" }, - { url = "https://files.pythonhosted.org/packages/c4/cb/810a22a6af9a4e97c8ab1c946b47f3489c5bca5adc483ce0ffc84c9cc768/pandas-3.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:a8d37a43c52917427e897cb2e429f67a449327394396a81034a4449b99afda59", size = 9043855, upload-time = "2026-02-17T22:19:16.09Z" }, - { url = "https://files.pythonhosted.org/packages/92/fa/423c89086cca1f039cf1253c3ff5b90f157b5b3757314aa635f6bf3e30aa/pandas-3.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d54855f04f8246ed7b6fc96b05d4871591143c46c0b6f4af874764ed0d2d6f06", size = 10752673, upload-time = "2026-02-17T22:19:18.304Z" }, - { url = "https://files.pythonhosted.org/packages/22/23/b5a08ec1f40020397f0faba72f1e2c11f7596a6169c7b3e800abff0e433f/pandas-3.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e1b677accee34a09e0dc2ce5624e4a58a1870ffe56fc021e9caf7f23cd7668f", size = 10404967, upload-time = "2026-02-17T22:19:20.726Z" }, - { url = "https://files.pythonhosted.org/packages/5c/81/94841f1bb4afdc2b52a99daa895ac2c61600bb72e26525ecc9543d453ebc/pandas-3.0.1-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a9cabbdcd03f1b6cd254d6dda8ae09b0252524be1592594c00b7895916cb1324", size = 10320575, upload-time = "2026-02-17T22:19:24.919Z" }, - { url = "https://files.pythonhosted.org/packages/0a/8b/2ae37d66a5342a83adadfd0cb0b4bf9c3c7925424dd5f40d15d6cfaa35ee/pandas-3.0.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ae2ab1f166668b41e770650101e7090824fd34d17915dd9cd479f5c5e0065e9", size = 10710921, upload-time = "2026-02-17T22:19:27.181Z" }, - { url = "https://files.pythonhosted.org/packages/a2/61/772b2e2757855e232b7ccf7cb8079a5711becb3a97f291c953def15a833f/pandas-3.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6bf0603c2e30e2cafac32807b06435f28741135cb8697eae8b28c7d492fc7d76", size = 11334191, upload-time = "2026-02-17T22:19:29.411Z" }, - { url = "https://files.pythonhosted.org/packages/1b/08/b16c6df3ef555d8495d1d265a7963b65be166785d28f06a350913a4fac78/pandas-3.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c426422973973cae1f4a23e51d4ae85974f44871b24844e4f7de752dd877098", size = 11782256, upload-time = "2026-02-17T22:19:32.34Z" }, - { url = "https://files.pythonhosted.org/packages/55/80/178af0594890dee17e239fca96d3d8670ba0f5ff59b7d0439850924a9c09/pandas-3.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b03f91ae8c10a85c1613102c7bef5229b5379f343030a3ccefeca8a33414cf35", size = 10485047, upload-time = "2026-02-17T22:19:34.605Z" }, - { url = "https://files.pythonhosted.org/packages/bb/8b/4bb774a998b97e6c2fd62a9e6cfdaae133b636fd1c468f92afb4ae9a447a/pandas-3.0.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:99d0f92ed92d3083d140bf6b97774f9f13863924cf3f52a70711f4e7588f9d0a", size = 10322465, upload-time = "2026-02-17T22:19:36.803Z" }, - { url = "https://files.pythonhosted.org/packages/72/3a/5b39b51c64159f470f1ca3b1c2a87da290657ca022f7cd11442606f607d1/pandas-3.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3b66857e983208654294bb6477b8a63dee26b37bdd0eb34d010556e91261784f", size = 9910632, upload-time = "2026-02-17T22:19:39.001Z" }, - { url = "https://files.pythonhosted.org/packages/4e/f7/b449ffb3f68c11da12fc06fbf6d2fa3a41c41e17d0284d23a79e1c13a7e4/pandas-3.0.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56cf59638bf24dc9bdf2154c81e248b3289f9a09a6d04e63608c159022352749", size = 10440535, upload-time = "2026-02-17T22:19:41.157Z" }, - { url = "https://files.pythonhosted.org/packages/55/77/6ea82043db22cb0f2bbfe7198da3544000ddaadb12d26be36e19b03a2dc5/pandas-3.0.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1a9f55e0f46951874b863d1f3906dcb57df2d9be5c5847ba4dfb55b2c815249", size = 10893940, upload-time = "2026-02-17T22:19:43.493Z" }, - { url = "https://files.pythonhosted.org/packages/03/30/f1b502a72468c89412c1b882a08f6eed8a4ee9dc033f35f65d0663df6081/pandas-3.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1849f0bba9c8a2fb0f691d492b834cc8dadf617e29015c66e989448d58d011ee", size = 11442711, upload-time = "2026-02-17T22:19:46.074Z" }, - { url = "https://files.pythonhosted.org/packages/0d/f0/ebb6ddd8fc049e98cabac5c2924d14d1dda26a20adb70d41ea2e428d3ec4/pandas-3.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3d288439e11b5325b02ae6e9cc83e6805a62c40c5a6220bea9beb899c073b1c", size = 11963918, upload-time = "2026-02-17T22:19:48.838Z" }, - { url = "https://files.pythonhosted.org/packages/09/f8/8ce132104074f977f907442790eaae24e27bce3b3b454e82faa3237ff098/pandas-3.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:93325b0fe372d192965f4cca88d97667f49557398bbf94abdda3bf1b591dbe66", size = 9862099, upload-time = "2026-02-17T22:19:51.081Z" }, - { url = "https://files.pythonhosted.org/packages/e6/b7/6af9aac41ef2456b768ef0ae60acf8abcebb450a52043d030a65b4b7c9bd/pandas-3.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:97ca08674e3287c7148f4858b01136f8bdfe7202ad25ad04fec602dd1d29d132", size = 9185333, upload-time = "2026-02-17T22:19:53.266Z" }, - { url = "https://files.pythonhosted.org/packages/66/fc/848bb6710bc6061cb0c5badd65b92ff75c81302e0e31e496d00029fe4953/pandas-3.0.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:58eeb1b2e0fb322befcf2bbc9ba0af41e616abadb3d3414a6bc7167f6cbfce32", size = 10772664, upload-time = "2026-02-17T22:19:55.806Z" }, - { url = "https://files.pythonhosted.org/packages/69/5c/866a9bbd0f79263b4b0db6ec1a341be13a1473323f05c122388e0f15b21d/pandas-3.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cd9af1276b5ca9e298bd79a26bda32fa9cc87ed095b2a9a60978d2ca058eaf87", size = 10421286, upload-time = "2026-02-17T22:19:58.091Z" }, - { url = "https://files.pythonhosted.org/packages/51/a4/2058fb84fb1cfbfb2d4a6d485e1940bb4ad5716e539d779852494479c580/pandas-3.0.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f87a04984d6b63788327cd9f79dda62b7f9043909d2440ceccf709249ca988", size = 10342050, upload-time = "2026-02-17T22:20:01.376Z" }, - { url = "https://files.pythonhosted.org/packages/22/1b/674e89996cc4be74db3c4eb09240c4bb549865c9c3f5d9b086ff8fcfbf00/pandas-3.0.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85fe4c4df62e1e20f9db6ebfb88c844b092c22cd5324bdcf94bfa2fc1b391221", size = 10740055, upload-time = "2026-02-17T22:20:04.328Z" }, - { url = "https://files.pythonhosted.org/packages/d0/f8/e954b750764298c22fa4614376531fe63c521ef517e7059a51f062b87dca/pandas-3.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:331ca75a2f8672c365ae25c0b29e46f5ac0c6551fdace8eec4cd65e4fac271ff", size = 11357632, upload-time = "2026-02-17T22:20:06.647Z" }, - { url = "https://files.pythonhosted.org/packages/6d/02/c6e04b694ffd68568297abd03588b6d30295265176a5c01b7459d3bc35a3/pandas-3.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:15860b1fdb1973fffade772fdb931ccf9b2f400a3f5665aef94a00445d7d8dd5", size = 11810974, upload-time = "2026-02-17T22:20:08.946Z" }, - { url = "https://files.pythonhosted.org/packages/89/41/d7dfb63d2407f12055215070c42fc6ac41b66e90a2946cdc5e759058398b/pandas-3.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:44f1364411d5670efa692b146c748f4ed013df91ee91e9bec5677fb1fd58b937", size = 10884622, upload-time = "2026-02-17T22:20:11.711Z" }, - { url = "https://files.pythonhosted.org/packages/68/b0/34937815889fa982613775e4b97fddd13250f11012d769949c5465af2150/pandas-3.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:108dd1790337a494aa80e38def654ca3f0968cf4f362c85f44c15e471667102d", size = 9452085, upload-time = "2026-02-17T22:20:14.331Z" }, -] - -[[package]] -name = "pathspec" -version = "1.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/da/99/b342345300f13440fe9fe385c3c481e2d9a595ee3bab4d3219247ac94e9a/pandas-3.0.2.tar.gz", hash = "sha256:f4753e73e34c8d83221ba58f232433fca2748be8b18dbca02d242ed153945043", size = 4645855, upload-time = "2026-03-31T06:48:30.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/40/c6ea527147c73b24fc15c891c3fcffe9c019793119c5742b8784a062c7db/pandas-3.0.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:db0dbfd2a6cdf3770aa60464d50333d8f3d9165b2f2671bcc299b72de5a6677b", size = 10326084, upload-time = "2026-03-31T06:47:43.834Z" }, + { url = "https://files.pythonhosted.org/packages/95/25/bdb9326c3b5455f8d4d3549fce7abcf967259de146fe2cf7a82368141948/pandas-3.0.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0555c5882688a39317179ab4a0ed41d3ebc8812ab14c69364bbee8fb7a3f6288", size = 9914146, upload-time = "2026-03-31T06:47:46.67Z" }, + { url = "https://files.pythonhosted.org/packages/8d/77/3a227ff3337aa376c60d288e1d61c5d097131d0ac71f954d90a8f369e422/pandas-3.0.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:01f31a546acd5574ef77fe199bc90b55527c225c20ccda6601cf6b0fd5ed597c", size = 10444081, upload-time = "2026-03-31T06:47:49.681Z" }, + { url = "https://files.pythonhosted.org/packages/15/88/3cdd54fa279341afa10acf8d2b503556b1375245dccc9315659f795dd2e9/pandas-3.0.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:deeca1b5a931fdf0c2212c8a659ade6d3b1edc21f0914ce71ef24456ca7a6535", size = 10897535, upload-time = "2026-03-31T06:47:53.033Z" }, + { url = "https://files.pythonhosted.org/packages/06/9d/98cc7a7624f7932e40f434299260e2917b090a579d75937cb8a57b9d2de3/pandas-3.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0f48afd9bb13300ffb5a3316973324c787054ba6665cda0da3fbd67f451995db", size = 11446992, upload-time = "2026-03-31T06:47:56.193Z" }, + { url = "https://files.pythonhosted.org/packages/9a/cd/19ff605cc3760e80602e6826ddef2824d8e7050ed80f2e11c4b079741dc3/pandas-3.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6c4d8458b97a35717b62469a4ea0e85abd5ed8687277f5ccfc67f8a5126f8c53", size = 11968257, upload-time = "2026-03-31T06:47:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/db/60/aba6a38de456e7341285102bede27514795c1eaa353bc0e7638b6b785356/pandas-3.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:b35d14bb5d8285d9494fe93815a9e9307c0876e10f1e8e89ac5b88f728ec8dcf", size = 9865893, upload-time = "2026-03-31T06:48:02.038Z" }, + { url = "https://files.pythonhosted.org/packages/08/71/e5ec979dd2e8a093dacb8864598c0ff59a0cee0bbcdc0bfec16a51684d4f/pandas-3.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:63d141b56ef686f7f0d714cfb8de4e320475b86bf4b620aa0b7da89af8cbdbbb", size = 9188644, upload-time = "2026-03-31T06:48:05.045Z" }, + { url = "https://files.pythonhosted.org/packages/f1/6c/7b45d85db19cae1eb524f2418ceaa9d85965dcf7b764ed151386b7c540f0/pandas-3.0.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:140f0cffb1fa2524e874dde5b477d9defe10780d8e9e220d259b2c0874c89d9d", size = 10776246, upload-time = "2026-03-31T06:48:07.789Z" }, + { url = "https://files.pythonhosted.org/packages/a8/3e/7b00648b086c106e81766f25322b48aa8dfa95b55e621dbdf2fdd413a117/pandas-3.0.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ae37e833ff4fed0ba352f6bdd8b73ba3ab3256a85e54edfd1ab51ae40cca0af8", size = 10424801, upload-time = "2026-03-31T06:48:10.897Z" }, + { url = "https://files.pythonhosted.org/packages/da/6e/558dd09a71b53b4008e7fc8a98ec6d447e9bfb63cdaeea10e5eb9b2dabe8/pandas-3.0.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d888a5c678a419a5bb41a2a93818e8ed9fd3172246555c0b37b7cc27027effd", size = 10345643, upload-time = "2026-03-31T06:48:13.7Z" }, + { url = "https://files.pythonhosted.org/packages/be/e3/921c93b4d9a280409451dc8d07b062b503bbec0531d2627e73a756e99a82/pandas-3.0.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b444dc64c079e84df91baa8bf613d58405645461cabca929d9178f2cd392398d", size = 10743641, upload-time = "2026-03-31T06:48:16.659Z" }, + { url = "https://files.pythonhosted.org/packages/56/ca/fd17286f24fa3b4d067965d8d5d7e14fe557dd4f979a0b068ac0deaf8228/pandas-3.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4544c7a54920de8eeacaa1466a6b7268ecfbc9bc64ab4dbb89c6bbe94d5e0660", size = 11361993, upload-time = "2026-03-31T06:48:19.475Z" }, + { url = "https://files.pythonhosted.org/packages/e4/a5/2f6ed612056819de445a433ca1f2821ac3dab7f150d569a59e9cc105de1d/pandas-3.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:734be7551687c00fbd760dc0522ed974f82ad230d4a10f54bf51b80d44a08702", size = 11815274, upload-time = "2026-03-31T06:48:22.695Z" }, + { url = "https://files.pythonhosted.org/packages/00/2f/b622683e99ec3ce00b0854bac9e80868592c5b051733f2cf3a868e5fea26/pandas-3.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:57a07209bebcbcf768d2d13c9b78b852f9a15978dac41b9e6421a81ad4cdd276", size = 10888530, upload-time = "2026-03-31T06:48:25.806Z" }, + { url = "https://files.pythonhosted.org/packages/cb/2b/f8434233fab2bd66a02ec014febe4e5adced20e2693e0e90a07d118ed30e/pandas-3.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:5371b72c2d4d415d08765f32d689217a43227484e81b2305b52076e328f6f482", size = 9455341, upload-time = "2026-03-31T06:48:28.418Z" }, ] [[package]] @@ -1891,42 +913,26 @@ wheels = [ [[package]] name = "prek" -version = "0.3.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/d6/277e002e56eeab3a9d48f1ca4cc067d249d6326fc1783b770d70ad5ae2be/prek-0.3.5.tar.gz", hash = "sha256:ca40b6685a4192256bc807f32237af94bf9b8799c0d708b98735738250685642", size = 374806, upload-time = "2026-03-09T10:35:18.842Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/a9/16dd8d3a50362ebccffe58518af1f1f571c96f0695d7fcd8bbd386585f58/prek-0.3.5-py3-none-linux_armv6l.whl", hash = "sha256:44b3e12791805804f286d103682b42a84e0f98a2687faa37045e9d3375d3d73d", size = 5105604, upload-time = "2026-03-09T10:35:00.332Z" }, - { url = "https://files.pythonhosted.org/packages/e4/74/bc6036f5bf03860cda66ab040b32737e54802b71a81ec381839deb25df9e/prek-0.3.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e3cb451cc51ac068974557491beb4c7d2d41dfde29ed559c1694c8ce23bf53e8", size = 5506155, upload-time = "2026-03-09T10:35:17.64Z" }, - { url = "https://files.pythonhosted.org/packages/02/d9/a3745c2a10509c63b6a118ada766614dd705efefd08f275804d5c807aa4a/prek-0.3.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:ad8f5f0d8da53dc94d00b76979af312b3dacccc9dcbc6417756c5dca3633c052", size = 5100383, upload-time = "2026-03-09T10:35:13.302Z" }, - { url = "https://files.pythonhosted.org/packages/43/8e/de965fc515d39309a332789cd3778161f7bc80cde15070bedf17f9f8cb93/prek-0.3.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:4511e15d34072851ac88e4b2006868fbe13655059ad941d7a0ff9ee17138fd9f", size = 5334913, upload-time = "2026-03-09T10:35:14.813Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8c/44f07e8940256059cfd82520e3cbe0764ab06ddb4aa43148465db00b39ad/prek-0.3.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcc0b63b8337e2046f51267facaac63ba755bc14aad53991840a5eccba3e5c28", size = 5033825, upload-time = "2026-03-09T10:35:06.976Z" }, - { url = "https://files.pythonhosted.org/packages/94/85/3ff0f96881ff2360c212d310ff23c3cf5a15b223d34fcfa8cdcef203be69/prek-0.3.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5fc0d78c3896a674aeb8247a83bbda7efec85274dbdfbc978ceff8d37e4ed20", size = 5438586, upload-time = "2026-03-09T10:34:58.779Z" }, - { url = "https://files.pythonhosted.org/packages/79/a5/c6d08d31293400fcb5d427f8e7e6bacfc959988e868ad3a9d97b4d87c4b7/prek-0.3.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64cad21cb9072d985179495b77b312f6b81e7b45357d0c68dc1de66e0408eabc", size = 6359714, upload-time = "2026-03-09T10:34:57.454Z" }, - { url = "https://files.pythonhosted.org/packages/ba/18/321dcff9ece8065d42c8c1c7a53a23b45d2b4330aa70993be75dc5f2822f/prek-0.3.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45ee84199bb48e013bdfde0c84352c17a44cc42d5792681b86d94e9474aab6f8", size = 5717632, upload-time = "2026-03-09T10:35:08.634Z" }, - { url = "https://files.pythonhosted.org/packages/a3/7f/1288226aa381d0cea403157f4e6b64b356e1a745f2441c31dd9d8a1d63da/prek-0.3.5-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:f43275e5d564e18e52133129ebeb5cb071af7ce4a547766c7f025aa0955dfbb6", size = 5339040, upload-time = "2026-03-09T10:35:03.665Z" }, - { url = "https://files.pythonhosted.org/packages/22/94/cfec83df9c2b8e7ed1608087bcf9538a6a77b4c2e7365123e9e0a3162cd1/prek-0.3.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:abcee520d31522bcbad9311f21326b447694cd5edba33618c25fd023fc9865ec", size = 5162586, upload-time = "2026-03-09T10:35:11.564Z" }, - { url = "https://files.pythonhosted.org/packages/13/b7/741d62132f37a5f7cc0fad1168bd31f20dea9628f482f077f569547e0436/prek-0.3.5-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:499c56a94a155790c75a973d351a33f8065579d9094c93f6d451ada5d1e469be", size = 5002933, upload-time = "2026-03-09T10:35:16.347Z" }, - { url = "https://files.pythonhosted.org/packages/6f/83/630a5671df6550fcfa67c54955e8a8174eb9b4d97ac38fb05a362029245b/prek-0.3.5-py3-none-musllinux_1_1_i686.whl", hash = "sha256:de1065b59f194624adc9dea269d4ff6b50e98a1b5bb662374a9adaa496b3c1eb", size = 5304934, upload-time = "2026-03-09T10:35:09.975Z" }, - { url = "https://files.pythonhosted.org/packages/de/79/67a7afd0c0b6c436630b7dba6e586a42d21d5d6e5778fbd9eba7bbd3dd26/prek-0.3.5-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:a1c4869e45ee341735d07179da3a79fa2afb5959cef8b3c8a71906eb52dc6933", size = 5829914, upload-time = "2026-03-09T10:35:05.39Z" }, - { url = "https://files.pythonhosted.org/packages/37/47/e2fe13b33e7b5fdd9dd1a312f5440208bfe1be6183e54c5c99c10f27d848/prek-0.3.5-py3-none-win32.whl", hash = "sha256:70b2152ecedc58f3f4f69adc884617b0cf44259f7414c44d6268ea6f107672eb", size = 4836910, upload-time = "2026-03-09T10:35:01.884Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ab/dc2a139fd4896d11f39631479ed385e86307af7f54059ebe9414bb0d00c6/prek-0.3.5-py3-none-win_amd64.whl", hash = "sha256:01d031b684f7e1546225393af1268d9b4451a44ef6cb9be4101c85c7862e08db", size = 5234234, upload-time = "2026-03-09T10:35:20.193Z" }, - { url = "https://files.pythonhosted.org/packages/ed/38/f7256b4b7581444f658e909c3b566f51bfabe56c03e80d107a6932d62040/prek-0.3.5-py3-none-win_arm64.whl", hash = "sha256:aa774168e3d868039ff79422bdef2df8d5a016ed804a9914607dcdd3d41da053", size = 5083330, upload-time = "2026-03-09T10:34:55.469Z" }, -] - -[[package]] -name = "premailer" -version = "3.10.0" +version = "0.3.8" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cachetools" }, - { name = "cssselect" }, - { name = "cssutils" }, - { name = "lxml" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a3/6f/e49bd31941eff2987076383fa6d811eb785a28f498f5bb131e981bd71e13/premailer-3.10.0.tar.gz", hash = "sha256:d1875a8411f5dc92b53ef9f193db6c0f879dc378d618e0ad292723e388bfe4c2", size = 24342, upload-time = "2021-08-02T20:32:54.328Z" } +sdist = { url = "https://files.pythonhosted.org/packages/62/ee/03e8180e3fda9de25b6480bd15cc2bde40d573868d50648b0e527b35562f/prek-0.3.8.tar.gz", hash = "sha256:434a214256516f187a3ab15f869d950243be66b94ad47987ee4281b69643a2d9", size = 400224, upload-time = "2026-03-23T08:23:35.981Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/07/4e8d94f94c7d41ca5ddf8a9695ad87b888104e2fd41a35546c1dc9ca74ac/premailer-3.10.0-py2.py3-none-any.whl", hash = "sha256:021b8196364d7df96d04f9ade51b794d0b77bcc19e998321c515633a2273be1a", size = 19544, upload-time = "2021-08-02T20:32:52.771Z" }, + { url = "https://files.pythonhosted.org/packages/00/84/40d2ddf362d12c4cd4a25a8c89a862edf87cdfbf1422aa41aac8e315d409/prek-0.3.8-py3-none-linux_armv6l.whl", hash = "sha256:6fb646ada60658fa6dd7771b2e0fb097f005151be222f869dada3eb26d79ed33", size = 5226646, upload-time = "2026-03-23T08:23:18.306Z" }, + { url = "https://files.pythonhosted.org/packages/e1/52/7308a033fa43b7e8e188797bd2b3b017c0f0adda70fa7af575b1f43ea888/prek-0.3.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f3d7fdadb15efc19c09953c7a33cf2061a70f367d1e1957358d3ad5cc49d0616", size = 5620104, upload-time = "2026-03-23T08:23:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b1/f106ac000a91511a9cd80169868daf2f5b693480ef5232cec5517a38a512/prek-0.3.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:72728c3295e79ca443f8c1ec037d2a5b914ec73a358f69cf1bc1964511876bf8", size = 5199867, upload-time = "2026-03-23T08:23:38.066Z" }, + { url = "https://files.pythonhosted.org/packages/b3/e9/970713f4b019f69de9844e1bab37b8ddb67558e410916f4eb5869a696165/prek-0.3.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:48efc28f2f53b5b8087efca9daaed91572d62df97d5f24a1c7a087fecb5017de", size = 5441801, upload-time = "2026-03-23T08:23:32.617Z" }, + { url = "https://files.pythonhosted.org/packages/12/a4/7ef44032b181753e19452ec3b09abb3a32607cf6b0a0508f0604becaaf2b/prek-0.3.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f6ca9d63bacbc448a5c18e955c78d3ac5176c3a17c3baacdd949b1a623e08a36", size = 5155107, upload-time = "2026-03-23T08:23:31.021Z" }, + { url = "https://files.pythonhosted.org/packages/bd/77/4d9c8985dbba84149760785dfe07093ea1e29d710257dfb7c89615e2234c/prek-0.3.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1000f7029696b4fe712fb1fefd4c55b9c4de72b65509c8e50296370a06f9dc3f", size = 5566541, upload-time = "2026-03-23T08:23:45.694Z" }, + { url = "https://files.pythonhosted.org/packages/1a/1a/81e6769ac1f7f8346d09ce2ab0b47cf06466acd9ff72e87e5d1f0d98cd32/prek-0.3.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ff0bed0e2c1286522987d982168a86cbbd0d069d840506a46c9fda983515517", size = 6552991, upload-time = "2026-03-23T08:23:21.958Z" }, + { url = "https://files.pythonhosted.org/packages/6f/fa/ce2df0dd2dc75a9437a52463239d0782998943d7b04e191fb89b83016c34/prek-0.3.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fb087ac0ffda3ac65bbbae9a38326a7fd27ee007bb4a94323ce1eb539d8bbec", size = 5832972, upload-time = "2026-03-23T08:23:20.258Z" }, + { url = "https://files.pythonhosted.org/packages/18/6b/9d4269df9073216d296244595a21c253b6475dfc9076c0bd2906be7a436c/prek-0.3.8-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:2e1e5e206ff7b31bd079cce525daddc96cd6bc544d20dc128921ad92f7a4c85d", size = 5448371, upload-time = "2026-03-23T08:23:41.835Z" }, + { url = "https://files.pythonhosted.org/packages/60/1d/1e4d8a78abefa5b9d086e5a9f1638a74b5e540eec8a648d9946707701f29/prek-0.3.8-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:dcea3fe23832a4481bccb7c45f55650cb233be7c805602e788bb7dba60f2d861", size = 5270546, upload-time = "2026-03-23T08:23:24.231Z" }, + { url = "https://files.pythonhosted.org/packages/77/07/34f36551a6319ae36e272bea63a42f59d41d2d47ab0d5fb00eb7b4e88e87/prek-0.3.8-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:4d25e647e9682f6818ab5c31e7a4b842993c14782a6ffcd128d22b784e0d677f", size = 5124032, upload-time = "2026-03-23T08:23:26.368Z" }, + { url = "https://files.pythonhosted.org/packages/e3/01/6d544009bb655e709993411796af77339f439526db4f3b3509c583ad8eb9/prek-0.3.8-py3-none-musllinux_1_1_i686.whl", hash = "sha256:de528b82935e33074815acff3c7c86026754d1212136295bc88fe9c43b4231d5", size = 5432245, upload-time = "2026-03-23T08:23:47.877Z" }, + { url = "https://files.pythonhosted.org/packages/54/96/1237ee269e9bfa283ffadbcba1f401f48a47aed2b2563eb1002740d6079d/prek-0.3.8-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:6d660f1c25a126e6d9f682fe61449441226514f412a4469f5d71f8f8cad56db2", size = 5950550, upload-time = "2026-03-23T08:23:43.8Z" }, + { url = "https://files.pythonhosted.org/packages/ca/6b/a574411459049bc691047c9912f375deda10c44a707b6ce98df2b658f0b3/prek-0.3.8-py3-none-win32.whl", hash = "sha256:b0c291c577615d9f8450421dff0b32bfd77a6b0d223ee4115a1f820cb636fdf1", size = 4949501, upload-time = "2026-03-23T08:23:16.338Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b4/46b59fe49f635acd9f6530778ce577f9d8b49452835726a5311ffc902c67/prek-0.3.8-py3-none-win_amd64.whl", hash = "sha256:bc147fdbdd4ec33fc7a987b893ecb69b1413ac100d95c9889a70f3fd58c73d06", size = 5346551, upload-time = "2026-03-23T08:23:34.501Z" }, + { url = "https://files.pythonhosted.org/packages/53/05/9cca1708bb8c65264124eb4b04251e0f65ce5bfc707080bb6b492d5a0df7/prek-0.3.8-py3-none-win_arm64.whl", hash = "sha256:a2614647aeafa817a5802ccb9561e92eedc20dcf840639a1b00826e2c2442515", size = 5190872, upload-time = "2026-03-23T08:23:29.463Z" }, ] [[package]] @@ -1934,7 +940,6 @@ name = "psycopg" version = "3.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, { name = "tzdata", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d3/b6/379d0a960f8f435ec78720462fd94c4863e7a31237cf81bf76d0af5883bf/psycopg-3.3.3.tar.gz", hash = "sha256:5e9a47458b3c1583326513b2556a2a9473a1001a56c9efe9e587245b43148dd9", size = 165624, upload-time = "2026-02-18T16:52:16.546Z" } @@ -1952,50 +957,6 @@ name = "psycopg-binary" version = "3.3.3" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/d8/a763308a41e2ecfb6256ba0877d340c2f2b124c8b2746401863d96fa2c7a/psycopg_binary-3.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b3385b58b2fe408a13d084c14b8dcf468cd36cbbe774408250facc128f9fa75c", size = 4609758, upload-time = "2026-02-18T16:46:33.132Z" }, - { url = "https://files.pythonhosted.org/packages/6c/a9/f8a683e85400c1208685e7c895abc049dc13aa0b6ea989e6adf0a3681fe0/psycopg_binary-3.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1bef235a50a80f6aba05147002bc354559657cb6386dbd04d8e1c97d1d7cbe84", size = 4676740, upload-time = "2026-02-18T16:46:42.904Z" }, - { url = "https://files.pythonhosted.org/packages/e3/7d/03512c4aaac8a58fc3b1221f38293aa517a1950d10ef8646c72c49addc7d/psycopg_binary-3.3.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:97c839717bf8c8df3f6d983a20949c4fb22e2a34ee172e3e427ede363feda27b", size = 5496335, upload-time = "2026-02-18T16:46:51.517Z" }, - { url = "https://files.pythonhosted.org/packages/8a/bc/23319b4b1c2c0b810d225e1b6f16efbb16150074fc0ea96bfcabdf59ee09/psycopg_binary-3.3.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:48e500cf1c0984dacf1f28ea482c3cdbb4c2288d51c336c04bc64198ab21fc51", size = 5172032, upload-time = "2026-02-18T16:47:00.878Z" }, - { url = "https://files.pythonhosted.org/packages/aa/c8/6d61dc0a56654c558a37b2d9b2094e470aa12621305cc7935fd769122e32/psycopg_binary-3.3.3-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb36a08859b9432d94ea6b26ec41a2f98f83f14868c91321d0c1e11f672eeae7", size = 6763107, upload-time = "2026-02-18T16:47:11.784Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b5/e2a3c90aa1059f5b5f593379caad7be3cc3c2ce1ddfc7730e39854e174fe/psycopg_binary-3.3.3-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0dde92cfde09293fb63b3f547919ba7d73bd2654573c03502b3263dd0218e44e", size = 5006494, upload-time = "2026-02-18T16:47:17.062Z" }, - { url = "https://files.pythonhosted.org/packages/5d/3e/bf126e0a1f864e191b7f3eeea667ee2ce13d582b036255fb8b12946d1f7a/psycopg_binary-3.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:78c9ce98caaf82ac8484d269791c1b403d7598633e0e4e2fa1097baae244e2f1", size = 4533850, upload-time = "2026-02-18T16:47:21.673Z" }, - { url = "https://files.pythonhosted.org/packages/f4/d8/bb5e8d395deb945629aa0c65d12ab90ec3bfcbdf56be89e2a84d001864c9/psycopg_binary-3.3.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d593612758d0041cb13cb0003f7f8d3fabb7ad9319e651e78afae49b1cf5860e", size = 4223316, upload-time = "2026-02-18T16:47:25.82Z" }, - { url = "https://files.pythonhosted.org/packages/c2/70/33eef61b0f0fd41ebf93b9699f44067313a45016827f67b3c8cc41f0a7ab/psycopg_binary-3.3.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:f24e8e17035200a465c178e9ea945527ad0738118694184c450f1192a452ff25", size = 3954515, upload-time = "2026-02-18T16:47:30.434Z" }, - { url = "https://files.pythonhosted.org/packages/ea/db/27c2b3b9698e713e83e11e8540daa27516f9e90390ec21a41091cb15fcaf/psycopg_binary-3.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e7b607f0e14f2a4cf7e78a05ebd13df6144acfba87cb90842e70d3f125d9f53f", size = 4260274, upload-time = "2026-02-18T16:47:36.128Z" }, - { url = "https://files.pythonhosted.org/packages/a1/3b/71e5d603059bf5474215f573a3e2d357a4e95672b26e04d41674400d4862/psycopg_binary-3.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:b27d3a23c79fa59557d2cc63a7e8bb4c7e022c018558eda36f9d7c4e6b99a6e0", size = 3557375, upload-time = "2026-02-18T16:47:42.799Z" }, - { url = "https://files.pythonhosted.org/packages/be/c0/b389119dd754483d316805260f3e73cdcad97925839107cc7a296f6132b1/psycopg_binary-3.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a89bb9ee11177b2995d87186b1d9fa892d8ea725e85eab28c6525e4cc14ee048", size = 4609740, upload-time = "2026-02-18T16:47:51.093Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e3/9976eef20f61840285174d360da4c820a311ab39d6b82fa09fbb545be825/psycopg_binary-3.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9f7d0cf072c6fbac3795b08c98ef9ea013f11db609659dcfc6b1f6cc31f9e181", size = 4676837, upload-time = "2026-02-18T16:47:55.523Z" }, - { url = "https://files.pythonhosted.org/packages/9f/f2/d28ba2f7404fd7f68d41e8a11df86313bd646258244cb12a8dd83b868a97/psycopg_binary-3.3.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:90eecd93073922f085967f3ed3a98ba8c325cbbc8c1a204e300282abd2369e13", size = 5497070, upload-time = "2026-02-18T16:47:59.929Z" }, - { url = "https://files.pythonhosted.org/packages/de/2f/6c5c54b815edeb30a281cfcea96dc93b3bb6be939aea022f00cab7aa1420/psycopg_binary-3.3.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dac7ee2f88b4d7bb12837989ca354c38d400eeb21bce3b73dac02622f0a3c8d6", size = 5172410, upload-time = "2026-02-18T16:48:05.665Z" }, - { url = "https://files.pythonhosted.org/packages/51/75/8206c7008b57de03c1ada46bd3110cc3743f3fd9ed52031c4601401d766d/psycopg_binary-3.3.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b62cf8784eb6d35beaee1056d54caf94ec6ecf2b7552395e305518ab61eb8fd2", size = 6763408, upload-time = "2026-02-18T16:48:13.541Z" }, - { url = "https://files.pythonhosted.org/packages/d4/5a/ea1641a1e6c8c8b3454b0fcb43c3045133a8b703e6e824fae134088e63bd/psycopg_binary-3.3.3-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a39f34c9b18e8f6794cca17bfbcd64572ca2482318db644268049f8c738f35a6", size = 5006255, upload-time = "2026-02-18T16:48:22.176Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fb/538df099bf55ae1637d52d7ccb6b9620b535a40f4c733897ac2b7bb9e14c/psycopg_binary-3.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:883d68d48ca9ff3cb3d10c5fdebea02c79b48eecacdddbf7cce6e7cdbdc216b8", size = 4532694, upload-time = "2026-02-18T16:48:27.338Z" }, - { url = "https://files.pythonhosted.org/packages/a1/d1/00780c0e187ea3c13dfc53bd7060654b2232cd30df562aac91a5f1c545ac/psycopg_binary-3.3.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:cab7bc3d288d37a80aa8c0820033250c95e40b1c2b5c57cf59827b19c2a8b69d", size = 4222833, upload-time = "2026-02-18T16:48:31.221Z" }, - { url = "https://files.pythonhosted.org/packages/7a/34/a07f1ff713c51d64dc9f19f2c32be80299a2055d5d109d5853662b922cb4/psycopg_binary-3.3.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:56c767007ca959ca32f796b42379fc7e1ae2ed085d29f20b05b3fc394f3715cc", size = 3952818, upload-time = "2026-02-18T16:48:35.869Z" }, - { url = "https://files.pythonhosted.org/packages/d3/67/d33f268a7759b4445f3c9b5a181039b01af8c8263c865c1be7a6444d4749/psycopg_binary-3.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:da2f331a01af232259a21573a01338530c6016dcfad74626c01330535bcd8628", size = 4258061, upload-time = "2026-02-18T16:48:41.365Z" }, - { url = "https://files.pythonhosted.org/packages/b4/3b/0d8d2c5e8e29ccc07d28c8af38445d9d9abcd238d590186cac82ee71fc84/psycopg_binary-3.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:19f93235ece6dbfc4036b5e4f6d8b13f0b8f2b3eeb8b0bd2936d406991bcdd40", size = 3558915, upload-time = "2026-02-18T16:48:46.679Z" }, - { url = "https://files.pythonhosted.org/packages/90/15/021be5c0cbc5b7c1ab46e91cc3434eb42569f79a0592e67b8d25e66d844d/psycopg_binary-3.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6698dbab5bcef8fdb570fc9d35fd9ac52041771bfcfe6fd0fc5f5c4e36f1e99d", size = 4591170, upload-time = "2026-02-18T16:48:55.594Z" }, - { url = "https://files.pythonhosted.org/packages/f1/54/a60211c346c9a2f8c6b272b5f2bbe21f6e11800ce7f61e99ba75cf8b63e1/psycopg_binary-3.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:329ff393441e75f10b673ae99ab45276887993d49e65f141da20d915c05aafd8", size = 4670009, upload-time = "2026-02-18T16:49:03.608Z" }, - { url = "https://files.pythonhosted.org/packages/c1/53/ac7c18671347c553362aadbf65f92786eef9540676ca24114cc02f5be405/psycopg_binary-3.3.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:eb072949b8ebf4082ae24289a2b0fd724da9adc8f22743409d6fd718ddb379df", size = 5469735, upload-time = "2026-02-18T16:49:10.128Z" }, - { url = "https://files.pythonhosted.org/packages/7f/c3/4f4e040902b82a344eff1c736cde2f2720f127fe939c7e7565706f96dd44/psycopg_binary-3.3.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:263a24f39f26e19ed7fc982d7859a36f17841b05bebad3eb47bb9cd2dd785351", size = 5152919, upload-time = "2026-02-18T16:49:16.335Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e7/d929679c6a5c212bcf738806c7c89f5b3d0919f2e1685a0e08d6ff877945/psycopg_binary-3.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5152d50798c2fa5bd9b68ec68eb68a1b71b95126c1d70adaa1a08cd5eefdc23d", size = 6738785, upload-time = "2026-02-18T16:49:22.687Z" }, - { url = "https://files.pythonhosted.org/packages/69/b0/09703aeb69a9443d232d7b5318d58742e8ca51ff79f90ffe6b88f1db45e7/psycopg_binary-3.3.3-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9d6a1e56dd267848edb824dbeb08cf5bac649e02ee0b03ba883ba3f4f0bd54f2", size = 4979008, upload-time = "2026-02-18T16:49:27.313Z" }, - { url = "https://files.pythonhosted.org/packages/cc/a6/e662558b793c6e13a7473b970fee327d635270e41eded3090ef14045a6a5/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73eaaf4bb04709f545606c1db2f65f4000e8a04cdbf3e00d165a23004692093e", size = 4508255, upload-time = "2026-02-18T16:49:31.575Z" }, - { url = "https://files.pythonhosted.org/packages/5f/7f/0f8b2e1d5e0093921b6f324a948a5c740c1447fbb45e97acaf50241d0f39/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:162e5675efb4704192411eaf8e00d07f7960b679cd3306e7efb120bb8d9456cc", size = 4189166, upload-time = "2026-02-18T16:49:35.801Z" }, - { url = "https://files.pythonhosted.org/packages/92/ec/ce2e91c33bc8d10b00c87e2f6b0fb570641a6a60042d6a9ae35658a3a797/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:fab6b5e37715885c69f5d091f6ff229be71e235f272ebaa35158d5a46fd548a0", size = 3924544, upload-time = "2026-02-18T16:49:41.129Z" }, - { url = "https://files.pythonhosted.org/packages/c5/2f/7718141485f73a924205af60041c392938852aa447a94c8cbd222ff389a1/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a4aab31bd6d1057f287c96c0effca3a25584eb9cc702f282ecb96ded7814e830", size = 4235297, upload-time = "2026-02-18T16:49:46.726Z" }, - { url = "https://files.pythonhosted.org/packages/57/f9/1add717e2643a003bbde31b1b220172e64fbc0cb09f06429820c9173f7fc/psycopg_binary-3.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:59aa31fe11a0e1d1bcc2ce37ed35fe2ac84cd65bb9036d049b1a1c39064d0f14", size = 3547659, upload-time = "2026-02-18T16:49:52.999Z" }, - { url = "https://files.pythonhosted.org/packages/03/0a/cac9fdf1df16a269ba0e5f0f06cac61f826c94cadb39df028cdfe19d3a33/psycopg_binary-3.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05f32239aec25c5fb15f7948cffdc2dc0dac098e48b80a140e4ba32b572a2e7d", size = 4590414, upload-time = "2026-02-18T16:50:01.441Z" }, - { url = "https://files.pythonhosted.org/packages/9c/c0/d8f8508fbf440edbc0099b1abff33003cd80c9e66eb3a1e78834e3fb4fb9/psycopg_binary-3.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c84f9d214f2d1de2fafebc17fa68ac3f6561a59e291553dfc45ad299f4898c1", size = 4669021, upload-time = "2026-02-18T16:50:08.803Z" }, - { url = "https://files.pythonhosted.org/packages/04/05/097016b77e343b4568feddf12c72171fc513acef9a4214d21b9478569068/psycopg_binary-3.3.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e77957d2ba17cada11be09a5066d93026cdb61ada7c8893101d7fe1c6e1f3925", size = 5467453, upload-time = "2026-02-18T16:50:14.985Z" }, - { url = "https://files.pythonhosted.org/packages/91/23/73244e5feb55b5ca109cede6e97f32ef45189f0fdac4c80d75c99862729d/psycopg_binary-3.3.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:42961609ac07c232a427da7c87a468d3c82fee6762c220f38e37cfdacb2b178d", size = 5151135, upload-time = "2026-02-18T16:50:24.82Z" }, - { url = "https://files.pythonhosted.org/packages/11/49/5309473b9803b207682095201d8708bbc7842ddf3f192488a69204e36455/psycopg_binary-3.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae07a3114313dd91fce686cab2f4c44af094398519af0e0f854bc707e1aeedf1", size = 6737315, upload-time = "2026-02-18T16:50:35.106Z" }, - { url = "https://files.pythonhosted.org/packages/d4/5d/03abe74ef34d460b33c4d9662bf6ec1dd38888324323c1a1752133c10377/psycopg_binary-3.3.3-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d257c58d7b36a621dcce1d01476ad8b60f12d80eb1406aee4cf796f88b2ae482", size = 4979783, upload-time = "2026-02-18T16:50:42.067Z" }, - { url = "https://files.pythonhosted.org/packages/f0/6c/3fbf8e604e15f2f3752900434046c00c90bb8764305a1b81112bff30ba24/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:07c7211f9327d522c9c47560cae00a4ecf6687f4e02d779d035dd3177b41cb12", size = 4509023, upload-time = "2026-02-18T16:50:50.116Z" }, - { url = "https://files.pythonhosted.org/packages/9c/6b/1a06b43b7c7af756c80b67eac8bfaa51d77e68635a8a8d246e4f0bb7604a/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:8e7e9eca9b363dbedeceeadd8be97149d2499081f3c52d141d7cd1f395a91f83", size = 4185874, upload-time = "2026-02-18T16:50:55.97Z" }, - { url = "https://files.pythonhosted.org/packages/2b/d3/bf49e3dcaadba510170c8d111e5e69e5ae3f981c1554c5bb71c75ce354bb/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:cb85b1d5702877c16f28d7b92ba030c1f49ebcc9b87d03d8c10bf45a2f1c7508", size = 3925668, upload-time = "2026-02-18T16:51:03.299Z" }, - { url = "https://files.pythonhosted.org/packages/f8/92/0aac830ed6a944fe334404e1687a074e4215630725753f0e3e9a9a595b62/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4d4606c84d04b80f9138d72f1e28c6c02dc5ae0c7b8f3f8aaf89c681ce1cd1b1", size = 4234973, upload-time = "2026-02-18T16:51:09.097Z" }, - { url = "https://files.pythonhosted.org/packages/2e/96/102244653ee5a143ece5afe33f00f52fe64e389dfce8dbc87580c6d70d3d/psycopg_binary-3.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:74eae563166ebf74e8d950ff359be037b85723d99ca83f57d9b244a871d6c13b", size = 3551342, upload-time = "2026-02-18T16:51:13.892Z" }, { url = "https://files.pythonhosted.org/packages/a2/71/7a57e5b12275fe7e7d84d54113f0226080423a869118419c9106c083a21c/psycopg_binary-3.3.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:497852c5eaf1f0c2d88ab74a64a8097c099deac0c71de1cbcf18659a8a04a4b2", size = 4607368, upload-time = "2026-02-18T16:51:19.295Z" }, { url = "https://files.pythonhosted.org/packages/c7/04/cb834f120f2b2c10d4003515ef9ca9d688115b9431735e3936ae48549af8/psycopg_binary-3.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:258d1ea53464d29768bf25930f43291949f4c7becc706f6e220c515a63a24edd", size = 4687047, upload-time = "2026-02-18T16:51:23.84Z" }, { url = "https://files.pythonhosted.org/packages/40/e9/47a69692d3da9704468041aa5ed3ad6fc7f6bb1a5ae788d261a26bbca6c7/psycopg_binary-3.3.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:111c59897a452196116db12e7f608da472fbff000693a21040e35fc978b23430", size = 5487096, upload-time = "2026-02-18T16:51:29.645Z" }, @@ -2009,6 +970,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/98/5a/291d89f44d3820fffb7a04ebc8f3ef5dda4f542f44a5daea0c55a84abf45/psycopg_binary-3.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:165f22ab5a9513a3d7425ffb7fcc7955ed8ccaeef6d37e369d6cc1dff1582383", size = 3652796, upload-time = "2026-02-18T16:52:14.02Z" }, ] +[[package]] +name = "puremagic" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/df/3725f4b848095ef634c0b2226c97901e64ee2d5a82981d89d4b784ae8ce1/puremagic-2.1.1.tar.gz", hash = "sha256:b156c4ae63d84842f92a85cd49c9b9029a4f107f98ad14e7584ed652954feff4", size = 1133417, upload-time = "2026-03-23T19:08:46.929Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/d0/12b1d4113fd6660a0a75e8c40500c5d1c4febd8e24dc85aaf20cfd93e9d6/puremagic-2.1.1-py3-none-any.whl", hash = "sha256:b8862451f96254358a6e2ea7fba46e0600cf8b13ebe917d6eecdb18fc22db964", size = 68025, upload-time = "2026-03-23T19:08:45.872Z" }, +] + [[package]] name = "pwdlib" version = "0.3.0" @@ -2028,11 +998,11 @@ bcrypt = [ [[package]] name = "pyasn1" -version = "0.6.2" +version = "0.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/b6/6e630dff89739fcd427e3f72b3d905ce0acb85a45d4ec3e2678718a3487f/pyasn1-0.6.2.tar.gz", hash = "sha256:9b59a2b25ba7e4f8197db7686c09fb33e658b98339fadb826e9512629017833b", size = 146586, upload-time = "2026-01-16T18:04:18.534Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/b5/a96872e5184f354da9c84ae119971a0a4c221fe9b27a4d94bd43f2596727/pyasn1-0.6.2-py3-none-any.whl", hash = "sha256:1eb26d860996a18e9b6ed05e7aae0e9fc21619fcee6af91cca9bad4fbea224bf", size = 83371, upload-time = "2026-01-16T18:04:17.174Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" }, ] [[package]] @@ -2080,61 +1050,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" }, - { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" }, - { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" }, - { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" }, - { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" }, - { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" }, - { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" }, - { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" }, - { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" }, - { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" }, - { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" }, - { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" }, - { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" }, - { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" }, - { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" }, - { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" }, - { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" }, - { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" }, - { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" }, - { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" }, - { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" }, - { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" }, - { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" }, - { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" }, - { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" }, - { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" }, - { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, - { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, - { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, - { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, - { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, - { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, - { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, - { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, - { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, - { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, - { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, - { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, - { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, - { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, - { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, - { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, - { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, - { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, - { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, - { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, - { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, - { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, - { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, - { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, - { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, - { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, @@ -2163,30 +1078,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, - { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, - { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, - { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, - { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" }, - { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, - { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, - { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, - { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" }, - { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" }, - { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" }, - { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" }, - { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" }, - { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" }, - { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" }, - { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" }, - { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" }, - { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" }, - { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" }, - { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, +] + +[[package]] +name = "pydantic-extra-types" +version = "2.11.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/41/d3/3be31542180c0300b6860129ff1e3a428f3ef580727616ce22462626129b/pydantic_extra_types-2.11.2.tar.gz", hash = "sha256:3a2b83b61fe920925688e7838b59caa90a45637d1dbba2b1364b8d1f7ff72a0a", size = 203929, upload-time = "2026-04-05T20:50:51.556Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/a4/7b6ab05c18d6c6e682382a0f0235301684452c4131a869f45961d1d032c9/pydantic_extra_types-2.11.2-py3-none-any.whl", hash = "sha256:683b8943252543e49760f89733b1519bc62f31d1a287ebbdc5a7b7959fb4acfd", size = 82851, upload-time = "2026-04-05T20:50:50.036Z" }, ] [[package]] @@ -2205,58 +1109,54 @@ wheels = [ [[package]] name = "pydata-sphinx-theme" -version = "0.16.1" +version = "0.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "accessible-pygments" }, { name = "babel" }, { name = "beautifulsoup4" }, - { name = "docutils", version = "0.21.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "docutils" }, { name = "pygments" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, - { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "sphinx" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/20/bb50f9de3a6de69e6abd6b087b52fa2418a0418b19597601605f855ad044/pydata_sphinx_theme-0.16.1.tar.gz", hash = "sha256:a08b7f0b7f70387219dc659bff0893a7554d5eb39b59d3b8ef37b8401b7642d7", size = 2412693, upload-time = "2024-12-17T10:53:39.537Z" } +sdist = { url = "https://files.pythonhosted.org/packages/de/bb/4a97aaa840b26601d6d04deca1389c35025336428706a4a732051187fbd3/pydata_sphinx_theme-0.17.0.tar.gz", hash = "sha256:529c5631582cb3328cf4814fb9eb80611d1704c854406d282a75c9c86e3a1955", size = 4990605, upload-time = "2026-04-03T13:02:20.091Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/0d/8ba33fa83a7dcde13eb3c1c2a0c1cc29950a048bfed6d9b0d8b6bd710b4c/pydata_sphinx_theme-0.16.1-py3-none-any.whl", hash = "sha256:225331e8ac4b32682c18fcac5a57a6f717c4e632cea5dd0e247b55155faeccde", size = 6723264, upload-time = "2024-12-17T10:53:35.645Z" }, + { url = "https://files.pythonhosted.org/packages/9d/b7/a2bae25aae3568fe9f17040b31f9c190b4c5d86856d8869d0a30364a2567/pydata_sphinx_theme-0.17.0-py3-none-any.whl", hash = "sha256:cec5c92f41f4a11541b6df8210c446b4aa9c3badb7fcf2db7893405b786d5c99", size = 6820685, upload-time = "2026-04-03T13:02:18.09Z" }, ] [[package]] name = "pygments" -version = "2.19.2" +version = "2.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] [[package]] name = "pyjwt" -version = "2.11.0" +version = "2.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" }, + { url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" }, ] [[package]] name = "pytest" -version = "7.4.4" +version = "9.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/1f/9d8e98e4133ffb16c90f3b405c43e38d3abb715bb5d7a63a5a684f7e46a3/pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280", size = 1357116, upload-time = "2023-12-31T12:00:18.035Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8", size = 325287, upload-time = "2023-12-31T12:00:13.963Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, ] [[package]] @@ -2282,20 +1182,11 @@ wheels = [ [[package]] name = "python-multipart" -version = "0.0.22" +version = "0.0.24" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/45/e23b5dc14ddb9918ae4a625379506b17b6f8fc56ca1d82db62462f59aea6/python_multipart-0.0.24.tar.gz", hash = "sha256:9574c97e1c026e00bc30340ef7c7d76739512ab4dfd428fec8c330fa6a5cc3c8", size = 37695, upload-time = "2026-04-05T20:49:13.829Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" }, -] - -[[package]] -name = "pytz" -version = "2026.1.post1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" }, + { url = "https://files.pythonhosted.org/packages/a3/73/89930efabd4da63cea44a3f438aeb753d600123570e6d6264e763617a9ce/python_multipart-0.0.24-py3-none-any.whl", hash = "sha256:9b110a98db707df01a53c194f0af075e736a770dc5058089650d70b4a182f950", size = 24420, upload-time = "2026-04-05T20:49:12.555Z" }, ] [[package]] @@ -2304,44 +1195,6 @@ version = "6.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, - { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, - { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, - { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, - { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, - { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, - { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, - { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, - { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, - { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, - { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, - { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, - { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, - { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, - { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, - { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, - { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, - { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, - { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, - { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, - { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, - { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, - { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, - { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, - { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, - { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, - { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, @@ -2364,7 +1217,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.5" +version = "2.33.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -2372,9 +1225,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, ] [[package]] @@ -2382,8 +1235,7 @@ name = "rich" version = "14.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "markdown-it-py" }, { name = "pygments" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" } @@ -2414,59 +1266,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/54/6f679c435d28e0a568d8e8a7c0a93a09010818634c3c3907fc98d8983770/roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7", size = 7676, upload-time = "2025-12-17T18:25:33.098Z" }, ] -[[package]] -name = "rsa" -version = "4.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyasn1" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, -] - [[package]] name = "ruff" -version = "0.15.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/77/9b/840e0039e65fcf12758adf684d2289024d6140cde9268cc59887dc55189c/ruff-0.15.5.tar.gz", hash = "sha256:7c3601d3b6d76dce18c5c824fc8d06f4eef33d6df0c21ec7799510cde0f159a2", size = 4574214, upload-time = "2026-03-05T20:06:34.946Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/20/5369c3ce21588c708bcbe517a8fbe1a8dfdb5dfd5137e14790b1da71612c/ruff-0.15.5-py3-none-linux_armv6l.whl", hash = "sha256:4ae44c42281f42e3b06b988e442d344a5b9b72450ff3c892e30d11b29a96a57c", size = 10478185, upload-time = "2026-03-05T20:06:29.093Z" }, - { url = "https://files.pythonhosted.org/packages/44/ed/e81dd668547da281e5dce710cf0bc60193f8d3d43833e8241d006720e42b/ruff-0.15.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6edd3792d408ebcf61adabc01822da687579a1a023f297618ac27a5b51ef0080", size = 10859201, upload-time = "2026-03-05T20:06:32.632Z" }, - { url = "https://files.pythonhosted.org/packages/c4/8f/533075f00aaf19b07c5cd6aa6e5d89424b06b3b3f4583bfa9c640a079059/ruff-0.15.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:89f463f7c8205a9f8dea9d658d59eff49db05f88f89cc3047fb1a02d9f344010", size = 10184752, upload-time = "2026-03-05T20:06:40.312Z" }, - { url = "https://files.pythonhosted.org/packages/66/0e/ba49e2c3fa0395b3152bad634c7432f7edfc509c133b8f4529053ff024fb/ruff-0.15.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba786a8295c6574c1116704cf0b9e6563de3432ac888d8f83685654fe528fd65", size = 10534857, upload-time = "2026-03-05T20:06:19.581Z" }, - { url = "https://files.pythonhosted.org/packages/59/71/39234440f27a226475a0659561adb0d784b4d247dfe7f43ffc12dd02e288/ruff-0.15.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd4b801e57955fe9f02b31d20375ab3a5c4415f2e5105b79fb94cf2642c91440", size = 10309120, upload-time = "2026-03-05T20:06:00.435Z" }, - { url = "https://files.pythonhosted.org/packages/f5/87/4140aa86a93df032156982b726f4952aaec4a883bb98cb6ef73c347da253/ruff-0.15.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391f7c73388f3d8c11b794dbbc2959a5b5afe66642c142a6effa90b45f6f5204", size = 11047428, upload-time = "2026-03-05T20:05:51.867Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f7/4953e7e3287676f78fbe85e3a0ca414c5ca81237b7575bdadc00229ac240/ruff-0.15.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc18f30302e379fe1e998548b0f5e9f4dff907f52f73ad6da419ea9c19d66c8", size = 11914251, upload-time = "2026-03-05T20:06:22.887Z" }, - { url = "https://files.pythonhosted.org/packages/77/46/0f7c865c10cf896ccf5a939c3e84e1cfaeed608ff5249584799a74d33835/ruff-0.15.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc6e7f90087e2d27f98dc34ed1b3ab7c8f0d273cc5431415454e22c0bd2a681", size = 11333801, upload-time = "2026-03-05T20:05:57.168Z" }, - { url = "https://files.pythonhosted.org/packages/d3/01/a10fe54b653061585e655f5286c2662ebddb68831ed3eaebfb0eb08c0a16/ruff-0.15.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cb7169f53c1ddb06e71a9aebd7e98fc0fea936b39afb36d8e86d36ecc2636a", size = 11206821, upload-time = "2026-03-05T20:06:03.441Z" }, - { url = "https://files.pythonhosted.org/packages/7a/0d/2132ceaf20c5e8699aa83da2706ecb5c5dcdf78b453f77edca7fb70f8a93/ruff-0.15.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9b037924500a31ee17389b5c8c4d88874cc6ea8e42f12e9c61a3d754ff72f1ca", size = 11133326, upload-time = "2026-03-05T20:06:25.655Z" }, - { url = "https://files.pythonhosted.org/packages/72/cb/2e5259a7eb2a0f87c08c0fe5bf5825a1e4b90883a52685524596bfc93072/ruff-0.15.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65bb414e5b4eadd95a8c1e4804f6772bbe8995889f203a01f77ddf2d790929dd", size = 10510820, upload-time = "2026-03-05T20:06:37.79Z" }, - { url = "https://files.pythonhosted.org/packages/ff/20/b67ce78f9e6c59ffbdb5b4503d0090e749b5f2d31b599b554698a80d861c/ruff-0.15.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d20aa469ae3b57033519c559e9bc9cd9e782842e39be05b50e852c7c981fa01d", size = 10302395, upload-time = "2026-03-05T20:05:54.504Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e5/719f1acccd31b720d477751558ed74e9c88134adcc377e5e886af89d3072/ruff-0.15.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:15388dd28c9161cdb8eda68993533acc870aa4e646a0a277aa166de9ad5a8752", size = 10754069, upload-time = "2026-03-05T20:06:06.422Z" }, - { url = "https://files.pythonhosted.org/packages/c3/9c/d1db14469e32d98f3ca27079dbd30b7b44dbb5317d06ab36718dee3baf03/ruff-0.15.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b30da330cbd03bed0c21420b6b953158f60c74c54c5f4c1dabbdf3a57bf355d2", size = 11304315, upload-time = "2026-03-05T20:06:10.867Z" }, - { url = "https://files.pythonhosted.org/packages/28/3a/950367aee7c69027f4f422059227b290ed780366b6aecee5de5039d50fa8/ruff-0.15.5-py3-none-win32.whl", hash = "sha256:732e5ee1f98ba5b3679029989a06ca39a950cced52143a0ea82a2102cb592b74", size = 10551676, upload-time = "2026-03-05T20:06:13.705Z" }, - { url = "https://files.pythonhosted.org/packages/b8/00/bf077a505b4e649bdd3c47ff8ec967735ce2544c8e4a43aba42ee9bf935d/ruff-0.15.5-py3-none-win_amd64.whl", hash = "sha256:821d41c5fa9e19117616c35eaa3f4b75046ec76c65e7ae20a333e9a8696bc7fe", size = 11678972, upload-time = "2026-03-05T20:06:45.379Z" }, - { url = "https://files.pythonhosted.org/packages/fe/4e/cd76eca6db6115604b7626668e891c9dd03330384082e33662fb0f113614/ruff-0.15.5-py3-none-win_arm64.whl", hash = "sha256:b498d1c60d2fe5c10c45ec3f698901065772730b411f164ae270bb6bfcc4740b", size = 10965572, upload-time = "2026-03-05T20:06:16.984Z" }, -] - -[[package]] -name = "sentry-sdk" -version = "1.45.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c8/28/02c0cd9184f9108e3c52519f9628b215077a3854240e0b17ae845e664855/sentry_sdk-1.45.1.tar.gz", hash = "sha256:a16c997c0f4e3df63c0fc5e4207ccb1ab37900433e0f72fef88315d317829a26", size = 244774, upload-time = "2024-07-26T13:48:32.375Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/9f/105366a122efa93f0cb1914f841747d160788e4d022d0488d2d44c2ba26c/sentry_sdk-1.45.1-py2.py3-none-any.whl", hash = "sha256:608887855ccfe39032bfd03936e3a1c4f4fc99b3a4ac49ced54a4220de61c9c1", size = 267163, upload-time = "2024-07-26T13:48:29.38Z" }, -] - -[package.optional-dependencies] -fastapi = [ - { name = "fastapi" }, +version = "0.15.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/97/e9f1ca355108ef7194e38c812ef40ba98c7208f47b13ad78d023caa583da/ruff-0.15.9.tar.gz", hash = "sha256:29cbb1255a9797903f6dde5ba0188c707907ff44a9006eb273b5a17bfa0739a2", size = 4617361, upload-time = "2026-04-02T18:17:20.829Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/1f/9cdfd0ac4b9d1e5a6cf09bedabdf0b56306ab5e333c85c87281273e7b041/ruff-0.15.9-py3-none-linux_armv6l.whl", hash = "sha256:6efbe303983441c51975c243e26dff328aca11f94b70992f35b093c2e71801e1", size = 10511206, upload-time = "2026-04-02T18:16:41.574Z" }, + { url = "https://files.pythonhosted.org/packages/3d/f6/32bfe3e9c136b35f02e489778d94384118bb80fd92c6d92e7ccd97db12ce/ruff-0.15.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4965bac6ac9ea86772f4e23587746f0b7a395eccabb823eb8bfacc3fa06069f7", size = 10923307, upload-time = "2026-04-02T18:17:08.645Z" }, + { url = "https://files.pythonhosted.org/packages/ca/25/de55f52ab5535d12e7aaba1de37a84be6179fb20bddcbe71ec091b4a3243/ruff-0.15.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eaf05aad70ca5b5a0a4b0e080df3a6b699803916d88f006efd1f5b46302daab8", size = 10316722, upload-time = "2026-04-02T18:16:44.206Z" }, + { url = "https://files.pythonhosted.org/packages/48/11/690d75f3fd6278fe55fff7c9eb429c92d207e14b25d1cae4064a32677029/ruff-0.15.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9439a342adb8725f32f92732e2bafb6d5246bd7a5021101166b223d312e8fc59", size = 10623674, upload-time = "2026-04-02T18:16:50.951Z" }, + { url = "https://files.pythonhosted.org/packages/bd/ec/176f6987be248fc5404199255522f57af1b4a5a1b57727e942479fec98ad/ruff-0.15.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c5e6faf9d97c8edc43877c3f406f47446fc48c40e1442d58cfcdaba2acea745", size = 10351516, upload-time = "2026-04-02T18:16:57.206Z" }, + { url = "https://files.pythonhosted.org/packages/b2/fc/51cffbd2b3f240accc380171d51446a32aa2ea43a40d4a45ada67368fbd2/ruff-0.15.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b34a9766aeec27a222373d0b055722900fbc0582b24f39661aa96f3fe6ad901", size = 11150202, upload-time = "2026-04-02T18:17:06.452Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d4/25292a6dfc125f6b6528fe6af31f5e996e19bf73ca8e3ce6eb7fa5b95885/ruff-0.15.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89dd695bc72ae76ff484ae54b7e8b0f6b50f49046e198355e44ea656e521fef9", size = 11988891, upload-time = "2026-04-02T18:17:18.575Z" }, + { url = "https://files.pythonhosted.org/packages/13/e1/1eebcb885c10e19f969dcb93d8413dfee8172578709d7ee933640f5e7147/ruff-0.15.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce187224ef1de1bd225bc9a152ac7102a6171107f026e81f317e4257052916d5", size = 11480576, upload-time = "2026-04-02T18:16:52.986Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6b/a1548ac378a78332a4c3dcf4a134c2475a36d2a22ddfa272acd574140b50/ruff-0.15.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b0c7c341f68adb01c488c3b7d4b49aa8ea97409eae6462d860a79cf55f431b6", size = 11254525, upload-time = "2026-04-02T18:17:02.041Z" }, + { url = "https://files.pythonhosted.org/packages/42/aa/4bb3af8e61acd9b1281db2ab77e8b2c3c5e5599bf2a29d4a942f1c62b8d6/ruff-0.15.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:55cc15eee27dc0eebdfcb0d185a6153420efbedc15eb1d38fe5e685657b0f840", size = 11204072, upload-time = "2026-04-02T18:17:13.581Z" }, + { url = "https://files.pythonhosted.org/packages/69/48/d550dc2aa6e423ea0bcc1d0ff0699325ffe8a811e2dba156bd80750b86dc/ruff-0.15.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a6537f6eed5cda688c81073d46ffdfb962a5f29ecb6f7e770b2dc920598997ed", size = 10594998, upload-time = "2026-04-02T18:16:46.369Z" }, + { url = "https://files.pythonhosted.org/packages/63/47/321167e17f5344ed5ec6b0aa2cff64efef5f9e985af8f5622cfa6536043f/ruff-0.15.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6d3fcbca7388b066139c523bda744c822258ebdcfbba7d24410c3f454cc9af71", size = 10359769, upload-time = "2026-04-02T18:17:10.994Z" }, + { url = "https://files.pythonhosted.org/packages/67/5e/074f00b9785d1d2c6f8c22a21e023d0c2c1817838cfca4c8243200a1fa87/ruff-0.15.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:058d8e99e1bfe79d8a0def0b481c56059ee6716214f7e425d8e737e412d69677", size = 10850236, upload-time = "2026-04-02T18:16:48.749Z" }, + { url = "https://files.pythonhosted.org/packages/76/37/804c4135a2a2caf042925d30d5f68181bdbd4461fd0d7739da28305df593/ruff-0.15.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8e1ddb11dbd61d5983fa2d7d6370ef3eb210951e443cace19594c01c72abab4c", size = 11358343, upload-time = "2026-04-02T18:16:55.068Z" }, + { url = "https://files.pythonhosted.org/packages/88/3d/1364fcde8656962782aa9ea93c92d98682b1ecec2f184e625a965ad3b4a6/ruff-0.15.9-py3-none-win32.whl", hash = "sha256:bde6ff36eaf72b700f32b7196088970bf8fdb2b917b7accd8c371bfc0fd573ec", size = 10583382, upload-time = "2026-04-02T18:17:04.261Z" }, + { url = "https://files.pythonhosted.org/packages/4c/56/5c7084299bd2cacaa07ae63a91c6f4ba66edc08bf28f356b24f6b717c799/ruff-0.15.9-py3-none-win_amd64.whl", hash = "sha256:45a70921b80e1c10cf0b734ef09421f71b5aa11d27404edc89d7e8a69505e43d", size = 11744969, upload-time = "2026-04-02T18:16:59.611Z" }, + { url = "https://files.pythonhosted.org/packages/03/36/76704c4f312257d6dbaae3c959add2a622f63fcca9d864659ce6d8d97d3d/ruff-0.15.9-py3-none-win_arm64.whl", hash = "sha256:0694e601c028fd97dc5c6ee244675bc241aeefced7ef80cd9c6935a871078f53", size = 11005870, upload-time = "2026-04-02T18:17:15.773Z" }, ] [[package]] @@ -2505,155 +1327,45 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" }, ] -[[package]] -name = "sphinx" -version = "8.1.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "alabaster", marker = "python_full_version < '3.11'" }, - { name = "babel", marker = "python_full_version < '3.11'" }, - { name = "colorama", marker = "python_full_version < '3.11' and sys_platform == 'win32'" }, - { name = "docutils", version = "0.21.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "imagesize", marker = "python_full_version < '3.11'" }, - { name = "jinja2", marker = "python_full_version < '3.11'" }, - { name = "packaging", marker = "python_full_version < '3.11'" }, - { name = "pygments", marker = "python_full_version < '3.11'" }, - { name = "requests", marker = "python_full_version < '3.11'" }, - { name = "snowballstemmer", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-applehelp", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-devhelp", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-htmlhelp", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-jsmath", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-qthelp", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-serializinghtml", marker = "python_full_version < '3.11'" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611, upload-time = "2024-10-13T20:27:13.93Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2", size = 3487125, upload-time = "2024-10-13T20:27:10.448Z" }, -] - -[[package]] -name = "sphinx" -version = "9.0.4" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -dependencies = [ - { name = "alabaster", marker = "python_full_version == '3.11.*'" }, - { name = "babel", marker = "python_full_version == '3.11.*'" }, - { name = "colorama", marker = "python_full_version == '3.11.*' and sys_platform == 'win32'" }, - { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, - { name = "imagesize", marker = "python_full_version == '3.11.*'" }, - { name = "jinja2", marker = "python_full_version == '3.11.*'" }, - { name = "packaging", marker = "python_full_version == '3.11.*'" }, - { name = "pygments", marker = "python_full_version == '3.11.*'" }, - { name = "requests", marker = "python_full_version == '3.11.*'" }, - { name = "roman-numerals", marker = "python_full_version == '3.11.*'" }, - { name = "snowballstemmer", marker = "python_full_version == '3.11.*'" }, - { name = "sphinxcontrib-applehelp", marker = "python_full_version == '3.11.*'" }, - { name = "sphinxcontrib-devhelp", marker = "python_full_version == '3.11.*'" }, - { name = "sphinxcontrib-htmlhelp", marker = "python_full_version == '3.11.*'" }, - { name = "sphinxcontrib-jsmath", marker = "python_full_version == '3.11.*'" }, - { name = "sphinxcontrib-qthelp", marker = "python_full_version == '3.11.*'" }, - { name = "sphinxcontrib-serializinghtml", marker = "python_full_version == '3.11.*'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/42/50/a8c6ccc36d5eacdfd7913ddccd15a9cee03ecafc5ee2bc40e1f168d85022/sphinx-9.0.4.tar.gz", hash = "sha256:594ef59d042972abbc581d8baa577404abe4e6c3b04ef61bd7fc2acbd51f3fa3", size = 8710502, upload-time = "2025-12-04T07:45:27.343Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/3f/4bbd76424c393caead2e1eb89777f575dee5c8653e2d4b6afd7a564f5974/sphinx-9.0.4-py3-none-any.whl", hash = "sha256:5bebc595a5e943ea248b99c13814c1c5e10b3ece718976824ffa7959ff95fffb", size = 3917713, upload-time = "2025-12-04T07:45:24.944Z" }, -] - [[package]] name = "sphinx" version = "9.1.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] dependencies = [ - { name = "alabaster", marker = "python_full_version >= '3.12'" }, - { name = "babel", marker = "python_full_version >= '3.12'" }, - { name = "colorama", marker = "python_full_version >= '3.12' and sys_platform == 'win32'" }, - { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "imagesize", marker = "python_full_version >= '3.12'" }, - { name = "jinja2", marker = "python_full_version >= '3.12'" }, - { name = "packaging", marker = "python_full_version >= '3.12'" }, - { name = "pygments", marker = "python_full_version >= '3.12'" }, - { name = "requests", marker = "python_full_version >= '3.12'" }, - { name = "roman-numerals", marker = "python_full_version >= '3.12'" }, - { name = "snowballstemmer", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-applehelp", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-devhelp", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-htmlhelp", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-jsmath", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-qthelp", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-serializinghtml", marker = "python_full_version >= '3.12'" }, + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cd/bd/f08eb0f4eed5c83f1ba2a3bd18f7745a2b1525fad70660a1c00224ec468a/sphinx-9.1.0.tar.gz", hash = "sha256:7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb", size = 8718324, upload-time = "2025-12-31T15:09:27.646Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/73/f7/b1884cb3188ab181fc81fa00c266699dab600f927a964df02ec3d5d1916a/sphinx-9.1.0-py3-none-any.whl", hash = "sha256:c84fdd4e782504495fe4f2c0b3413d6c2bf388589bb352d439b2a3bb99991978", size = 3921742, upload-time = "2025-12-31T15:09:25.561Z" }, ] -[[package]] -name = "sphinx-autobuild" -version = "2024.10.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "colorama", marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "starlette", marker = "python_full_version < '3.11'" }, - { name = "uvicorn", marker = "python_full_version < '3.11'" }, - { name = "watchfiles", marker = "python_full_version < '3.11'" }, - { name = "websockets", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a5/2c/155e1de2c1ba96a72e5dba152c509a8b41e047ee5c2def9e9f0d812f8be7/sphinx_autobuild-2024.10.3.tar.gz", hash = "sha256:248150f8f333e825107b6d4b86113ab28fa51750e5f9ae63b59dc339be951fb1", size = 14023, upload-time = "2024-10-02T23:15:30.172Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/c0/eba125db38c84d3c74717008fd3cb5000b68cd7e2cbafd1349c6a38c3d3b/sphinx_autobuild-2024.10.3-py3-none-any.whl", hash = "sha256:158e16c36f9d633e613c9aaf81c19b0fc458ca78b112533b20dafcda430d60fa", size = 11908, upload-time = "2024-10-02T23:15:28.739Z" }, -] - [[package]] name = "sphinx-autobuild" version = "2025.8.25" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.11'" }, - { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, - { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "starlette", marker = "python_full_version >= '3.11'" }, - { name = "uvicorn", marker = "python_full_version >= '3.11'" }, - { name = "watchfiles", marker = "python_full_version >= '3.11'" }, - { name = "websockets", marker = "python_full_version >= '3.11'" }, + { name = "colorama" }, + { name = "sphinx" }, + { name = "starlette" }, + { name = "uvicorn" }, + { name = "watchfiles" }, + { name = "websockets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e0/3c/a59a3a453d4133777f7ed2e83c80b7dc817d43c74b74298ca0af869662ad/sphinx_autobuild-2025.8.25.tar.gz", hash = "sha256:9cf5aab32853c8c31af572e4fecdc09c997e2b8be5a07daf2a389e270e85b213", size = 15200, upload-time = "2025-08-25T18:44:55.436Z" } wheels = [ @@ -2662,95 +1374,22 @@ wheels = [ [[package]] name = "sphinx-autodoc-typehints" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/26/f0/43c6a5ff3e7b08a8c3b32f81b859f1b518ccc31e45f22e2b41ced38be7b9/sphinx_autodoc_typehints-3.0.1.tar.gz", hash = "sha256:b9b40dd15dee54f6f810c924f863f9cf1c54f9f3265c495140ea01be7f44fa55", size = 36282, upload-time = "2025-01-16T18:25:30.958Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/dc/dc46c5c7c566b7ec5e8f860f9c89533bf03c0e6aadc96fb9b337867e4460/sphinx_autodoc_typehints-3.0.1-py3-none-any.whl", hash = "sha256:4b64b676a14b5b79cefb6628a6dc8070e320d4963e8ff640a2f3e9390ae9045a", size = 20245, upload-time = "2025-01-16T18:25:27.394Z" }, -] - -[[package]] -name = "sphinx-autodoc-typehints" -version = "3.6.1" +version = "3.9.11" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] dependencies = [ - { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1d/f6/bdd93582b2aaad2cfe9eb5695a44883c8bc44572dd3c351a947acbb13789/sphinx_autodoc_typehints-3.6.1.tar.gz", hash = "sha256:fa0b686ae1b85965116c88260e5e4b82faec3687c2e94d6a10f9b36c3743e2fe", size = 37563, upload-time = "2026-01-02T15:23:46.543Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/6a/c0360b115c81d449b3b73bf74b64ca773464d5c7b1b77bda87c5e874853b/sphinx_autodoc_typehints-3.6.1-py3-none-any.whl", hash = "sha256:dd818ba31d4c97f219a8c0fcacef280424f84a3589cedcb73003ad99c7da41ca", size = 20869, upload-time = "2026-01-02T15:23:45.194Z" }, -] - -[[package]] -name = "sphinx-autodoc-typehints" -version = "3.9.8" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] -dependencies = [ - { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/4d/02216afa475c838c123b41f30e3a2875ad27c14fae3f5bbed4ba4e7fd894/sphinx_autodoc_typehints-3.9.8.tar.gz", hash = "sha256:1e36b31ee593b7e838988045918b7fa965f5062abbd6800af96d5e2c3f17130e", size = 68763, upload-time = "2026-03-09T15:40:01.02Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/6c/f275f59095b2fec6627c3ce2caba4e18f55a3925718cf0547cde04821a37/sphinx_autodoc_typehints-3.9.8-py3-none-any.whl", hash = "sha256:df123ec82479934fed27e31d4ccdcf382901c5d9481450fc224054496e574466", size = 36685, upload-time = "2026-03-09T15:39:59.567Z" }, -] - -[[package]] -name = "sphinx-design" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2b/69/b34e0cb5336f09c6866d53b4a19d76c227cdec1bbc7ac4de63ca7d58c9c7/sphinx_design-0.6.1.tar.gz", hash = "sha256:b44eea3719386d04d765c1a8257caca2b3e6f8421d7b3a5e742c0fd45f84e632", size = 2193689, upload-time = "2024-08-02T13:48:44.277Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/e9/d29ae58dd12971d2cbb872884676a70d1a5e4719b4d82e197264cdf0431a/sphinx_autodoc_typehints-3.9.11.tar.gz", hash = "sha256:28516c916b41fa83271ee2ab9191b73807e4113d3bfb94222ac87d8d9795b6e7", size = 70261, upload-time = "2026-03-24T16:57:28.462Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/43/65c0acbd8cc6f50195a3a1fc195c404988b15c67090e73c7a41a9f57d6bd/sphinx_design-0.6.1-py3-none-any.whl", hash = "sha256:b11f37db1a802a183d61b159d9a202314d4d2fe29c163437001324fe2f19549c", size = 2215338, upload-time = "2024-08-02T13:48:42.106Z" }, + { url = "https://files.pythonhosted.org/packages/dd/e3/ff212b51c16717681792eaf18691e6b5affbbb3d4290147c457fa9127372/sphinx_autodoc_typehints-3.9.11-py3-none-any.whl", hash = "sha256:b5cbc7a56a9338021ab7a4e6aa132aa7829fa2f8b64eca927faab64cd3971b80", size = 37279, upload-time = "2026-03-24T16:57:27.147Z" }, ] [[package]] name = "sphinx-design" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] dependencies = [ - { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, - { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/13/7b/804f311da4663a4aecc6cf7abd83443f3d4ded970826d0c958edc77d4527/sphinx_design-0.7.0.tar.gz", hash = "sha256:d2a3f5b19c24b916adb52f97c5f00efab4009ca337812001109084a740ec9b7a", size = 2203582, upload-time = "2026-01-19T13:12:53.297Z" } wheels = [ @@ -2800,9 +1439,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jinja2" }, { name = "pyyaml" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, - { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2b/ae/999891de292919b66ea34f2c22fc22c9be90ab3536fbc0fca95716277351/sphinxcontrib_mermaid-2.0.1.tar.gz", hash = "sha256:a21a385a059a6cafd192aa3a586b14bf5c42721e229db67b459dc825d7f0a497", size = 19839, upload-time = "2026-03-05T14:10:41.901Z" } wheels = [ @@ -2829,150 +1466,87 @@ wheels = [ [[package]] name = "sqlalchemy" -version = "2.0.48" +version = "2.0.49" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1f/73/b4a9737255583b5fa858e0bb8e116eb94b88c910164ed2ed719147bde3de/sqlalchemy-2.0.48.tar.gz", hash = "sha256:5ca74f37f3369b45e1f6b7b06afb182af1fd5dde009e4ffd831830d98cbe5fe7", size = 9886075, upload-time = "2026-03-02T15:28:51.474Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/67/1235676e93dd3b742a4a8eddfae49eea46c85e3eed29f0da446a8dd57500/sqlalchemy-2.0.48-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7001dc9d5f6bb4deb756d5928eaefe1930f6f4179da3924cbd95ee0e9f4dce89", size = 2157384, upload-time = "2026-03-02T15:38:26.781Z" }, - { url = "https://files.pythonhosted.org/packages/4d/d7/fa728b856daa18c10e1390e76f26f64ac890c947008284387451d56ca3d0/sqlalchemy-2.0.48-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1a89ce07ad2d4b8cfc30bd5889ec40613e028ed80ef47da7d9dd2ce969ad30e0", size = 3236981, upload-time = "2026-03-02T15:58:53.53Z" }, - { url = "https://files.pythonhosted.org/packages/5c/ad/6c4395649a212a6c603a72c5b9ab5dce3135a1546cfdffa3c427e71fd535/sqlalchemy-2.0.48-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10853a53a4a00417a00913d270dddda75815fcb80675874285f41051c094d7dd", size = 3235232, upload-time = "2026-03-02T15:52:25.654Z" }, - { url = "https://files.pythonhosted.org/packages/01/f4/58f845e511ac0509765a6f85eb24924c1ef0d54fb50de9d15b28c3601458/sqlalchemy-2.0.48-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fac0fa4e4f55f118fd87177dacb1c6522fe39c28d498d259014020fec9164c29", size = 3188106, upload-time = "2026-03-02T15:58:55.193Z" }, - { url = "https://files.pythonhosted.org/packages/3f/f9/6dcc7bfa5f5794c3a095e78cd1de8269dfb5584dfd4c2c00a50d3c1ade44/sqlalchemy-2.0.48-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3713e21ea67bca727eecd4a24bf68bcd414c403faae4989442be60994301ded0", size = 3209522, upload-time = "2026-03-02T15:52:27.407Z" }, - { url = "https://files.pythonhosted.org/packages/d7/5a/b632875ab35874d42657f079529f0745410604645c269a8c21fb4272ff7a/sqlalchemy-2.0.48-cp310-cp310-win32.whl", hash = "sha256:d404dc897ce10e565d647795861762aa2d06ca3f4a728c5e9a835096c7059018", size = 2117695, upload-time = "2026-03-02T15:46:51.389Z" }, - { url = "https://files.pythonhosted.org/packages/de/03/9752eb2a41afdd8568e41ac3c3128e32a0a73eada5ab80483083604a56d1/sqlalchemy-2.0.48-cp310-cp310-win_amd64.whl", hash = "sha256:841a94c66577661c1f088ac958cd767d7c9bf507698f45afffe7a4017049de76", size = 2140928, upload-time = "2026-03-02T15:46:52.992Z" }, - { url = "https://files.pythonhosted.org/packages/d7/6d/b8b78b5b80f3c3ab3f7fa90faa195ec3401f6d884b60221260fd4d51864c/sqlalchemy-2.0.48-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b4c575df7368b3b13e0cebf01d4679f9a28ed2ae6c1cd0b1d5beffb6b2007dc", size = 2157184, upload-time = "2026-03-02T15:38:28.161Z" }, - { url = "https://files.pythonhosted.org/packages/21/4b/4f3d4a43743ab58b95b9ddf5580a265b593d017693df9e08bd55780af5bb/sqlalchemy-2.0.48-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e83e3f959aaa1c9df95c22c528096d94848a1bc819f5d0ebf7ee3df0ca63db6c", size = 3313555, upload-time = "2026-03-02T15:58:57.21Z" }, - { url = "https://files.pythonhosted.org/packages/21/dd/3b7c53f1dbbf736fd27041aee68f8ac52226b610f914085b1652c2323442/sqlalchemy-2.0.48-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f7b7243850edd0b8b97043f04748f31de50cf426e939def5c16bedb540698f7", size = 3313057, upload-time = "2026-03-02T15:52:29.366Z" }, - { url = "https://files.pythonhosted.org/packages/d9/cc/3e600a90ae64047f33313d7d32e5ad025417f09d2ded487e8284b5e21a15/sqlalchemy-2.0.48-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:82745b03b4043e04600a6b665cb98697c4339b24e34d74b0a2ac0a2488b6f94d", size = 3265431, upload-time = "2026-03-02T15:58:59.096Z" }, - { url = "https://files.pythonhosted.org/packages/8b/19/780138dacfe3f5024f4cf96e4005e91edf6653d53d3673be4844578faf1d/sqlalchemy-2.0.48-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e5e088bf43f6ee6fec7dbf1ef7ff7774a616c236b5c0cb3e00662dd71a56b571", size = 3287646, upload-time = "2026-03-02T15:52:31.569Z" }, - { url = "https://files.pythonhosted.org/packages/40/fd/f32ced124f01a23151f4777e4c705f3a470adc7bd241d9f36a7c941a33bf/sqlalchemy-2.0.48-cp311-cp311-win32.whl", hash = "sha256:9c7d0a77e36b5f4b01ca398482230ab792061d243d715299b44a0b55c89fe617", size = 2116956, upload-time = "2026-03-02T15:46:54.535Z" }, - { url = "https://files.pythonhosted.org/packages/58/d5/dd767277f6feef12d05651538f280277e661698f617fa4d086cce6055416/sqlalchemy-2.0.48-cp311-cp311-win_amd64.whl", hash = "sha256:583849c743e0e3c9bb7446f5b5addeacedc168d657a69b418063dfdb2d90081c", size = 2141627, upload-time = "2026-03-02T15:46:55.849Z" }, - { url = "https://files.pythonhosted.org/packages/ef/91/a42ae716f8925e9659df2da21ba941f158686856107a61cc97a95e7647a3/sqlalchemy-2.0.48-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:348174f228b99f33ca1f773e85510e08927620caa59ffe7803b37170df30332b", size = 2155737, upload-time = "2026-03-02T15:49:13.207Z" }, - { url = "https://files.pythonhosted.org/packages/b9/52/f75f516a1f3888f027c1cfb5d22d4376f4b46236f2e8669dcb0cddc60275/sqlalchemy-2.0.48-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53667b5f668991e279d21f94ccfa6e45b4e3f4500e7591ae59a8012d0f010dcb", size = 3337020, upload-time = "2026-03-02T15:50:34.547Z" }, - { url = "https://files.pythonhosted.org/packages/37/9a/0c28b6371e0cdcb14f8f1930778cb3123acfcbd2c95bb9cf6b4a2ba0cce3/sqlalchemy-2.0.48-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34634e196f620c7a61d18d5cf7dc841ca6daa7961aed75d532b7e58b309ac894", size = 3349983, upload-time = "2026-03-02T15:53:25.542Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/0aee8f3ff20b1dcbceb46ca2d87fcc3d48b407925a383ff668218509d132/sqlalchemy-2.0.48-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:546572a1793cc35857a2ffa1fe0e58571af1779bcc1ffa7c9fb0839885ed69a9", size = 3279690, upload-time = "2026-03-02T15:50:36.277Z" }, - { url = "https://files.pythonhosted.org/packages/ce/8c/a957bc91293b49181350bfd55e6dfc6e30b7f7d83dc6792d72043274a390/sqlalchemy-2.0.48-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:07edba08061bc277bfdc772dd2a1a43978f5a45994dd3ede26391b405c15221e", size = 3314738, upload-time = "2026-03-02T15:53:27.519Z" }, - { url = "https://files.pythonhosted.org/packages/4b/44/1d257d9f9556661e7bdc83667cc414ba210acfc110c82938cb3611eea58f/sqlalchemy-2.0.48-cp312-cp312-win32.whl", hash = "sha256:908a3fa6908716f803b86896a09a2c4dde5f5ce2bb07aacc71ffebb57986ce99", size = 2115546, upload-time = "2026-03-02T15:54:31.591Z" }, - { url = "https://files.pythonhosted.org/packages/f2/af/c3c7e1f3a2b383155a16454df62ae8c62a30dd238e42e68c24cebebbfae6/sqlalchemy-2.0.48-cp312-cp312-win_amd64.whl", hash = "sha256:68549c403f79a8e25984376480959975212a670405e3913830614432b5daa07a", size = 2142484, upload-time = "2026-03-02T15:54:34.072Z" }, - { url = "https://files.pythonhosted.org/packages/d1/c6/569dc8bf3cd375abc5907e82235923e986799f301cd79a903f784b996fca/sqlalchemy-2.0.48-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e3070c03701037aa418b55d36532ecb8f8446ed0135acb71c678dbdf12f5b6e4", size = 2152599, upload-time = "2026-03-02T15:49:14.41Z" }, - { url = "https://files.pythonhosted.org/packages/6d/ff/f4e04a4bd5a24304f38cb0d4aa2ad4c0fb34999f8b884c656535e1b2b74c/sqlalchemy-2.0.48-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2645b7d8a738763b664a12a1542c89c940daa55196e8d73e55b169cc5c99f65f", size = 3278825, upload-time = "2026-03-02T15:50:38.269Z" }, - { url = "https://files.pythonhosted.org/packages/fe/88/cb59509e4668d8001818d7355d9995be90c321313078c912420603a7cb95/sqlalchemy-2.0.48-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b19151e76620a412c2ac1c6f977ab1b9fa7ad43140178345136456d5265b32ed", size = 3295200, upload-time = "2026-03-02T15:53:29.366Z" }, - { url = "https://files.pythonhosted.org/packages/87/dc/1609a4442aefd750ea2f32629559394ec92e89ac1d621a7f462b70f736ff/sqlalchemy-2.0.48-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5b193a7e29fd9fa56e502920dca47dffe60f97c863494946bd698c6058a55658", size = 3226876, upload-time = "2026-03-02T15:50:39.802Z" }, - { url = "https://files.pythonhosted.org/packages/37/c3/6ae2ab5ea2fa989fbac4e674de01224b7a9d744becaf59bb967d62e99bed/sqlalchemy-2.0.48-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:36ac4ddc3d33e852da9cb00ffb08cea62ca05c39711dc67062ca2bb1fae35fd8", size = 3265045, upload-time = "2026-03-02T15:53:31.421Z" }, - { url = "https://files.pythonhosted.org/packages/6f/82/ea4665d1bb98c50c19666e672f21b81356bd6077c4574e3d2bbb84541f53/sqlalchemy-2.0.48-cp313-cp313-win32.whl", hash = "sha256:389b984139278f97757ea9b08993e7b9d1142912e046ab7d82b3fbaeb0209131", size = 2113700, upload-time = "2026-03-02T15:54:35.825Z" }, - { url = "https://files.pythonhosted.org/packages/b7/2b/b9040bec58c58225f073f5b0c1870defe1940835549dafec680cbd58c3c3/sqlalchemy-2.0.48-cp313-cp313-win_amd64.whl", hash = "sha256:d612c976cbc2d17edfcc4c006874b764e85e990c29ce9bd411f926bbfb02b9a2", size = 2139487, upload-time = "2026-03-02T15:54:37.079Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f4/7b17bd50244b78a49d22cc63c969d71dc4de54567dc152a9b46f6fae40ce/sqlalchemy-2.0.48-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69f5bc24904d3bc3640961cddd2523e361257ef68585d6e364166dfbe8c78fae", size = 3558851, upload-time = "2026-03-02T15:57:48.607Z" }, - { url = "https://files.pythonhosted.org/packages/20/0d/213668e9aca61d370f7d2a6449ea4ec699747fac67d4bda1bb3d129025be/sqlalchemy-2.0.48-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd08b90d211c086181caed76931ecfa2bdfc83eea3cfccdb0f82abc6c4b876cb", size = 3525525, upload-time = "2026-03-02T16:04:38.058Z" }, - { url = "https://files.pythonhosted.org/packages/85/d7/a84edf412979e7d59c69b89a5871f90a49228360594680e667cb2c46a828/sqlalchemy-2.0.48-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1ccd42229aaac2df431562117ac7e667d702e8e44afdb6cf0e50fa3f18160f0b", size = 3466611, upload-time = "2026-03-02T15:57:50.759Z" }, - { url = "https://files.pythonhosted.org/packages/86/55/42404ce5770f6be26a2b0607e7866c31b9a4176c819e9a7a5e0a055770be/sqlalchemy-2.0.48-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0dcbc588cd5b725162c076eb9119342f6579c7f7f55057bb7e3c6ff27e13121", size = 3475812, upload-time = "2026-03-02T16:04:40.092Z" }, - { url = "https://files.pythonhosted.org/packages/ae/ae/29b87775fadc43e627cf582fe3bda4d02e300f6b8f2747c764950d13784c/sqlalchemy-2.0.48-cp313-cp313t-win32.whl", hash = "sha256:9764014ef5e58aab76220c5664abb5d47d5bc858d9debf821e55cfdd0f128485", size = 2141335, upload-time = "2026-03-02T15:52:51.518Z" }, - { url = "https://files.pythonhosted.org/packages/91/44/f39d063c90f2443e5b46ec4819abd3d8de653893aae92df42a5c4f5843de/sqlalchemy-2.0.48-cp313-cp313t-win_amd64.whl", hash = "sha256:e2f35b4cccd9ed286ad62e0a3c3ac21e06c02abc60e20aa51a3e305a30f5fa79", size = 2173095, upload-time = "2026-03-02T15:52:52.79Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b3/f437eaa1cf028bb3c927172c7272366393e73ccd104dcf5b6963f4ab5318/sqlalchemy-2.0.48-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e2d0d88686e3d35a76f3e15a34e8c12d73fc94c1dea1cd55782e695cc14086dd", size = 2154401, upload-time = "2026-03-02T15:49:17.24Z" }, - { url = "https://files.pythonhosted.org/packages/6c/1c/b3abdf0f402aa3f60f0df6ea53d92a162b458fca2321d8f1f00278506402/sqlalchemy-2.0.48-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49b7bddc1eebf011ea5ab722fdbe67a401caa34a350d278cc7733c0e88fecb1f", size = 3274528, upload-time = "2026-03-02T15:50:41.489Z" }, - { url = "https://files.pythonhosted.org/packages/f2/5e/327428a034407651a048f5e624361adf3f9fbac9d0fa98e981e9c6ff2f5e/sqlalchemy-2.0.48-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:426c5ca86415d9b8945c7073597e10de9644802e2ff502b8e1f11a7a2642856b", size = 3279523, upload-time = "2026-03-02T15:53:32.962Z" }, - { url = "https://files.pythonhosted.org/packages/2a/ca/ece73c81a918add0965b76b868b7b5359e068380b90ef1656ee995940c02/sqlalchemy-2.0.48-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:288937433bd44e3990e7da2402fabc44a3c6c25d3704da066b85b89a85474ae0", size = 3224312, upload-time = "2026-03-02T15:50:42.996Z" }, - { url = "https://files.pythonhosted.org/packages/88/11/fbaf1ae91fa4ee43f4fe79661cead6358644824419c26adb004941bdce7c/sqlalchemy-2.0.48-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8183dc57ae7d9edc1346e007e840a9f3d6aa7b7f165203a99e16f447150140d2", size = 3246304, upload-time = "2026-03-02T15:53:34.937Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5fb0deb13930b4f2f698c5541ae076c18981173e27dd00376dbaea7a9c82/sqlalchemy-2.0.48-cp314-cp314-win32.whl", hash = "sha256:1182437cb2d97988cfea04cf6cdc0b0bb9c74f4d56ec3d08b81e23d621a28cc6", size = 2116565, upload-time = "2026-03-02T15:54:38.321Z" }, - { url = "https://files.pythonhosted.org/packages/95/7e/e83615cb63f80047f18e61e31e8e32257d39458426c23006deeaf48f463b/sqlalchemy-2.0.48-cp314-cp314-win_amd64.whl", hash = "sha256:144921da96c08feb9e2b052c5c5c1d0d151a292c6135623c6b2c041f2a45f9e0", size = 2142205, upload-time = "2026-03-02T15:54:39.831Z" }, - { url = "https://files.pythonhosted.org/packages/83/e3/69d8711b3f2c5135e9cde5f063bc1605860f0b2c53086d40c04017eb1f77/sqlalchemy-2.0.48-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5aee45fd2c6c0f2b9cdddf48c48535e7471e42d6fb81adfde801da0bd5b93241", size = 3563519, upload-time = "2026-03-02T15:57:52.387Z" }, - { url = "https://files.pythonhosted.org/packages/f8/4f/a7cce98facca73c149ea4578981594aaa5fd841e956834931de503359336/sqlalchemy-2.0.48-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7cddca31edf8b0653090cbb54562ca027c421c58ddde2c0685f49ff56a1690e0", size = 3528611, upload-time = "2026-03-02T16:04:42.097Z" }, - { url = "https://files.pythonhosted.org/packages/cd/7d/5936c7a03a0b0cb0fa0cc425998821c6029756b0855a8f7ee70fba1de955/sqlalchemy-2.0.48-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7a936f1bb23d370b7c8cc079d5fce4c7d18da87a33c6744e51a93b0f9e97e9b3", size = 3472326, upload-time = "2026-03-02T15:57:54.423Z" }, - { url = "https://files.pythonhosted.org/packages/f4/33/cea7dfc31b52904efe3dcdc169eb4514078887dff1f5ae28a7f4c5d54b3c/sqlalchemy-2.0.48-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e004aa9248e8cb0a5f9b96d003ca7c1c0a5da8decd1066e7b53f59eb8ce7c62b", size = 3478453, upload-time = "2026-03-02T16:04:44.584Z" }, - { url = "https://files.pythonhosted.org/packages/c8/95/32107c4d13be077a9cae61e9ae49966a35dc4bf442a8852dd871db31f62e/sqlalchemy-2.0.48-cp314-cp314t-win32.whl", hash = "sha256:b8438ec5594980d405251451c5b7ea9aa58dda38eb7ac35fb7e4c696712ee24f", size = 2147209, upload-time = "2026-03-02T15:52:54.274Z" }, - { url = "https://files.pythonhosted.org/packages/d2/d7/1e073da7a4bc645eb83c76067284a0374e643bc4be57f14cc6414656f92c/sqlalchemy-2.0.48-cp314-cp314t-win_amd64.whl", hash = "sha256:d854b3970067297f3a7fbd7a4683587134aa9b3877ee15aa29eea478dc68f933", size = 2182198, upload-time = "2026-03-02T15:52:55.606Z" }, - { url = "https://files.pythonhosted.org/packages/46/2c/9664130905f03db57961b8980b05cab624afd114bf2be2576628a9f22da4/sqlalchemy-2.0.48-py3-none-any.whl", hash = "sha256:a66fe406437dd65cacd96a72689a3aaaecaebbcd62d81c5ac1c0fdbeac835096", size = 1940202, upload-time = "2026-03-02T15:52:43.285Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/09/45/461788f35e0364a8da7bda51a1fe1b09762d0c32f12f63727998d85a873b/sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f", size = 9898221, upload-time = "2026-04-03T16:38:11.704Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/33/bf28f618c0a9597d14e0b9ee7d1e0622faff738d44fe986ee287cdf1b8d0/sqlalchemy-2.0.49-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:233088b4b99ebcbc5258c755a097aa52fbf90727a03a5a80781c4b9c54347a2e", size = 2156356, upload-time = "2026-04-03T16:53:09.914Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a7/5f476227576cb8644650eff68cc35fa837d3802b997465c96b8340ced1e2/sqlalchemy-2.0.49-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57ca426a48eb2c682dae8204cd89ea8ab7031e2675120a47924fabc7caacbc2a", size = 3276486, upload-time = "2026-04-03T17:07:46.9Z" }, + { url = "https://files.pythonhosted.org/packages/2e/84/efc7c0bf3a1c5eef81d397f6fddac855becdbb11cb38ff957888603014a7/sqlalchemy-2.0.49-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:685e93e9c8f399b0c96a624799820176312f5ceef958c0f88215af4013d29066", size = 3281479, upload-time = "2026-04-03T17:12:32.226Z" }, + { url = "https://files.pythonhosted.org/packages/91/68/bb406fa4257099c67bd75f3f2261b129c63204b9155de0d450b37f004698/sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e0400fa22f79acc334d9a6b185dc00a44a8e6578aa7e12d0ddcd8434152b187", size = 3226269, upload-time = "2026-04-03T17:07:48.678Z" }, + { url = "https://files.pythonhosted.org/packages/67/84/acb56c00cca9f251f437cb49e718e14f7687505749ea9255d7bd8158a6df/sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a05977bffe9bffd2229f477fa75eabe3192b1b05f408961d1bebff8d1cd4d401", size = 3248260, upload-time = "2026-04-03T17:12:34.381Z" }, + { url = "https://files.pythonhosted.org/packages/56/19/6a20ea25606d1efd7bd1862149bb2a22d1451c3f851d23d887969201633f/sqlalchemy-2.0.49-cp314-cp314-win32.whl", hash = "sha256:0f2fa354ba106eafff2c14b0cc51f22801d1e8b2e4149342023bd6f0955de5f5", size = 2118463, upload-time = "2026-04-03T17:05:47.093Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4f/8297e4ed88e80baa1f5aa3c484a0ee29ef3c69c7582f206c916973b75057/sqlalchemy-2.0.49-cp314-cp314-win_amd64.whl", hash = "sha256:77641d299179c37b89cf2343ca9972c88bb6eef0d5fc504a2f86afd15cd5adf5", size = 2144204, upload-time = "2026-04-03T17:05:48.694Z" }, + { url = "https://files.pythonhosted.org/packages/1f/33/95e7216df810c706e0cd3655a778604bbd319ed4f43333127d465a46862d/sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c1dc3368794d522f43914e03312202523cc89692f5389c32bea0233924f8d977", size = 3565474, upload-time = "2026-04-03T16:58:35.128Z" }, + { url = "https://files.pythonhosted.org/packages/0c/a4/ed7b18d8ccf7f954a83af6bb73866f5bc6f5636f44c7731fbb741f72cc4f/sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c821c47ecfe05cc32140dcf8dc6fd5d21971c86dbd56eabfe5ba07a64910c01", size = 3530567, upload-time = "2026-04-03T17:06:04.587Z" }, + { url = "https://files.pythonhosted.org/packages/73/a3/20faa869c7e21a827c4a2a42b41353a54b0f9f5e96df5087629c306df71e/sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9c04bff9a5335eb95c6ecf1c117576a0aa560def274876fd156cfe5510fccc61", size = 3474282, upload-time = "2026-04-03T16:58:37.131Z" }, + { url = "https://files.pythonhosted.org/packages/b7/50/276b9a007aa0764304ad467eceb70b04822dc32092492ee5f322d559a4dc/sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7f605a456948c35260e7b2a39f8952a26f077fd25653c37740ed186b90aaa68a", size = 3480406, upload-time = "2026-04-03T17:06:07.176Z" }, + { url = "https://files.pythonhosted.org/packages/e5/c3/c80fcdb41905a2df650c2a3e0337198b6848876e63d66fe9188ef9003d24/sqlalchemy-2.0.49-cp314-cp314t-win32.whl", hash = "sha256:6270d717b11c5476b0cbb21eedc8d4dbb7d1a956fd6c15a23e96f197a6193158", size = 2149151, upload-time = "2026-04-03T17:02:07.281Z" }, + { url = "https://files.pythonhosted.org/packages/05/52/9f1a62feab6ed368aff068524ff414f26a6daebc7361861035ae00b05530/sqlalchemy-2.0.49-cp314-cp314t-win_amd64.whl", hash = "sha256:275424295f4256fd301744b8f335cff367825d270f155d522b30c7bf49903ee7", size = 2184178, upload-time = "2026-04-03T17:02:08.623Z" }, + { url = "https://files.pythonhosted.org/packages/e5/30/8519fdde58a7bdf155b714359791ad1dc018b47d60269d5d160d311fdc36/sqlalchemy-2.0.49-py3-none-any.whl", hash = "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0", size = 1942158, upload-time = "2026-04-03T16:53:44.135Z" }, ] [[package]] name = "sqlmodel" -version = "0.0.37" +version = "0.0.38" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "sqlalchemy" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/26/1d2faa0fd5a765267f49751de533adac6b9ff9366c7c6e7692df4f32230f/sqlmodel-0.0.37.tar.gz", hash = "sha256:d2c19327175794faf50b1ee31cc966764f55b1dedefc046450bc5741a3d68352", size = 85527, upload-time = "2026-02-21T16:39:47.038Z" } +sdist = { url = "https://files.pythonhosted.org/packages/64/0d/26ec1329960ea9430131fe63f63a95ea4cb8971d49c891ff7e1f3255421c/sqlmodel-0.0.38.tar.gz", hash = "sha256:d583ec237b14103809f74e8630032bc40ab68cd6b754a610f0813c56911a547b", size = 86710, upload-time = "2026-04-02T21:03:55.571Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/e1/7c8d18e737433f3b5bbe27b56a9072a9fcb36342b48f1bef34b6da1d61f2/sqlmodel-0.0.37-py3-none-any.whl", hash = "sha256:2137a4045ef3fd66a917a7717ada959a1ceb3630d95e1f6aaab39dd2c0aef278", size = 27224, upload-time = "2026-02-21T16:39:47.781Z" }, + { url = "https://files.pythonhosted.org/packages/72/c7/10c60af0607ab6fa136264f7f39d205932218516226d38585324ffda705d/sqlmodel-0.0.38-py3-none-any.whl", hash = "sha256:84e3fa990a77395461ded72a6c73173438ce8449d5c1c4d97fbff1b1df692649", size = 27294, upload-time = "2026-04-02T21:03:56.406Z" }, ] [[package]] name = "starlette" -version = "0.46.2" +version = "1.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" } +sdist = { url = "https://files.pythonhosted.org/packages/81/69/17425771797c36cded50b7fe44e850315d039f28b15901ab44839e70b593/starlette-1.0.0.tar.gz", hash = "sha256:6a4beaf1f81bb472fd19ea9b918b50dc3a77a6f2e190a12954b25e6ed5eea149", size = 2655289, upload-time = "2026-03-22T18:29:46.779Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, + { url = "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl", hash = "sha256:d3ec55e0bb321692d275455ddfd3df75fff145d009685eb40dc91fc66b03d38b", size = 72651, upload-time = "2026-03-22T18:29:45.111Z" }, ] [[package]] name = "tenacity" -version = "8.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a3/4d/6a19536c50b849338fcbe9290d562b52cbdcf30d8963d3588a68a4107df1/tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78", size = 47309, upload-time = "2024-07-05T07:25:31.836Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687", size = 28165, upload-time = "2024-07-05T07:25:29.591Z" }, -] - -[[package]] -name = "tomli" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" }, - { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" }, - { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" }, - { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" }, - { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" }, - { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" }, - { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" }, - { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" }, - { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" }, - { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" }, - { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" }, - { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" }, - { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" }, - { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" }, - { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" }, - { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" }, - { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" }, - { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" }, - { url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" }, - { url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" }, - { url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" }, - { url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" }, - { url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" }, - { url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" }, - { url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" }, - { url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" }, - { url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" }, - { url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" }, - { url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" }, - { url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" }, - { url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" }, - { url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" }, - { url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" }, - { url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" }, - { url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" }, - { url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" }, - { url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" }, - { url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" }, - { url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" }, - { url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" }, - { url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" }, - { url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" }, - { url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" }, - { url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" }, - { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, +version = "9.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" }, +] + +[[package]] +name = "ty" +version = "0.0.29" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/d5/853561de49fae38c519e905b2d8da9c531219608f1fccc47a0fc2c896980/ty-0.0.29.tar.gz", hash = "sha256:e7936cca2f691eeda631876c92809688dbbab68687c3473f526cd83b6a9228d8", size = 5469221, upload-time = "2026-04-05T15:01:21.328Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/b7/911f9962115acfa24e3b2ec9d4992dd994c38e8769e1b1d7680bb4d28a51/ty-0.0.29-py3-none-linux_armv6l.whl", hash = "sha256:b8a40955f7660d3eaceb0d964affc81b790c0765e7052921a5f861ff8a471c30", size = 10568206, upload-time = "2026-04-05T15:01:19.165Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c3/fcae2167d4c77a97269f92f11d1b43b03617f81de1283d5d05b43432110c/ty-0.0.29-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6b6849adae15b00bbe2d3c5b078967dcb62eba37d38936b8eeb4c81a82d2e3b8", size = 10442530, upload-time = "2026-04-05T15:01:28.471Z" }, + { url = "https://files.pythonhosted.org/packages/97/33/5a6bfa240cfcb9c36046ae2459fa9ea23238d20130d8656ff5ac4d6c012a/ty-0.0.29-py3-none-macosx_11_0_arm64.whl", hash = "sha256:dcdd9b17209788152f7b7ea815eda07989152325052fe690013537cc7904ce49", size = 9915735, upload-time = "2026-04-05T15:01:10.365Z" }, + { url = "https://files.pythonhosted.org/packages/b3/1e/318f45fae232118e81a6306c30f50de42c509c412128d5bd231eab699ffb/ty-0.0.29-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d8ed4789bae78ffaf94462c0d25589a734cab0366b86f2bbcb1bb90e1a7a169", size = 10419748, upload-time = "2026-04-05T15:01:32.375Z" }, + { url = "https://files.pythonhosted.org/packages/a9/a8/5687872e2ab5a0f7dd4fd8456eac31e9381ad4dc74961f6f29965ad4dd91/ty-0.0.29-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91ec374b8565e0ad0900011c24641ebbef2da51adbd4fb69ff3280c8a7eceb02", size = 10394738, upload-time = "2026-04-05T15:01:06.473Z" }, + { url = "https://files.pythonhosted.org/packages/de/68/015d118097eeb95e6a44c4abce4c0a28b7b9dfb3085b7f0ee48e4f099633/ty-0.0.29-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:298a8d5faa2502d3810bbbb47a030b9455495b9921594206043c785dd61548cf", size = 10910613, upload-time = "2026-04-05T15:01:17.17Z" }, + { url = "https://files.pythonhosted.org/packages/1c/01/47ce3c6c53e0670eadbe80756b167bf80ed6681d1ba57cfde2e8065a13d1/ty-0.0.29-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c8fba1a3524c6109d1e020d92301c79d41bf442fa8d335b9fa366239339cb70", size = 11475750, upload-time = "2026-04-05T15:01:30.461Z" }, + { url = "https://files.pythonhosted.org/packages/c4/cf/e361845b1081c9264ad5b7c963231bab03f2666865a9f2a115c4233f2137/ty-0.0.29-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c48adf88a70d264128c39ee922ed14a947817fced1e93c08c1a89c9244edcde", size = 11190055, upload-time = "2026-04-05T15:01:12.369Z" }, + { url = "https://files.pythonhosted.org/packages/79/12/0fb0857e9a62cb11586e9a712103877bbf717f5fb570d16634408cfdefee/ty-0.0.29-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ce0a7a0e96bc7b42518cd3a1a6a6298ef64ff40ca4614355c1aa807059b5c6f", size = 11020539, upload-time = "2026-04-05T15:01:37.022Z" }, + { url = "https://files.pythonhosted.org/packages/20/36/5a26753802083f80cd125db6c4348ad42b3c982ec36e718e0bf4c18f75e5/ty-0.0.29-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a6ac86a05b4a3731d45365ab97780acc7b8146fa62fccb3cbe94fe6546c67a97", size = 10396399, upload-time = "2026-04-05T15:01:26.167Z" }, + { url = "https://files.pythonhosted.org/packages/00/e6/b4e75b5752239ab3ab400f19faef4dbef81d05aab5d3419fda0c062a3765/ty-0.0.29-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6bbbf53141af0f3150bf288d716263f1a3550054e4b3551ca866d38192ba9891", size = 10421461, upload-time = "2026-04-05T15:01:08.367Z" }, + { url = "https://files.pythonhosted.org/packages/c0/21/1084b5b609f9abed62070ec0b31c283a403832a6310c8bbc208bd45ee1e6/ty-0.0.29-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1c9e06b770c1d0ff5efc51e34312390db31d53fcf3088163f413030b42b74f84", size = 10599187, upload-time = "2026-04-05T15:01:23.52Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a1/ce19a2ca717bbcc1ee11378aba52ef70b6ce5b87245162a729d9fdc2360f/ty-0.0.29-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0307fe37e3f000ef1a4ae230bbaf511508a78d24a5e51b40902a21b09d5e6037", size = 11121198, upload-time = "2026-04-05T15:01:15.22Z" }, + { url = "https://files.pythonhosted.org/packages/6b/6b/f1430b279af704321566ce7ec2725d3d8258c2f815ebd93e474c64cd4543/ty-0.0.29-py3-none-win32.whl", hash = "sha256:7a2a898217960a825f8bc0087e1fdbaf379606175e98f9807187221d53a4a8ed", size = 9995331, upload-time = "2026-04-05T15:01:01.32Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ef/3ef01c17785ff9a69378465c7d0faccd48a07b163554db0995e5d65a5a23/ty-0.0.29-py3-none-win_amd64.whl", hash = "sha256:fc1294200226b91615acbf34e0a9ad81caf98c081e9c6a912a31b0a7b603bc3f", size = 11023644, upload-time = "2026-04-05T15:01:04.432Z" }, + { url = "https://files.pythonhosted.org/packages/2c/55/87280a994d6a2d2647c65e12abbc997ed49835794366153c04c4d9304d76/ty-0.0.29-py3-none-win_arm64.whl", hash = "sha256:f9794bbd1bb3ce13f78c191d0c89ae4c63f52c12b6daa0c6fe220b90d019d12c", size = 10428165, upload-time = "2026-04-05T15:01:34.665Z" }, ] [[package]] @@ -2992,11 +1566,11 @@ wheels = [ [[package]] name = "types-docutils" -version = "0.22.3.20260223" +version = "0.22.3.20260322" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/80/33/92c0129283363e3b3ba270bf6a2b7d077d949d2f90afc4abaf6e73578563/types_docutils-0.22.3.20260223.tar.gz", hash = "sha256:e90e868da82df615ea2217cf36dff31f09660daa15fc0f956af53f89c1364501", size = 57230, upload-time = "2026-02-23T04:11:21.806Z" } +sdist = { url = "https://files.pythonhosted.org/packages/44/bb/243a87fc1605a4a94c2c343d6dbddbf0d7ef7c0b9550f360b8cda8e82c39/types_docutils-0.22.3.20260322.tar.gz", hash = "sha256:e2450bb997283c3141ec5db3e436b91f0aa26efe35eb9165178ca976ccb4930b", size = 57311, upload-time = "2026-03-22T04:08:44.064Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/c7/a4ae6a75d5b07d63089d5c04d450a0de4a5d48ffcb84b95659b22d3885fe/types_docutils-0.22.3.20260223-py3-none-any.whl", hash = "sha256:cc2d6b7560a28e351903db0989091474aa619ad287843a018324baee9c4d9a8f", size = 91969, upload-time = "2026-02-23T04:11:20.966Z" }, + { url = "https://files.pythonhosted.org/packages/c6/4a/22c090cd4615a16917dff817cbe7c5956da376c961e024c241cd962d2c3d/types_docutils-0.22.3.20260322-py3-none-any.whl", hash = "sha256:681d4510ce9b80a0c6a593f0f9843d81f8caa786db7b39ba04d9fd5480ac4442", size = 91978, upload-time = "2026-03-22T04:08:43.117Z" }, ] [[package]] @@ -3022,11 +1596,11 @@ wheels = [ [[package]] name = "tzdata" -version = "2025.3" +version = "2026.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/f5/cd531b2d15a671a40c0f66cf06bc3570a12cd56eef98960068ebbad1bf5a/tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98", size = 197639, upload-time = "2026-04-03T11:25:22.002Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, + { url = "https://files.pythonhosted.org/packages/b0/70/d460bd685a170790ec89317e9bd33047988e4bce507b831f5db771e142de/tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9", size = 348952, upload-time = "2026-04-03T11:25:20.313Z" }, ] [[package]] @@ -3040,16 +1614,15 @@ wheels = [ [[package]] name = "uvicorn" -version = "0.41.0" +version = "0.44.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/32/ce/eeb58ae4ac36fe09e3842eb02e0eb676bf2c53ae062b98f1b2531673efdd/uvicorn-0.41.0.tar.gz", hash = "sha256:09d11cf7008da33113824ee5a1c6422d89fbc2ff476540d69a34c87fab8b571a", size = 82633, upload-time = "2026-02-16T23:07:24.1Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/da/6eee1ff8b6cbeed47eeb5229749168e81eb4b7b999a1a15a7176e51410c9/uvicorn-0.44.0.tar.gz", hash = "sha256:6c942071b68f07e178264b9152f1f16dfac5da85880c4ce06366a96d70d4f31e", size = 86947, upload-time = "2026-04-06T09:23:22.826Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/e4/d04a086285c20886c0daad0e026f250869201013d18f81d9ff5eada73a88/uvicorn-0.41.0-py3-none-any.whl", hash = "sha256:29e35b1d2c36a04b9e180d4007ede3bcb32a85fbdfd6c6aeb3f26839de088187", size = 68783, upload-time = "2026-02-16T23:07:22.357Z" }, + { url = "https://files.pythonhosted.org/packages/b7/23/a5bbd9600dd607411fa644c06ff4951bec3a4d82c4b852374024359c19c0/uvicorn-0.44.0-py3-none-any.whl", hash = "sha256:ce937c99a2cc70279556967274414c087888e8cec9f9c94644dfca11bd3ced89", size = 69425, upload-time = "2026-04-06T09:23:21.524Z" }, ] [package.optional-dependencies] @@ -3069,30 +1642,6 @@ version = "0.22.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335, upload-time = "2025-10-16T22:16:11.43Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903, upload-time = "2025-10-16T22:16:12.979Z" }, - { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499, upload-time = "2025-10-16T22:16:14.451Z" }, - { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133, upload-time = "2025-10-16T22:16:16.272Z" }, - { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681, upload-time = "2025-10-16T22:16:18.07Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261, upload-time = "2025-10-16T22:16:19.596Z" }, - { url = "https://files.pythonhosted.org/packages/c7/d5/69900f7883235562f1f50d8184bb7dd84a2fb61e9ec63f3782546fdbd057/uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c60ebcd36f7b240b30788554b6f0782454826a0ed765d8430652621b5de674b9", size = 1352420, upload-time = "2025-10-16T22:16:21.187Z" }, - { url = "https://files.pythonhosted.org/packages/a8/73/c4e271b3bce59724e291465cc936c37758886a4868787da0278b3b56b905/uvloop-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b7f102bf3cb1995cfeaee9321105e8f5da76fdb104cdad8986f85461a1b7b77", size = 748677, upload-time = "2025-10-16T22:16:22.558Z" }, - { url = "https://files.pythonhosted.org/packages/86/94/9fb7fad2f824d25f8ecac0d70b94d0d48107ad5ece03769a9c543444f78a/uvloop-0.22.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53c85520781d84a4b8b230e24a5af5b0778efdb39142b424990ff1ef7c48ba21", size = 3753819, upload-time = "2025-10-16T22:16:23.903Z" }, - { url = "https://files.pythonhosted.org/packages/74/4f/256aca690709e9b008b7108bc85fba619a2bc37c6d80743d18abad16ee09/uvloop-0.22.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56a2d1fae65fd82197cb8c53c367310b3eabe1bbb9fb5a04d28e3e3520e4f702", size = 3804529, upload-time = "2025-10-16T22:16:25.246Z" }, - { url = "https://files.pythonhosted.org/packages/7f/74/03c05ae4737e871923d21a76fe28b6aad57f5c03b6e6bfcfa5ad616013e4/uvloop-0.22.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40631b049d5972c6755b06d0bfe8233b1bd9a8a6392d9d1c45c10b6f9e9b2733", size = 3621267, upload-time = "2025-10-16T22:16:26.819Z" }, - { url = "https://files.pythonhosted.org/packages/75/be/f8e590fe61d18b4a92070905497aec4c0e64ae1761498cad09023f3f4b3e/uvloop-0.22.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:535cc37b3a04f6cd2c1ef65fa1d370c9a35b6695df735fcff5427323f2cd5473", size = 3723105, upload-time = "2025-10-16T22:16:28.252Z" }, - { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" }, - { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" }, - { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" }, - { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" }, - { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" }, - { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" }, - { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" }, - { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" }, - { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" }, - { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" }, - { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" }, { url = "https://files.pythonhosted.org/packages/90/cd/b62bdeaa429758aee8de8b00ac0dd26593a9de93d302bff3d21439e9791d/uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142", size = 1362067, upload-time = "2025-10-16T22:16:44.503Z" }, { url = "https://files.pythonhosted.org/packages/0d/f8/a132124dfda0777e489ca86732e85e69afcd1ff7686647000050ba670689/uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74", size = 752423, upload-time = "2025-10-16T22:16:45.968Z" }, { url = "https://files.pythonhosted.org/packages/a3/94/94af78c156f88da4b3a733773ad5ba0b164393e357cc4bd0ab2e2677a7d6/uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35", size = 4272437, upload-time = "2025-10-16T22:16:47.451Z" }, @@ -3116,67 +1665,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318, upload-time = "2025-10-14T15:04:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478, upload-time = "2025-10-14T15:04:20.297Z" }, - { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894, upload-time = "2025-10-14T15:04:21.527Z" }, - { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065, upload-time = "2025-10-14T15:04:22.795Z" }, - { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377, upload-time = "2025-10-14T15:04:24.138Z" }, - { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837, upload-time = "2025-10-14T15:04:25.057Z" }, - { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456, upload-time = "2025-10-14T15:04:26.497Z" }, - { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614, upload-time = "2025-10-14T15:04:27.539Z" }, - { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690, upload-time = "2025-10-14T15:04:28.495Z" }, - { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459, upload-time = "2025-10-14T15:04:29.491Z" }, - { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663, upload-time = "2025-10-14T15:04:30.435Z" }, - { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453, upload-time = "2025-10-14T15:04:31.53Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f8/2c5f479fb531ce2f0564eda479faecf253d886b1ab3630a39b7bf7362d46/watchfiles-1.1.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f57b396167a2565a4e8b5e56a5a1c537571733992b226f4f1197d79e94cf0ae5", size = 406529, upload-time = "2025-10-14T15:04:32.899Z" }, - { url = "https://files.pythonhosted.org/packages/fe/cd/f515660b1f32f65df671ddf6f85bfaca621aee177712874dc30a97397977/watchfiles-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:421e29339983e1bebc281fab40d812742268ad057db4aee8c4d2bce0af43b741", size = 394384, upload-time = "2025-10-14T15:04:33.761Z" }, - { url = "https://files.pythonhosted.org/packages/7b/c3/28b7dc99733eab43fca2d10f55c86e03bd6ab11ca31b802abac26b23d161/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e43d39a741e972bab5d8100b5cdacf69db64e34eb19b6e9af162bccf63c5cc6", size = 448789, upload-time = "2025-10-14T15:04:34.679Z" }, - { url = "https://files.pythonhosted.org/packages/4a/24/33e71113b320030011c8e4316ccca04194bf0cbbaeee207f00cbc7d6b9f5/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f537afb3276d12814082a2e9b242bdcf416c2e8fd9f799a737990a1dbe906e5b", size = 460521, upload-time = "2025-10-14T15:04:35.963Z" }, - { url = "https://files.pythonhosted.org/packages/f4/c3/3c9a55f255aa57b91579ae9e98c88704955fa9dac3e5614fb378291155df/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2cd9e04277e756a2e2d2543d65d1e2166d6fd4c9b183f8808634fda23f17b14", size = 488722, upload-time = "2025-10-14T15:04:37.091Z" }, - { url = "https://files.pythonhosted.org/packages/49/36/506447b73eb46c120169dc1717fe2eff07c234bb3232a7200b5f5bd816e9/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f3f58818dc0b07f7d9aa7fe9eb1037aecb9700e63e1f6acfed13e9fef648f5d", size = 596088, upload-time = "2025-10-14T15:04:38.39Z" }, - { url = "https://files.pythonhosted.org/packages/82/ab/5f39e752a9838ec4d52e9b87c1e80f1ee3ccdbe92e183c15b6577ab9de16/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb9f66367023ae783551042d31b1d7fd422e8289eedd91f26754a66f44d5cff", size = 472923, upload-time = "2025-10-14T15:04:39.666Z" }, - { url = "https://files.pythonhosted.org/packages/af/b9/a419292f05e302dea372fa7e6fda5178a92998411f8581b9830d28fb9edb/watchfiles-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aebfd0861a83e6c3d1110b78ad54704486555246e542be3e2bb94195eabb2606", size = 456080, upload-time = "2025-10-14T15:04:40.643Z" }, - { url = "https://files.pythonhosted.org/packages/b0/c3/d5932fd62bde1a30c36e10c409dc5d54506726f08cb3e1d8d0ba5e2bc8db/watchfiles-1.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5fac835b4ab3c6487b5dbad78c4b3724e26bcc468e886f8ba8cc4306f68f6701", size = 629432, upload-time = "2025-10-14T15:04:41.789Z" }, - { url = "https://files.pythonhosted.org/packages/f7/77/16bddd9779fafb795f1a94319dc965209c5641db5bf1edbbccace6d1b3c0/watchfiles-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:399600947b170270e80134ac854e21b3ccdefa11a9529a3decc1327088180f10", size = 623046, upload-time = "2025-10-14T15:04:42.718Z" }, - { url = "https://files.pythonhosted.org/packages/46/ef/f2ecb9a0f342b4bfad13a2787155c6ee7ce792140eac63a34676a2feeef2/watchfiles-1.1.1-cp311-cp311-win32.whl", hash = "sha256:de6da501c883f58ad50db3a32ad397b09ad29865b5f26f64c24d3e3281685849", size = 271473, upload-time = "2025-10-14T15:04:43.624Z" }, - { url = "https://files.pythonhosted.org/packages/94/bc/f42d71125f19731ea435c3948cad148d31a64fccde3867e5ba4edee901f9/watchfiles-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:35c53bd62a0b885bf653ebf6b700d1bf05debb78ad9292cf2a942b23513dc4c4", size = 287598, upload-time = "2025-10-14T15:04:44.516Z" }, - { url = "https://files.pythonhosted.org/packages/57/c9/a30f897351f95bbbfb6abcadafbaca711ce1162f4db95fc908c98a9165f3/watchfiles-1.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:57ca5281a8b5e27593cb7d82c2ac927ad88a96ed406aa446f6344e4328208e9e", size = 277210, upload-time = "2025-10-14T15:04:45.883Z" }, - { url = "https://files.pythonhosted.org/packages/74/d5/f039e7e3c639d9b1d09b07ea412a6806d38123f0508e5f9b48a87b0a76cc/watchfiles-1.1.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8c89f9f2f740a6b7dcc753140dd5e1ab9215966f7a3530d0c0705c83b401bd7d", size = 404745, upload-time = "2025-10-14T15:04:46.731Z" }, - { url = "https://files.pythonhosted.org/packages/a5/96/a881a13aa1349827490dab2d363c8039527060cfcc2c92cc6d13d1b1049e/watchfiles-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd404be08018c37350f0d6e34676bd1e2889990117a2b90070b3007f172d0610", size = 391769, upload-time = "2025-10-14T15:04:48.003Z" }, - { url = "https://files.pythonhosted.org/packages/4b/5b/d3b460364aeb8da471c1989238ea0e56bec24b6042a68046adf3d9ddb01c/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8526e8f916bb5b9a0a777c8317c23ce65de259422bba5b31325a6fa6029d33af", size = 449374, upload-time = "2025-10-14T15:04:49.179Z" }, - { url = "https://files.pythonhosted.org/packages/b9/44/5769cb62d4ed055cb17417c0a109a92f007114a4e07f30812a73a4efdb11/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2edc3553362b1c38d9f06242416a5d8e9fe235c204a4072e988ce2e5bb1f69f6", size = 459485, upload-time = "2025-10-14T15:04:50.155Z" }, - { url = "https://files.pythonhosted.org/packages/19/0c/286b6301ded2eccd4ffd0041a1b726afda999926cf720aab63adb68a1e36/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30f7da3fb3f2844259cba4720c3fc7138eb0f7b659c38f3bfa65084c7fc7abce", size = 488813, upload-time = "2025-10-14T15:04:51.059Z" }, - { url = "https://files.pythonhosted.org/packages/c7/2b/8530ed41112dd4a22f4dcfdb5ccf6a1baad1ff6eed8dc5a5f09e7e8c41c7/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8979280bdafff686ba5e4d8f97840f929a87ed9cdf133cbbd42f7766774d2aa", size = 594816, upload-time = "2025-10-14T15:04:52.031Z" }, - { url = "https://files.pythonhosted.org/packages/ce/d2/f5f9fb49489f184f18470d4f99f4e862a4b3e9ac2865688eb2099e3d837a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcc5c24523771db3a294c77d94771abcfcb82a0e0ee8efd910c37c59ec1b31bb", size = 475186, upload-time = "2025-10-14T15:04:53.064Z" }, - { url = "https://files.pythonhosted.org/packages/cf/68/5707da262a119fb06fbe214d82dd1fe4a6f4af32d2d14de368d0349eb52a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db5d7ae38ff20153d542460752ff397fcf5c96090c1230803713cf3147a6803", size = 456812, upload-time = "2025-10-14T15:04:55.174Z" }, - { url = "https://files.pythonhosted.org/packages/66/ab/3cbb8756323e8f9b6f9acb9ef4ec26d42b2109bce830cc1f3468df20511d/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:28475ddbde92df1874b6c5c8aaeb24ad5be47a11f87cde5a28ef3835932e3e94", size = 630196, upload-time = "2025-10-14T15:04:56.22Z" }, - { url = "https://files.pythonhosted.org/packages/78/46/7152ec29b8335f80167928944a94955015a345440f524d2dfe63fc2f437b/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:36193ed342f5b9842edd3532729a2ad55c4160ffcfa3700e0d54be496b70dd43", size = 622657, upload-time = "2025-10-14T15:04:57.521Z" }, - { url = "https://files.pythonhosted.org/packages/0a/bf/95895e78dd75efe9a7f31733607f384b42eb5feb54bd2eb6ed57cc2e94f4/watchfiles-1.1.1-cp312-cp312-win32.whl", hash = "sha256:859e43a1951717cc8de7f4c77674a6d389b106361585951d9e69572823f311d9", size = 272042, upload-time = "2025-10-14T15:04:59.046Z" }, - { url = "https://files.pythonhosted.org/packages/87/0a/90eb755f568de2688cb220171c4191df932232c20946966c27a59c400850/watchfiles-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:91d4c9a823a8c987cce8fa2690923b069966dabb196dd8d137ea2cede885fde9", size = 288410, upload-time = "2025-10-14T15:05:00.081Z" }, - { url = "https://files.pythonhosted.org/packages/36/76/f322701530586922fbd6723c4f91ace21364924822a8772c549483abed13/watchfiles-1.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:a625815d4a2bdca61953dbba5a39d60164451ef34c88d751f6c368c3ea73d404", size = 278209, upload-time = "2025-10-14T15:05:01.168Z" }, - { url = "https://files.pythonhosted.org/packages/bb/f4/f750b29225fe77139f7ae5de89d4949f5a99f934c65a1f1c0b248f26f747/watchfiles-1.1.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:130e4876309e8686a5e37dba7d5e9bc77e6ed908266996ca26572437a5271e18", size = 404321, upload-time = "2025-10-14T15:05:02.063Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f9/f07a295cde762644aa4c4bb0f88921d2d141af45e735b965fb2e87858328/watchfiles-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f3bde70f157f84ece3765b42b4a52c6ac1a50334903c6eaf765362f6ccca88a", size = 391783, upload-time = "2025-10-14T15:05:03.052Z" }, - { url = "https://files.pythonhosted.org/packages/bc/11/fc2502457e0bea39a5c958d86d2cb69e407a4d00b85735ca724bfa6e0d1a/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b1fe858430fc0251737ef3824c54027bedb8c37c38114488b8e131cf8219", size = 449279, upload-time = "2025-10-14T15:05:04.004Z" }, - { url = "https://files.pythonhosted.org/packages/e3/1f/d66bc15ea0b728df3ed96a539c777acfcad0eb78555ad9efcaa1274688f0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f27db948078f3823a6bb3b465180db8ebecf26dd5dae6f6180bd87383b6b4428", size = 459405, upload-time = "2025-10-14T15:05:04.942Z" }, - { url = "https://files.pythonhosted.org/packages/be/90/9f4a65c0aec3ccf032703e6db02d89a157462fbb2cf20dd415128251cac0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059098c3a429f62fc98e8ec62b982230ef2c8df68c79e826e37b895bc359a9c0", size = 488976, upload-time = "2025-10-14T15:05:05.905Z" }, - { url = "https://files.pythonhosted.org/packages/37/57/ee347af605d867f712be7029bb94c8c071732a4b44792e3176fa3c612d39/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfb5862016acc9b869bb57284e6cb35fdf8e22fe59f7548858e2f971d045f150", size = 595506, upload-time = "2025-10-14T15:05:06.906Z" }, - { url = "https://files.pythonhosted.org/packages/a8/78/cc5ab0b86c122047f75e8fc471c67a04dee395daf847d3e59381996c8707/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:319b27255aacd9923b8a276bb14d21a5f7ff82564c744235fc5eae58d95422ae", size = 474936, upload-time = "2025-10-14T15:05:07.906Z" }, - { url = "https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c755367e51db90e75b19454b680903631d41f9e3607fbd941d296a020c2d752d", size = 456147, upload-time = "2025-10-14T15:05:09.138Z" }, - { url = "https://files.pythonhosted.org/packages/57/99/da6573ba71166e82d288d4df0839128004c67d2778d3b566c138695f5c0b/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c22c776292a23bfc7237a98f791b9ad3144b02116ff10d820829ce62dff46d0b", size = 630007, upload-time = "2025-10-14T15:05:10.117Z" }, - { url = "https://files.pythonhosted.org/packages/a8/51/7439c4dd39511368849eb1e53279cd3454b4a4dbace80bab88feeb83c6b5/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3a476189be23c3686bc2f4321dd501cb329c0a0469e77b7b534ee10129ae6374", size = 622280, upload-time = "2025-10-14T15:05:11.146Z" }, - { url = "https://files.pythonhosted.org/packages/95/9c/8ed97d4bba5db6fdcdb2b298d3898f2dd5c20f6b73aee04eabe56c59677e/watchfiles-1.1.1-cp313-cp313-win32.whl", hash = "sha256:bf0a91bfb5574a2f7fc223cf95eeea79abfefa404bf1ea5e339c0c1560ae99a0", size = 272056, upload-time = "2025-10-14T15:05:12.156Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f3/c14e28429f744a260d8ceae18bf58c1d5fa56b50d006a7a9f80e1882cb0d/watchfiles-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:52e06553899e11e8074503c8e716d574adeeb7e68913115c4b3653c53f9bae42", size = 288162, upload-time = "2025-10-14T15:05:13.208Z" }, - { url = "https://files.pythonhosted.org/packages/dc/61/fe0e56c40d5cd29523e398d31153218718c5786b5e636d9ae8ae79453d27/watchfiles-1.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac3cc5759570cd02662b15fbcd9d917f7ecd47efe0d6b40474eafd246f91ea18", size = 277909, upload-time = "2025-10-14T15:05:14.49Z" }, - { url = "https://files.pythonhosted.org/packages/79/42/e0a7d749626f1e28c7108a99fb9bf524b501bbbeb9b261ceecde644d5a07/watchfiles-1.1.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:563b116874a9a7ce6f96f87cd0b94f7faf92d08d0021e837796f0a14318ef8da", size = 403389, upload-time = "2025-10-14T15:05:15.777Z" }, - { url = "https://files.pythonhosted.org/packages/15/49/08732f90ce0fbbc13913f9f215c689cfc9ced345fb1bcd8829a50007cc8d/watchfiles-1.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ad9fe1dae4ab4212d8c91e80b832425e24f421703b5a42ef2e4a1e215aff051", size = 389964, upload-time = "2025-10-14T15:05:16.85Z" }, - { url = "https://files.pythonhosted.org/packages/27/0d/7c315d4bd5f2538910491a0393c56bf70d333d51bc5b34bee8e68e8cea19/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce70f96a46b894b36eba678f153f052967a0d06d5b5a19b336ab0dbbd029f73e", size = 448114, upload-time = "2025-10-14T15:05:17.876Z" }, - { url = "https://files.pythonhosted.org/packages/c3/24/9e096de47a4d11bc4df41e9d1e61776393eac4cb6eb11b3e23315b78b2cc/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb467c999c2eff23a6417e58d75e5828716f42ed8289fe6b77a7e5a91036ca70", size = 460264, upload-time = "2025-10-14T15:05:18.962Z" }, - { url = "https://files.pythonhosted.org/packages/cc/0f/e8dea6375f1d3ba5fcb0b3583e2b493e77379834c74fd5a22d66d85d6540/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:836398932192dae4146c8f6f737d74baeac8b70ce14831a239bdb1ca882fc261", size = 487877, upload-time = "2025-10-14T15:05:20.094Z" }, - { url = "https://files.pythonhosted.org/packages/ac/5b/df24cfc6424a12deb41503b64d42fbea6b8cb357ec62ca84a5a3476f654a/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:743185e7372b7bc7c389e1badcc606931a827112fbbd37f14c537320fca08620", size = 595176, upload-time = "2025-10-14T15:05:21.134Z" }, - { url = "https://files.pythonhosted.org/packages/8f/b5/853b6757f7347de4e9b37e8cc3289283fb983cba1ab4d2d7144694871d9c/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afaeff7696e0ad9f02cbb8f56365ff4686ab205fcf9c4c5b6fdfaaa16549dd04", size = 473577, upload-time = "2025-10-14T15:05:22.306Z" }, - { url = "https://files.pythonhosted.org/packages/e1/f7/0a4467be0a56e80447c8529c9fce5b38eab4f513cb3d9bf82e7392a5696b/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7eb7da0eb23aa2ba036d4f616d46906013a68caf61b7fdbe42fc8b25132e77", size = 455425, upload-time = "2025-10-14T15:05:23.348Z" }, - { url = "https://files.pythonhosted.org/packages/8e/e0/82583485ea00137ddf69bc84a2db88bd92ab4a6e3c405e5fb878ead8d0e7/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:831a62658609f0e5c64178211c942ace999517f5770fe9436be4c2faeba0c0ef", size = 628826, upload-time = "2025-10-14T15:05:24.398Z" }, - { url = "https://files.pythonhosted.org/packages/28/9a/a785356fccf9fae84c0cc90570f11702ae9571036fb25932f1242c82191c/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f9a2ae5c91cecc9edd47e041a930490c31c3afb1f5e6d71de3dc671bfaca02bf", size = 622208, upload-time = "2025-10-14T15:05:25.45Z" }, { url = "https://files.pythonhosted.org/packages/c3/f4/0872229324ef69b2c3edec35e84bd57a1289e7d3fe74588048ed8947a323/watchfiles-1.1.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d1715143123baeeaeadec0528bb7441103979a1d5f6fd0e1f915383fea7ea6d5", size = 404315, upload-time = "2025-10-14T15:05:26.501Z" }, { url = "https://files.pythonhosted.org/packages/7b/22/16d5331eaed1cb107b873f6ae1b69e9ced582fcf0c59a50cd84f403b1c32/watchfiles-1.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:39574d6370c4579d7f5d0ad940ce5b20db0e4117444e39b6d8f99db5676c52fd", size = 390869, upload-time = "2025-10-14T15:05:27.649Z" }, { url = "https://files.pythonhosted.org/packages/b2/7e/5643bfff5acb6539b18483128fdc0ef2cccc94a5b8fbda130c823e8ed636/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7365b92c2e69ee952902e8f70f3ba6360d0d596d9299d55d7d386df84b6941fb", size = 449919, upload-time = "2025-10-14T15:05:28.701Z" }, @@ -3200,14 +1688,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" }, { url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" }, { url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" }, - { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611, upload-time = "2025-10-14T15:06:05.809Z" }, - { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889, upload-time = "2025-10-14T15:06:07.035Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616, upload-time = "2025-10-14T15:06:08.072Z" }, - { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413, upload-time = "2025-10-14T15:06:09.209Z" }, - { url = "https://files.pythonhosted.org/packages/d3/8e/e500f8b0b77be4ff753ac94dc06b33d8f0d839377fee1b78e8c8d8f031bf/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:db476ab59b6765134de1d4fe96a1a9c96ddf091683599be0f26147ea1b2e4b88", size = 408250, upload-time = "2025-10-14T15:06:10.264Z" }, - { url = "https://files.pythonhosted.org/packages/bd/95/615e72cd27b85b61eec764a5ca51bd94d40b5adea5ff47567d9ebc4d275a/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89eef07eee5e9d1fda06e38822ad167a044153457e6fd997f8a858ab7564a336", size = 396117, upload-time = "2025-10-14T15:06:11.28Z" }, - { url = "https://files.pythonhosted.org/packages/c9/81/e7fe958ce8a7fb5c73cc9fb07f5aeaf755e6aa72498c57d760af760c91f8/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce19e06cbda693e9e7686358af9cd6f5d61312ab8b00488bc36f5aabbaf77e24", size = 450493, upload-time = "2025-10-14T15:06:12.321Z" }, - { url = "https://files.pythonhosted.org/packages/6e/d4/ed38dd3b1767193de971e694aa544356e63353c33a85d948166b5ff58b9e/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e6f39af2eab0118338902798b5aa6664f46ff66bc0280de76fca67a7f262a49", size = 457546, upload-time = "2025-10-14T15:06:13.372Z" }, ] [[package]] @@ -3216,42 +1696,6 @@ version = "16.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/74/221f58decd852f4b59cc3354cccaf87e8ef695fede361d03dc9a7396573b/websockets-16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04cdd5d2d1dacbad0a7bf36ccbcd3ccd5a30ee188f2560b7a62a30d14107b31a", size = 177343, upload-time = "2026-01-10T09:22:21.28Z" }, - { url = "https://files.pythonhosted.org/packages/19/0f/22ef6107ee52ab7f0b710d55d36f5a5d3ef19e8a205541a6d7ffa7994e5a/websockets-16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8ff32bb86522a9e5e31439a58addbb0166f0204d64066fb955265c4e214160f0", size = 175021, upload-time = "2026-01-10T09:22:22.696Z" }, - { url = "https://files.pythonhosted.org/packages/10/40/904a4cb30d9b61c0e278899bf36342e9b0208eb3c470324a9ecbaac2a30f/websockets-16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:583b7c42688636f930688d712885cf1531326ee05effd982028212ccc13e5957", size = 175320, upload-time = "2026-01-10T09:22:23.94Z" }, - { url = "https://files.pythonhosted.org/packages/9d/2f/4b3ca7e106bc608744b1cdae041e005e446124bebb037b18799c2d356864/websockets-16.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7d837379b647c0c4c2355c2499723f82f1635fd2c26510e1f587d89bc2199e72", size = 183815, upload-time = "2026-01-10T09:22:25.469Z" }, - { url = "https://files.pythonhosted.org/packages/86/26/d40eaa2a46d4302becec8d15b0fc5e45bdde05191e7628405a19cf491ccd/websockets-16.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df57afc692e517a85e65b72e165356ed1df12386ecb879ad5693be08fac65dde", size = 185054, upload-time = "2026-01-10T09:22:27.101Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ba/6500a0efc94f7373ee8fefa8c271acdfd4dca8bd49a90d4be7ccabfc397e/websockets-16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2b9f1e0d69bc60a4a87349d50c09a037a2607918746f07de04df9e43252c77a3", size = 184565, upload-time = "2026-01-10T09:22:28.293Z" }, - { url = "https://files.pythonhosted.org/packages/04/b4/96bf2cee7c8d8102389374a2616200574f5f01128d1082f44102140344cc/websockets-16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:335c23addf3d5e6a8633f9f8eda77efad001671e80b95c491dd0924587ece0b3", size = 183848, upload-time = "2026-01-10T09:22:30.394Z" }, - { url = "https://files.pythonhosted.org/packages/02/8e/81f40fb00fd125357814e8c3025738fc4ffc3da4b6b4a4472a82ba304b41/websockets-16.0-cp310-cp310-win32.whl", hash = "sha256:37b31c1623c6605e4c00d466c9d633f9b812ea430c11c8a278774a1fde1acfa9", size = 178249, upload-time = "2026-01-10T09:22:32.083Z" }, - { url = "https://files.pythonhosted.org/packages/b4/5f/7e40efe8df57db9b91c88a43690ac66f7b7aa73a11aa6a66b927e44f26fa/websockets-16.0-cp310-cp310-win_amd64.whl", hash = "sha256:8e1dab317b6e77424356e11e99a432b7cb2f3ec8c5ab4dabbcee6add48f72b35", size = 178685, upload-time = "2026-01-10T09:22:33.345Z" }, - { url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" }, - { url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" }, - { url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" }, - { url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" }, - { url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" }, - { url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" }, - { url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" }, - { url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" }, - { url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" }, - { url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" }, - { url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" }, - { url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" }, - { url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" }, - { url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" }, - { url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" }, - { url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" }, - { url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" }, - { url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" }, - { url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" }, - { url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" }, - { url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" }, - { url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" }, - { url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" }, - { url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" }, { url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" }, { url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" }, { url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" }, @@ -3270,10 +1714,5 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" }, { url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" }, { url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" }, - { url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" }, - { url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" }, - { url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" }, - { url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" }, - { url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" }, { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, ] diff --git a/frontend/.oxlintrc.jsonc b/frontend/.oxlintrc.jsonc index 432437e..5e8c51a 100644 --- a/frontend/.oxlintrc.jsonc +++ b/frontend/.oxlintrc.jsonc @@ -21,6 +21,7 @@ "**/dist/**/*", "**/node_modules/**/*", "**/src/client/**/*", + "**/src/lib/client/**/*", "**/playwright-report", "**/playwright.config.ts", ], diff --git a/frontend/.storybook/main.ts b/frontend/.storybook/main.ts index e5d322a..92d8e32 100644 --- a/frontend/.storybook/main.ts +++ b/frontend/.storybook/main.ts @@ -1,11 +1,33 @@ import type { StorybookConfig } from '@storybook/react-vite' const config: StorybookConfig = { - stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(ts|tsx)'], + addons: ['@storybook/addon-docs', '@storybook/addon-a11y', '@storybook/addon-vitest'], + framework: { name: '@storybook/react-vite', - options: {}, + options: { + builder: { + viteConfigPath: 'vite.config.ts', + }, + }, }, + + // docs: { + // autodocs: 'tag', + // }, + + typescript: { + reactDocgen: 'react-docgen-typescript', + reactDocgenTypescriptOptions: { + shouldExtractLiteralValuesFromEnum: true, + shouldRemoveUndefinedFromOptional: true, + propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true), + }, + }, + + staticDirs: ['../public'], } + export default config diff --git a/frontend/.storybook/preview.ts b/frontend/.storybook/preview.ts index d7d7c10..80e6d99 100644 --- a/frontend/.storybook/preview.ts +++ b/frontend/.storybook/preview.ts @@ -1,5 +1,8 @@ import type { Preview } from '@storybook/react-vite' +// @ts-ignore +import '#/src/globals.css' + const preview: Preview = { parameters: { controls: { @@ -10,11 +13,13 @@ const preview: Preview = { }, a11y: { - // 'todo' - show a11y violations in the test UI only - // 'error' - fail CI on a11y violations - // 'off' - skip a11y checks entirely test: 'todo', }, + options: { + storySort: { + order: ['Getting started', 'Chakra UI cards', 'layout', ['Navigation bar', '*'], 'UI', '*'], + }, + }, }, } diff --git a/frontend/.storybook/vitest.setup.ts b/frontend/.storybook/vitest.setup.ts index 0906823..f952989 100644 --- a/frontend/.storybook/vitest.setup.ts +++ b/frontend/.storybook/vitest.setup.ts @@ -3,6 +3,4 @@ import { setProjectAnnotations } from '@storybook/react-vite' import * as projectAnnotations from './preview' -// This is an important step to apply the right configuration when testing your stories. -// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]) diff --git a/frontend/README.md b/frontend/README.md index 3f8451d..18cba47 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,28 +1,21 @@ -# California Accountability Panel frontend +# California Accountability Panel front-end documentation -This project is a copy of the main application frontend, but there are slight differences. The goals are: +This project is a copy of the main application front-end, but there are slight differences. The goals are: -- A simpler development environment without Docker. -- Experiment with components while previewing them with Storybook. - Test the project extensively, in more ways than with the main application. +- Experiment with components while previewing them with Storybook. +- A simpler development environment without Docker. > [!Note] > This project must be manually kept in sync by copy-pasting files to and from the main application. See the [sync documentation](https://opensacorg.github.io/app-capanel-doc/developer-guide/documentation-repository-sync). -## Overview - -- [Developer Guide index](https://opensacorg.github.io/app-capanel-doc/developer-guide/) -- [Components guide](https://opensacorg.github.io/app-capanel-doc/developer-guide/components) -- [Storybook guide](https://opensacorg.github.io/app-capanel-doc/developer-guide/storybook) -- [Extended backend/frontend README reference](https://opensacorg.github.io/app-capanel-doc/developer-guide/readme-reference) - -## Requirements +## Prerequisites - [pnpm](https://pnpm.io/) ## Quick start -First, install the frontend dependencies. +First, install the front-end dependencies. - `cd frontend` - `pnpm install` @@ -30,6 +23,9 @@ First, install the frontend dependencies. > [!Warning] > Before running anything, first create the required `.env` files. See [environment variable documentation](https://opensacorg.github.io/app-capanel-doc/developer-guide/environment-variables). +> [!Note] +> PNPM commands must be run from the frontend folder. It is recommended to open the frontend folder directly in VSCode. To run from the root of the project, it is recommended to use Make. + ### Preview the documentation `pnpm storybook` @@ -42,8 +38,16 @@ First, install the frontend dependencies. 1. Generate OpenAPI client: - `pnpm run openapi-ts` (from `frontend/` with `openapi.json` prepared) + 2. Run Playwright tests: - `cd backend` - `uv run fastapi dev` - `cd ../frontend` - `pnpm test` + +## Resources + +- [Developer Guide index](https://opensacorg.github.io/app-capanel-doc/developer-guide/) +- [Components guide](https://opensacorg.github.io/app-capanel-doc/developer-guide/components) +- [Storybook guide](https://opensacorg.github.io/app-capanel-doc/developer-guide/storybook) +- [Extended backend/frontend README reference](https://opensacorg.github.io/app-capanel-doc/developer-guide/readme-reference) diff --git a/frontend/nginx.conf b/frontend/nginx.conf deleted file mode 100644 index f5ffde3..0000000 --- a/frontend/nginx.conf +++ /dev/null @@ -1,40 +0,0 @@ -server { - listen 8080; - - root /usr/share/nginx/html; - index index.html; - - # SPA fallback — serve index.html for all non-file routes - location / { - try_files $uri $uri/ /index.html; - } - - # Proxy API requests to the FastAPI sidecar (localhost in Cloud Run) - location /api { - proxy_pass http://127.0.0.1:9000; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - # Proxy FastAPI docs - location ~ ^/(docs|redoc|openapi.json) { - proxy_pass http://127.0.0.1:9000; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - # Cache static assets built by Vite (hashed filenames = safe to cache long) - location /assets/ { - expires 1y; - add_header Cache-Control "public, no-transform"; - } - - error_page 500 502 503 504 /50x.html; - location = /50x.html { - root /usr/share/nginx/html; - } -} diff --git a/frontend/package.json b/frontend/package.json index 515cd69..0bd4837 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,30 +20,42 @@ "url": "git+https://github.com/opensacorg/app-capanel-doc.org.git" }, "type": "module", + "imports": { + "#/*": "./*", + "#.storybook/*": "./.storybook/*", + "#vite.config.ts": "./vite.config.ts", + "#tsconfig.json": "./tsconfig.json", + "#.oxlintrc.jsonc": "./.oxlintrc.jsonc", + "#.oxfmtrc.jsonc": "./.oxfmtrc.jsonc", + "#playwright.config.ts": "./playwright.config.ts", + "#vitest.config.ts": "./vitest.config.ts", + "#components.json": "./components.json", + "#openapi-ts.config.ts": "./openapi-ts.config.ts" + }, "scripts": { "dev": "vite", - "build": "tsc -p tsconfig.build.json && vite build", + "build": "tsgo && vite build", "compile": "tsgo", - "fmt": "oxfmt", - "fmt:check": "oxfmt --check", - "lint": "oxlint", - "lint:fix": "oxlint --fix", + "format": "oxfmt", + "format:check": "oxfmt --check", + "lint": "oxlint --fix", + "lint:check": "oxlint", "preview": "vite preview", "openapi-ts": "openapi-ts", "test": "pnpm exec playwright test", "test:ui": "pnpm exec playwright test --ui", - "storybook": "storybook dev -p 6006", + "storybook": "storybook dev -p 6006 --no-open", "build-storybook": "storybook build" }, "dependencies": { - "@base-ui/react": "^1.2.0", - "@faker-js/faker": "^10.3.0", + "@base-ui/react": "^1.3.0", + "@faker-js/faker": "^10.4.0", "@fontsource-variable/figtree": "^5.2.10", "@fontsource-variable/urbanist": "^5.2.7", - "@hugeicons/core-free-icons": "^3.3.0", - "@hugeicons/react": "^1.1.5", - "@modelcontextprotocol/sdk": "^1.27.1", - "@tailwindcss/vite": "^4.2.1", + "@hugeicons/core-free-icons": "^4.1.1", + "@hugeicons/react": "^1.1.6", + "@modelcontextprotocol/sdk": "^1.29.0", + "@tailwindcss/vite": "^4.2.2", "@tanstack/ai": "latest", "@tanstack/ai-anthropic": "latest", "@tanstack/ai-client": "latest", @@ -53,17 +65,17 @@ "@tanstack/ai-react": "latest", "@tanstack/match-sorter-utils": "^8.19.4", "@tanstack/react-ai-devtools": "latest", - "@tanstack/react-devtools": "^0.9.10", - "@tanstack/react-form": "^1.28.4", - "@tanstack/react-query": "^5.90.21", - "@tanstack/react-query-devtools": "^5.91.3", - "@tanstack/react-router": "^1.166.6", - "@tanstack/react-router-devtools": "^1.166.6", - "@tanstack/react-store": "^0.9.2", + "@tanstack/react-devtools": "^0.10.1", + "@tanstack/react-form": "^1.28.6", + "@tanstack/react-query": "^5.96.2", + "@tanstack/react-query-devtools": "^5.96.2", + "@tanstack/react-router": "^1.168.10", + "@tanstack/react-router-devtools": "^1.166.11", + "@tanstack/react-store": "^0.9.3", "@tanstack/react-table": "^8.21.3", - "@tanstack/router-plugin": "^1.166.6", - "@tanstack/store": "^0.9.2", - "axios": "^1.13.6", + "@tanstack/router-plugin": "^1.167.12", + "@tanstack/store": "^0.9.3", + "axios": "^1.14.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", @@ -71,52 +83,50 @@ "embla-carousel-react": "^8.6.0", "highlight.js": "^11.11.1", "input-otp": "^1.4.2", - "lucide-react": "^0.577.0", "next-themes": "^0.4.6", - "postgres": "^3.4.8", + "postgres": "^3.4.9", "react": "^19.2.4", "react-day-picker": "^9.14.0", "react-dom": "^19.2.4", - "react-icons": "^5.6.0", - "react-resizable-panels": "^4.7.2", - "recharts": "3.7.0", - "shadcn": "^3.8.5", + "react-resizable-panels": "^4.9.0", + "recharts": "3.8.0", + "shadcn": "^4.1.2", "sonner": "^2.0.7", - "streamdown": "^2.4.0", + "streamdown": "^2.5.0", "tailwind-merge": "^3.5.0", - "tailwindcss": "^4.2.1", + "tailwindcss": "^4.2.2", "tw-animate-css": "^1.4.0", "vaul": "^1.1.2", - "vite-tsconfig-paths": "^6.1.1", "zod": "^4.3.6" }, "devDependencies": { - "@hey-api/openapi-ts": "0.93.1", - "@playwright/test": "^1.58.2", - "@storybook/addon-a11y": "^10.2.17", - "@storybook/addon-docs": "^10.2.17", - "@storybook/addon-vitest": "^10.2.17", - "@storybook/react-vite": "^10.2.17", - "@tanstack/devtools-event-client": "^0.4.1", - "@tanstack/devtools-vite": "^0.5.3", - "@tanstack/router-devtools": "^1.166.6", - "@tanstack/router-plugin": "^1.166.2", - "@types/node": "^25.4.0", + "@hey-api/openapi-ts": "0.94.4", + "@playwright/test": "^1.59.1", + "@storybook/addon-a11y": "^10.3.4", + "@storybook/addon-docs": "^10.3.4", + "@storybook/addon-vitest": "^10.3.4", + "@storybook/react": "^10.3.4", + "@storybook/react-vite": "^10.3.4", + "@tanstack/devtools-event-client": "^0.4.3", + "@tanstack/devtools-vite": "^0.6.0", + "@tanstack/router-devtools": "^1.166.11", + "@tanstack/router-plugin": "^1.167.4", + "@types/node": "^25.5.2", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", - "@typescript/native-preview": "7.0.0-dev.20260304.1", - "@vitejs/plugin-react": "^5.1.4", + "@typescript/native-preview": "7.0.0-dev.20260324.1", + "@vitejs/plugin-react": "^6.0.1", + "@vitest/browser-playwright": "^4.1.2", "babel-plugin-react-compiler": "^1.0.0", - "dotenv": "^17.3.1", - "eslint-plugin-react-hooks": "^7.0.1", - "oxfmt": "^0.36.0", - "oxlint": "^1.51.0", - "playwright": "^1.58.2", - "storybook": "^10.2.17", + "dotenv": "^17.4.1", + "oxfmt": "^0.42.0", + "oxlint": "^1.59.0", + "playwright": "^1.59.1", + "storybook": "^10.3.4", "tw-animate-css": "^1.4.0", - "vite": "npm:rolldown-vite@^7.3.1", - "vitest": "^4.0.18", - "web-vitals": "^5.1.0" + "vite": "8.0.2", + "vitest": "^4.1.2", + "web-vitals": "^5.2.0" }, "lint-staged": { "*": "oxfmt --no-error-on-unmatched-pattern" diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts new file mode 100644 index 0000000..f7d0a31 --- /dev/null +++ b/frontend/playwright.config.ts @@ -0,0 +1,61 @@ +import { defineConfig, devices } from '@playwright/test' +import dotenv from 'dotenv' +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) + +dotenv.config({ path: path.resolve(__dirname, '.env') }) + +/** + * Playwright configuration. See https://app-lbe-doc.vercel.app/testing. + */ +export default defineConfig({ + testDir: './tests', + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: 'html', + use: { + baseURL: 'http://localhost:3000', + trace: 'on-first-retry', + }, + projects: [ + { + name: 'Microsoft Edge', + use: { ...devices['Desktop Edge'], channel: 'msedge' }, + }, + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + { + name: 'Mobile Chrome', + use: { ...devices['Pixel 5'] }, + }, + { + name: 'Mobile Safari', + use: { ...devices['iPhone 12'] }, + }, + ], + webServer: { + command: 'npm run dev', + url: 'http://localhost:3000', + reuseExistingServer: !process.env.CI, + }, +}) diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index f1846be..3d7e54e 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -9,11 +9,11 @@ importers: .: dependencies: '@base-ui/react': - specifier: ^1.2.0 - version: 1.2.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^1.3.0 + version: 1.3.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@faker-js/faker': - specifier: ^10.3.0 - version: 10.3.0 + specifier: ^10.4.0 + version: 10.4.0 '@fontsource-variable/figtree': specifier: ^5.2.10 version: 5.2.10 @@ -21,77 +21,77 @@ importers: specifier: ^5.2.7 version: 5.2.7 '@hugeicons/core-free-icons': - specifier: ^3.3.0 - version: 3.3.0 + specifier: ^4.1.1 + version: 4.1.1 '@hugeicons/react': - specifier: ^1.1.5 - version: 1.1.5(react@19.2.4) + specifier: ^1.1.6 + version: 1.1.6(react@19.2.4) '@modelcontextprotocol/sdk': - specifier: ^1.27.1 - version: 1.27.1(zod@4.3.6) + specifier: ^1.29.0 + version: 1.29.0(zod@4.3.6) '@tailwindcss/vite': - specifier: ^4.2.1 - version: 4.2.1(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)) + specifier: ^4.2.2 + version: 4.2.2(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) '@tanstack/ai': specifier: latest - version: 0.6.2 + version: 0.10.0 '@tanstack/ai-anthropic': specifier: latest - version: 0.6.0(@tanstack/ai@0.6.2)(zod@4.3.6) + version: 0.7.2(@tanstack/ai@0.10.0)(zod@4.3.6) '@tanstack/ai-client': specifier: latest - version: 0.5.3 + version: 0.7.7 '@tanstack/ai-gemini': specifier: latest - version: 0.8.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(@tanstack/ai@0.6.2) + version: 0.8.5(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(@tanstack/ai@0.10.0) '@tanstack/ai-ollama': specifier: latest - version: 0.6.0(@tanstack/ai@0.6.2) + version: 0.6.4(@tanstack/ai@0.10.0) '@tanstack/ai-openai': specifier: latest - version: 0.6.0(@tanstack/ai@0.6.2)(ws@8.19.0)(zod@4.3.6) + version: 0.7.3(@tanstack/ai-client@0.7.7)(@tanstack/ai@0.10.0)(ws@8.20.0)(zod@4.3.6) '@tanstack/ai-react': specifier: latest - version: 0.6.3(@tanstack/ai@0.6.2)(@types/react@19.2.14)(react@19.2.4) + version: 0.7.8(@tanstack/ai@0.10.0)(@types/react@19.2.14)(react@19.2.4) '@tanstack/match-sorter-utils': specifier: ^8.19.4 version: 8.19.4 '@tanstack/react-ai-devtools': specifier: latest - version: 0.2.12(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11) + version: 0.2.21(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.12) '@tanstack/react-devtools': - specifier: ^0.9.10 - version: 0.9.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11) + specifier: ^0.10.1 + version: 0.10.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.12) '@tanstack/react-form': - specifier: ^1.28.4 - version: 1.28.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^1.28.6 + version: 1.28.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-query': - specifier: ^5.90.21 - version: 5.90.21(react@19.2.4) + specifier: ^5.96.2 + version: 5.96.2(react@19.2.4) '@tanstack/react-query-devtools': - specifier: ^5.91.3 - version: 5.91.3(@tanstack/react-query@5.90.21(react@19.2.4))(react@19.2.4) + specifier: ^5.96.2 + version: 5.96.2(@tanstack/react-query@5.96.2(react@19.2.4))(react@19.2.4) '@tanstack/react-router': - specifier: ^1.166.6 - version: 1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^1.168.10 + version: 1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-router-devtools': - specifier: ^1.166.6 - version: 1.166.6(@tanstack/react-router@1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.166.6)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^1.166.11 + version: 1.166.11(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.168.9)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-store': - specifier: ^0.9.2 - version: 0.9.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^0.9.3 + version: 0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-table': specifier: ^8.21.3 version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/router-plugin': - specifier: ^1.166.6 - version: 1.166.6(@tanstack/react-router@1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)) + specifier: ^1.167.12 + version: 1.167.12(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) '@tanstack/store': - specifier: ^0.9.2 - version: 0.9.2 + specifier: ^0.9.3 + version: 0.9.3 axios: - specifier: ^1.13.6 - version: 1.13.6 + specifier: ^1.14.0 + version: 1.14.0 class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -113,15 +113,12 @@ importers: input-otp: specifier: ^1.4.2 version: 1.4.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - lucide-react: - specifier: ^0.577.0 - version: 0.577.0(react@19.2.4) next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) postgres: - specifier: ^3.4.8 - version: 3.4.8 + specifier: ^3.4.9 + version: 3.4.9 react: specifier: ^19.2.4 version: 19.2.4 @@ -131,73 +128,70 @@ importers: react-dom: specifier: ^19.2.4 version: 19.2.4(react@19.2.4) - react-icons: - specifier: ^5.6.0 - version: 5.6.0(react@19.2.4) react-resizable-panels: - specifier: ^4.7.2 - version: 4.7.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^4.9.0 + version: 4.9.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) recharts: - specifier: 3.7.0 - version: 3.7.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@19.2.4)(react@19.2.4)(redux@5.0.1) + specifier: 3.8.0 + version: 3.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@19.2.4)(react@19.2.4)(redux@5.0.1) shadcn: - specifier: ^3.8.5 - version: 3.8.5(@types/node@25.4.0)(typescript@6.0.0-beta) + specifier: ^4.1.2 + version: 4.1.2(@types/node@25.5.2)(typescript@6.0.0-beta) sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) streamdown: - specifier: ^2.4.0 - version: 2.4.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^2.5.0 + version: 2.5.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tailwind-merge: specifier: ^3.5.0 version: 3.5.0 tailwindcss: - specifier: ^4.2.1 - version: 4.2.1 + specifier: ^4.2.2 + version: 4.2.2 tw-animate-css: specifier: ^1.4.0 version: 1.4.0 vaul: specifier: ^1.1.2 version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - vite-tsconfig-paths: - specifier: ^6.1.1 - version: 6.1.1(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(typescript@6.0.0-beta) zod: specifier: ^4.3.6 version: 4.3.6 devDependencies: '@hey-api/openapi-ts': - specifier: 0.93.1 - version: 0.93.1(typescript@6.0.0-beta) + specifier: 0.94.4 + version: 0.94.4(typescript@6.0.0-beta) '@playwright/test': - specifier: ^1.58.2 - version: 1.58.2 + specifier: ^1.59.1 + version: 1.59.1 '@storybook/addon-a11y': - specifier: ^10.2.17 - version: 10.2.17(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + specifier: ^10.3.4 + version: 10.3.4(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) '@storybook/addon-docs': - specifier: ^10.2.17 - version: 10.2.17(@types/react@19.2.14)(esbuild@0.27.3)(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + specifier: ^10.3.4 + version: 10.3.4(@types/react@19.2.14)(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) '@storybook/addon-vitest': - specifier: ^10.2.17 - version: 10.2.17(@vitest/runner@4.0.18)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vitest@4.0.18(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@25.4.0)(typescript@6.0.0-beta))(tsx@4.21.0)) + specifier: ^10.3.4 + version: 10.3.4(@vitest/browser-playwright@4.1.2)(@vitest/browser@4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))(vitest@4.1.2))(@vitest/runner@4.1.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vitest@4.1.2) + '@storybook/react': + specifier: ^10.3.4 + version: 10.3.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@6.0.0-beta) '@storybook/react-vite': - specifier: ^10.2.17 - version: 10.2.17(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@6.0.0-beta) + specifier: ^10.3.4 + version: 10.3.4(esbuild@0.27.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@6.0.0-beta)(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) '@tanstack/devtools-event-client': - specifier: ^0.4.1 - version: 0.4.1 + specifier: ^0.4.3 + version: 0.4.3 '@tanstack/devtools-vite': - specifier: ^0.5.3 - version: 0.5.3(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)) + specifier: ^0.6.0 + version: 0.6.0(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) '@tanstack/router-devtools': - specifier: ^1.166.6 - version: 1.166.6(@tanstack/react-router@1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.166.6)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^1.166.11 + version: 1.166.11(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.168.9)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/node': - specifier: ^25.4.0 - version: 25.4.0 + specifier: ^25.5.2 + version: 25.5.2 '@types/react': specifier: ^19.2.14 version: 19.2.14 @@ -205,50 +199,49 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.14) '@typescript/native-preview': - specifier: 7.0.0-dev.20260304.1 - version: 7.0.0-dev.20260304.1 + specifier: 7.0.0-dev.20260324.1 + version: 7.0.0-dev.20260324.1 '@vitejs/plugin-react': - specifier: ^5.1.4 - version: 5.1.4(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)) + specifier: ^6.0.1 + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) + '@vitest/browser-playwright': + specifier: ^4.1.2 + version: 4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(playwright@1.59.1)(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))(vitest@4.1.2) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 dotenv: - specifier: ^17.3.1 - version: 17.3.1 - eslint-plugin-react-hooks: - specifier: ^7.0.1 - version: 7.0.1(eslint@9.39.3(jiti@2.6.1)) + specifier: ^17.4.1 + version: 17.4.1 oxfmt: - specifier: ^0.36.0 - version: 0.36.0 + specifier: ^0.42.0 + version: 0.42.0 oxlint: - specifier: ^1.51.0 - version: 1.51.0 + specifier: ^1.59.0 + version: 1.59.0 playwright: - specifier: ^1.58.2 - version: 1.58.2 + specifier: ^1.59.1 + version: 1.59.1 storybook: - specifier: ^10.2.17 - version: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^10.3.4 + version: 10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) vite: - specifier: npm:rolldown-vite@^7.3.1 - version: rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) + specifier: 8.0.2 + version: 8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) vitest: - specifier: ^4.0.18 - version: 4.0.18(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@25.4.0)(typescript@6.0.0-beta))(tsx@4.21.0) + specifier: ^4.1.2 + version: 4.1.2(@types/node@25.5.2)(@vitest/browser-playwright@4.1.2)(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) web-vitals: - specifier: ^5.1.0 - version: 5.1.0 + specifier: ^5.2.0 + version: 5.2.0 packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@antfu/ni@25.0.0': - resolution: {integrity: sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA==} - hasBin: true + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} '@anthropic-ai/sdk@0.71.2': resolution: {integrity: sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==} @@ -337,12 +330,12 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} engines: {node: '>=6.0.0'} hasBin: true @@ -364,18 +357,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.28.6': resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} engines: {node: '>=6.9.0'} @@ -388,8 +369,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} '@babel/template@7.28.6': @@ -404,8 +385,8 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@base-ui/react@1.2.0': - resolution: {integrity: sha512-O6aEQHcm+QyGTFY28xuwRD3SEJGZOBDpyjN2WvpfWYFVhg+3zfXPysAILqtM0C1kWC82MccOE/v1j+GHXE4qIw==} + '@base-ui/react@1.3.0': + resolution: {integrity: sha512-FwpKqZbPz14AITp1CVgf4AjhKPe1OeeVKSBMdgD10zbFlj3QSWelmtCMLi2+/PFZZcIm3l87G7rwtCZJwHyXWA==} engines: {node: '>=14.0.0'} peerDependencies: '@types/react': ^17 || ^18 || ^19 @@ -415,8 +396,8 @@ packages: '@types/react': optional: true - '@base-ui/utils@0.2.5': - resolution: {integrity: sha512-oYC7w0gp76RI5MxprlGLV0wze0SErZaRl3AAkeP3OnNB/UBMb6RqNf6ZSIlxOc9Qp68Ab3C2VOcJQyRs7Xc7Vw==} + '@base-ui/utils@0.2.6': + resolution: {integrity: sha512-yQ+qeuqohwhsNpoYDqqXaLllYAkPCP4vYdDrVo8FQXaAPfHWm1pG/Vm+jmGTA5JFS0BAIjookyapuJFY8F9PIw==} peerDependencies: '@types/react': ^17 || ^18 || ^19 react: ^17 || ^18 || ^19 @@ -425,224 +406,207 @@ packages: '@types/react': optional: true + '@blazediff/core@1.9.1': + resolution: {integrity: sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==} + + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + + '@chevrotain/cst-dts-gen@11.1.2': + resolution: {integrity: sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==} + + '@chevrotain/gast@11.1.2': + resolution: {integrity: sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==} + + '@chevrotain/regexp-to-ast@11.1.2': + resolution: {integrity: sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==} + + '@chevrotain/types@11.1.2': + resolution: {integrity: sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==} + + '@chevrotain/utils@11.1.2': + resolution: {integrity: sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==} + '@date-fns/tz@1.4.1': resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} - '@dotenvx/dotenvx@1.54.1': - resolution: {integrity: sha512-41gU3q7v05GM92QPuPUf4CmUw+mmF8p4wLUh6MCRlxpCkJ9ByLcY9jUf6MwrMNmiKyG/rIckNxj9SCfmNCmCqw==} + '@dotenvx/dotenvx@1.60.1': + resolution: {integrity: sha512-pPKqhE/HiaPDfbSf6doJnxeqzLszWP4eLICB89wRDZGaBaLzGpa3RgahVYIauBonaEWT8oxqAyacWKHtD+n3hQ==} hasBin: true - '@ecies/ciphers@0.2.5': - resolution: {integrity: sha512-GalEZH4JgOMHYYcYmVqnFirFsjZHeoGMDt9IxEnM9F7GRUUyUksJ7Ou53L83WHJq3RWKD3AcBpo0iQh0oMpf8A==} - engines: {bun: '>=1', deno: '>=2', node: '>=16'} + '@ecies/ciphers@0.2.6': + resolution: {integrity: sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g==} + engines: {bun: '>=1', deno: '>=2.7.10', node: '>=16'} peerDependencies: '@noble/ciphers': ^1.0.0 - '@emnapi/core@1.8.1': - resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} - '@emnapi/runtime@1.8.1': - resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} - '@emnapi/wasi-threads@1.1.0': - resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.21.2': - resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@3.3.5': - resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.39.3': - resolution: {integrity: sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@faker-js/faker@10.3.0': - resolution: {integrity: sha512-It0Sne6P3szg7JIi6CgKbvTZoMjxBZhcv91ZrqrNuaZQfB5WoqYYbzCUOq89YR+VY8juY9M1vDWmDDa2TzfXCw==} + '@faker-js/faker@10.4.0': + resolution: {integrity: sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==} engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} '@floating-ui/core@1.7.5': @@ -666,8 +630,8 @@ packages: '@fontsource-variable/urbanist@5.2.7': resolution: {integrity: sha512-OYeUoBQhwm3pbXG5yUxq1omO9H64Dx1eKxldKYOztrf+8GFG1vu3FP/zZpmFOwtgsPj2h6JYHX9VVWopSxvOyQ==} - '@google/genai@1.44.0': - resolution: {integrity: sha512-kRt9ZtuXmz+tLlcNntN/VV4LRdpl6ZOu5B1KbfNgfR65db15O6sUQcwnwLka8sT/V6qysD93fWrgJHF2L7dA9A==} + '@google/genai@1.48.0': + resolution: {integrity: sha512-plonYK4ML2PrxsRD9SeqmFt76eREWkQdPCglOA6aYDzL1AAbE+7PUnT54SvpWGfws13L0AZEqGSpL7+1IPnTxQ==} engines: {node: '>=20.0.0'} peerDependencies: '@modelcontextprotocol/sdk': ^1.25.2 @@ -675,63 +639,47 @@ packages: '@modelcontextprotocol/sdk': optional: true - '@hey-api/codegen-core@0.7.0': - resolution: {integrity: sha512-HglL4B4QwpzocE+c8qDU6XK8zMf8W8Pcv0RpFDYxHuYALWLTnpDUuEsglC7NQ4vC1maoXsBpMbmwpco0N4QviA==} + '@hey-api/codegen-core@0.7.4': + resolution: {integrity: sha512-DGd9yeSQzflOWO3Y5mt1GRXkXH9O/yIMgbxPjwLI3jwu/3nAjoXXD26lEeFb6tclYlg0JAqTIs5d930G/qxHeA==} engines: {node: '>=20.19.0'} - peerDependencies: - typescript: '>=5.5.3' '@hey-api/json-schema-ref-parser@1.3.1': resolution: {integrity: sha512-7atnpUkT8TyUPHYPLk91j/GyaqMuwTEHanLOe50Dlx0EEvNuQqFD52Yjg8x4KU0UFL1mWlyhE+sUE/wAtQ1N2A==} engines: {node: '>=20.19.0'} - '@hey-api/openapi-ts@0.93.1': - resolution: {integrity: sha512-oQJPHiVkJKesZFpoW3jfQhrSQ7xdgzai7895ENl6ZDjCaIK6bOUTly7bsu+7+0ONsGH9jbtGbkoUzC+MtY+RKg==} + '@hey-api/openapi-ts@0.94.4': + resolution: {integrity: sha512-943f7wlLAQ0KHVx8CeD3xYJzBsCRQYtr+lgMYrAdfV48j32loqsqiMAM4fsMxvSO7mkz0lqcJkIb+YZIXO8Ubg==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: - typescript: '>=5.5.3' + typescript: '>=5.5.3 || 6.0.1-rc' - '@hey-api/shared@0.2.1': - resolution: {integrity: sha512-uWI9047e9OVe3Ss+6vPMnRiixjRcjcBbdgpeq4IQymet3+wsn0+N/4RLDHBz1h57SemaxayPRUA0JOOsuC1qyA==} + '@hey-api/shared@0.2.5': + resolution: {integrity: sha512-NS57dHXxhwBtenPWAzljA0I493ZxzjcZZtr8KFr8SsLboofdjcAbVRFAfOQ0iv2JMhOe9oyiWEEc1QOJ/9WWaw==} engines: {node: '>=20.19.0'} - peerDependencies: - typescript: '>=5.5.3' - '@hey-api/types@0.1.3': - resolution: {integrity: sha512-mZaiPOWH761yD4GjDQvtjS2ZYLu5o5pI1TVSvV/u7cmbybv51/FVtinFBeaE1kFQCKZ8OQpn2ezjLBJrKsGATw==} - peerDependencies: - typescript: '>=5.5.3' + '@hey-api/types@0.1.4': + resolution: {integrity: sha512-thWfawrDIP7wSI9ioT13I5soaaqB5vAPIiZmgD8PbeEVKNrkonc0N/Sjj97ezl7oQgusZmaNphGdMKipPO6IBg==} - '@hono/node-server@1.19.11': - resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} + '@hono/node-server@1.19.13': + resolution: {integrity: sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ==} engines: {node: '>=18.14.1'} peerDependencies: hono: ^4 - '@hugeicons/core-free-icons@3.3.0': - resolution: {integrity: sha512-qYyr4JQ2eQIHTSTbITvnJvs6ERNK64D9gpwZnf2IyuG0exzqfyABLO/oTB71FB3RZPfu1GbwycdiGSo46apjMQ==} + '@hugeicons/core-free-icons@4.1.1': + resolution: {integrity: sha512-teqIBvPHl90ygIwKyJwTxOH8aNp1X1PjDTcMvLkEwdPxPD+8mssrZ5kXKIAJJFYPsz69a8LYQY0UPid4PAdavg==} - '@hugeicons/react@1.1.5': - resolution: {integrity: sha512-JX/iDz3oO7hWdVqbjwFwRrAjHk8h2vI+mBkNzp4JcXG3t4idoupfjon73nLOA7cr27m0M8hrRC1Q2h6nEBGKVA==} + '@hugeicons/react@1.1.6': + resolution: {integrity: sha512-c2LhXJMAW5wN1pC/smBXG0YPqUON6ceR/ZdXHCjEI9KvB+hjtqYjmzIxok5hAQOeXGz0WtORgCQMzqewFKAZwg==} peerDependencies: react: '>=16.0.0' - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} + '@iconify/utils@3.1.0': + resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==} '@inquirer/ansi@1.0.2': resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} @@ -768,15 +716,11 @@ packages: '@types/node': optional: true - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4': - resolution: {integrity: sha512-6PyZBYKnnVNqOSB0YFly+62R7dmov8segT27A+RVTBVd4iAE6kbW9QBJGlyR2yG4D4ohzhZSTIu7BK1UTtmFFA==} + '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0': + resolution: {integrity: sha512-qvsTEwEFefhdirGOPnu9Wp6ChfIwy2dBCRuETU3uE+4cC+PFoxMSiiEhxk4lOluA34eARHA0OxqsEUYDqRMgeQ==} peerDependencies: typescript: '>= 4.3.x' - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true @@ -806,8 +750,11 @@ packages: '@types/react': '>=16' react: '>=16' - '@modelcontextprotocol/sdk@1.27.1': - resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==} + '@mermaid-js/parser@1.1.0': + resolution: {integrity: sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==} + + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -820,8 +767,11 @@ packages: resolution: {integrity: sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==} engines: {node: '>=18'} - '@napi-rs/wasm-runtime@1.1.1': - resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@napi-rs/wasm-runtime@1.1.2': + resolution: {integrity: sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 '@noble/ciphers@1.3.0': resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} @@ -856,266 +806,261 @@ packages: '@open-draft/until@2.1.0': resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} - '@oxc-project/runtime@0.101.0': - resolution: {integrity: sha512-t3qpfVZIqSiLQ5Kqt/MC4Ge/WCOGrrcagAdzTcDaggupjiGxUx4nJF2v6wUCXWSzWHn5Ns7XLv13fCJEwCOERQ==} - engines: {node: ^20.19.0 || >=22.12.0} - - '@oxc-project/types@0.101.0': - resolution: {integrity: sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==} + '@oxc-project/types@0.122.0': + resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} - '@oxfmt/binding-android-arm-eabi@0.36.0': - resolution: {integrity: sha512-Z4yVHJWx/swHHjtr0dXrBZb6LxS+qNz1qdza222mWwPTUK4L790+5i3LTgjx3KYGBzcYpjaiZBw4vOx94dH7MQ==} + '@oxfmt/binding-android-arm-eabi@0.42.0': + resolution: {integrity: sha512-dsqPTYsozeokRjlrt/b4E7Pj0z3eS3Eg74TWQuuKbjY4VttBmA88rB7d50Xrd+TZ986qdXCNeZRPEzZHAe+jow==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxfmt/binding-android-arm64@0.36.0': - resolution: {integrity: sha512-3ElCJRFNPQl7jexf2CAa9XmAm8eC5JPrIDSjc9jSchkVSFTEqyL0NtZinBB2h1a4i4JgP1oGl/5G5n8YR4FN8Q==} + '@oxfmt/binding-android-arm64@0.42.0': + resolution: {integrity: sha512-t+aAjHxcr5eOBphFHdg1ouQU9qmZZoRxnX7UOJSaTwSoKsb6TYezNKO0YbWytGXCECObRqNcUxPoPr0KaraAIg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxfmt/binding-darwin-arm64@0.36.0': - resolution: {integrity: sha512-nak4znWCqIExKhYSY/mz/lWsqWIpdsS7o0+SRzXR1Q0m7GrMcG1UrF1pS7TLGZhhkf7nTfEF7q6oZzJiodRDuw==} + '@oxfmt/binding-darwin-arm64@0.42.0': + resolution: {integrity: sha512-ulpSEYMKg61C5bRMZinFHrKJYRoKGVbvMEXA5zM1puX3O9T6Q4XXDbft20yrDijpYWeuG59z3Nabt+npeTsM1A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxfmt/binding-darwin-x64@0.36.0': - resolution: {integrity: sha512-V4GP96thDnpKx6ADnMDnhIXNdtV+Ql9D4HUU+a37VTeVbs5qQSF/s6hhUP1b3xUqU7iRcwh72jUU2Y12rtGHAw==} + '@oxfmt/binding-darwin-x64@0.42.0': + resolution: {integrity: sha512-ttxLKhQYPdFiM8I/Ri37cvqChE4Xa562nNOsZFcv1CKTVLeEozXjKuYClNvxkXmNlcF55nzM80P+CQkdFBu+uQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxfmt/binding-freebsd-x64@0.36.0': - resolution: {integrity: sha512-/xapWCADfI5wrhxpEUjhI9fnw7MV5BUZizVa8e24n3VSK6A3Y1TB/ClOP1tfxNspykFKXp4NBWl6NtDJP3osqQ==} + '@oxfmt/binding-freebsd-x64@0.42.0': + resolution: {integrity: sha512-Og7QS3yI3tdIKYZ58SXik0rADxIk2jmd+/YvuHRyKULWpG4V2fR5V4hvKm624Mc0cQET35waPXiCQWvjQEjwYQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxfmt/binding-linux-arm-gnueabihf@0.36.0': - resolution: {integrity: sha512-1lOmv61XMFIH5uNm27620kRRzWt/RK6tdn250BRDoG9W7OXGOQ5UyI1HVT+SFkoOoKztBiinWgi68+NA1MjBVQ==} + '@oxfmt/binding-linux-arm-gnueabihf@0.42.0': + resolution: {integrity: sha512-jwLOw/3CW4H6Vxcry4/buQHk7zm9Ne2YsidzTL1kpiMe4qqrRCwev3dkyWe2YkFmP+iZCQ7zku4KwjcLRoh8ew==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm-musleabihf@0.36.0': - resolution: {integrity: sha512-vMH23AskdR1ujUS9sPck2Df9rBVoZUnCVY86jisILzIQ/QQ/yKUTi7tgnIvydPx7TyB/48wsQ5QMr5Knq5p/aw==} + '@oxfmt/binding-linux-arm-musleabihf@0.42.0': + resolution: {integrity: sha512-XwXu2vkMtiq2h7tfvN+WA/9/5/1IoGAVCFPiiQUvcAuG3efR97KNcRGM8BetmbYouFotQ2bDal3yyjUx6IPsTg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm64-gnu@0.36.0': - resolution: {integrity: sha512-Hy1V+zOBHpBiENRx77qrUTt5aPDHeCASRc8K5KwwAHkX2AKP0nV89eL17hsZrE9GmnXFjsNmd80lyf7aRTXsbw==} + '@oxfmt/binding-linux-arm64-gnu@0.42.0': + resolution: {integrity: sha512-ea7s/XUJoT7ENAtUQDudFe3nkSM3e3Qpz4nJFRdzO2wbgXEcjnchKLEsV3+t4ev3r8nWxIYr9NRjPWtnyIFJVA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-arm64-musl@0.36.0': - resolution: {integrity: sha512-SPGLJkOIHSIC6ABUQ5V8NqJpvYhMJueJv26NYqfCnwi/Mn6A61amkpJJ9Suy0Nmvs+OWESJpcebrBUbXPGZyQQ==} + '@oxfmt/binding-linux-arm64-musl@0.42.0': + resolution: {integrity: sha512-+JA0YMlSdDqmacygGi2REp57c3fN+tzARD8nwsukx9pkCHK+6DkbAA9ojS4lNKsiBjIW8WWa0pBrBWhdZEqfuw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-ppc64-gnu@0.36.0': - resolution: {integrity: sha512-3EuoyB8x9x8ysYJjbEO/M9fkSk72zQKnXCvpZMDHXlnY36/1qMp55Nm0PrCwjGO/1pen5hdOVkz9WmP3nAp2IQ==} + '@oxfmt/binding-linux-ppc64-gnu@0.42.0': + resolution: {integrity: sha512-VfnET0j4Y5mdfCzh5gBt0NK28lgn5DKx+8WgSMLYYeSooHhohdbzwAStLki9pNuGy51y4I7IoW8bqwAaCMiJQg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-gnu@0.36.0': - resolution: {integrity: sha512-MpY3itLwpGh8dnywtrZtaZ604T1m715SydCKy0+qTxetv+IHzuA+aO/AGzrlzUNYZZmtWtmDBrChZGibvZxbRQ==} + '@oxfmt/binding-linux-riscv64-gnu@0.42.0': + resolution: {integrity: sha512-gVlCbmBkB0fxBWbhBj9rcxezPydsQHf4MFKeHoTSPicOQ+8oGeTQgQ8EeesSybWeiFPVRx3bgdt4IJnH6nOjAA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-musl@0.36.0': - resolution: {integrity: sha512-mmDhe4Vtx+XwQPRPn/V25+APnkApYgZ23q+6GVsNYY98pf3aU0aI3Me96pbRs/AfJ1jIiGC+/6q71FEu8dHcHw==} + '@oxfmt/binding-linux-riscv64-musl@0.42.0': + resolution: {integrity: sha512-zN5OfstL0avgt/IgvRu0zjQzVh/EPkcLzs33E9LMAzpqlLWiPWeMDZyMGFlSRGOdDjuNmlZBCgj0pFnK5u32TQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-s390x-gnu@0.36.0': - resolution: {integrity: sha512-AYXhU+DmNWLSnvVwkHM92fuYhogtVHab7UQrPNaDf1sxadugg9gWVmcgJDlIwxJdpk5CVW/TFvwUKwI432zhhA==} + '@oxfmt/binding-linux-s390x-gnu@0.42.0': + resolution: {integrity: sha512-9X6+H2L0qMc2sCAgO9HS03bkGLMKvOFjmEdchaFlany3vNZOjnVui//D8k/xZAtQv2vaCs1reD5KAgPoIU4msA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-gnu@0.36.0': - resolution: {integrity: sha512-H16QhhQ3usoakMleiAAQ2mg0NsBDAdyE9agUgfC8IHHh3jZEbr0rIKwjEqwbOHK5M0EmfhJmr+aGO/MgZPsneA==} + '@oxfmt/binding-linux-x64-gnu@0.42.0': + resolution: {integrity: sha512-BajxJ6KQvMMdpXGPWhBGyjb2Jvx4uec0w+wi6TJZ6Tv7+MzPwe0pO8g5h1U0jyFgoaF7mDl6yKPW3ykWcbUJRw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-musl@0.36.0': - resolution: {integrity: sha512-EFFGkixA39BcmHiCe2ECdrq02D6FCve5ka6ObbvrheXl4V+R0U/E+/uLyVx1X65LW8TA8QQHdnbdDallRekohw==} + '@oxfmt/binding-linux-x64-musl@0.42.0': + resolution: {integrity: sha512-0wV284I6vc5f0AqAhgAbHU2935B4bVpncPoe5n/WzVZY/KnHgqxC8iSFGeSyLWEgstFboIcWkOPck7tqbdHkzA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxfmt/binding-openharmony-arm64@0.36.0': - resolution: {integrity: sha512-zr/t369wZWFOj1qf06Z5gGNjFymfUNDrxKMmr7FKiDRVI1sNsdKRCuRL4XVjtcptKQ+ao3FfxLN1vrynivmCYg==} + '@oxfmt/binding-openharmony-arm64@0.42.0': + resolution: {integrity: sha512-p4BG6HpGnhfgHk1rzZfyR6zcWkE7iLrWxyehHfXUy4Qa5j3e0roglFOdP/Nj5cJJ58MA3isQ5dlfkW2nNEpolw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxfmt/binding-win32-arm64-msvc@0.36.0': - resolution: {integrity: sha512-FxO7UksTv8h4olzACgrqAXNF6BP329+H322323iDrMB5V/+a1kcAw07fsOsUmqNrb9iJBsCQgH/zqcqp5903ag==} + '@oxfmt/binding-win32-arm64-msvc@0.42.0': + resolution: {integrity: sha512-mn//WV60A+IetORDxYieYGAoQso4KnVRRjORDewMcod4irlRe0OSC7YPhhwaexYNPQz/GCFk+v9iUcZ2W22yxQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxfmt/binding-win32-ia32-msvc@0.36.0': - resolution: {integrity: sha512-OjoMQ89H01M0oLMfr/CPNH1zi48ZIwxAKObUl57oh7ssUBNDp/2Vjf7E1TQ8M4oj4VFQ/byxl2SmcPNaI2YNDg==} + '@oxfmt/binding-win32-ia32-msvc@0.42.0': + resolution: {integrity: sha512-3gWltUrvuz4LPJXWivoAxZ28Of2O4N7OGuM5/X3ubPXCEV8hmgECLZzjz7UYvSDUS3grfdccQwmjynm+51EFpw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxfmt/binding-win32-x64-msvc@0.36.0': - resolution: {integrity: sha512-MoyeQ9S36ZTz/4bDhOKJgOBIDROd4dQ5AkT9iezhEaUBxAPdNX9Oq0jD8OSnCj3G4wam/XNxVWKMA52kmzmPtQ==} + '@oxfmt/binding-win32-x64-msvc@0.42.0': + resolution: {integrity: sha512-Wg4TMAfQRL9J9AZevJ/ZNy3uyyDztDYQtGr4P8UyyzIhLhFrdSmz1J/9JT+rv0fiCDLaFOBQnj3f3K3+a5PzDQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.51.0': - resolution: {integrity: sha512-jJYIqbx4sX+suIxWstc4P7SzhEwb4ArWA2KVrmEuu9vH2i0qM6QIHz/ehmbGE4/2fZbpuMuBzTl7UkfNoqiSgw==} + '@oxlint/binding-android-arm-eabi@1.59.0': + resolution: {integrity: sha512-etYDw/UaEv936AQUd/CRMBVd+e+XuuU6wC+VzOv1STvsTyZenLChepLWqLtnyTTp4YMlM22ypzogDDwqYxv5cg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.51.0': - resolution: {integrity: sha512-GtXyBCcH4ti98YdiMNCrpBNGitx87EjEWxevnyhcBK12k/Vu4EzSB45rzSC4fGFUD6sQgeaxItRCEEWeVwPafw==} + '@oxlint/binding-android-arm64@1.59.0': + resolution: {integrity: sha512-TgLc7XVLKH2a4h8j3vn1MDjfK33i9MY60f/bKhRGWyVzbk5LCZ4X01VZG7iHrMmi5vYbAp8//Ponigx03CLsdw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.51.0': - resolution: {integrity: sha512-3QJbeYaMHn6Bh2XeBXuITSsbnIctyTjvHf5nRjKYrT9pPeErNIpp5VDEeAXC0CZSwSVTsc8WOSDwgrAI24JolQ==} + '@oxlint/binding-darwin-arm64@1.59.0': + resolution: {integrity: sha512-DXyFPf5ZKldMLloRHx/B9fsxsiTQomaw7cmEW3YIJko2HgCh+GUhp9gGYwHrqlLJPsEe3dYj9JebjX92D3j3AA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.51.0': - resolution: {integrity: sha512-NzErhMaTEN1cY0E8C5APy74lw5VwsNfJfVPBMWPVQLqAbO0k4FFLjvHURvkUL+Y18Wu+8Vs1kbqPh2hjXYA4pg==} + '@oxlint/binding-darwin-x64@1.59.0': + resolution: {integrity: sha512-LgvrsdgVLX1qWqIEmNsSmMXJhpAWdtUQ0M+oR0CySwi+9IHWyOGuIL8w8+u/kbZNMyZr4WUyYB5i0+D+AKgkLg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.51.0': - resolution: {integrity: sha512-msAIh3vPAoKoHlOE/oe6Q5C/n9umypv/k81lED82ibrJotn+3YG2Qp1kiR8o/Dg5iOEU97c6tl0utxcyFenpFw==} + '@oxlint/binding-freebsd-x64@1.59.0': + resolution: {integrity: sha512-bOJhqX/ny4hrFuTPlyk8foSRx/vLRpxJh0jOOKN2NWW6FScXHPAA5rQbrwdQPcgGB5V8Ua51RS03fke8ssBcug==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.51.0': - resolution: {integrity: sha512-CqQPcvqYyMe9ZBot2stjGogEzk1z8gGAngIX7srSzrzexmXixwVxBdFZyxTVM0CjGfDeV+Ru0w25/WNjlMM2Hw==} + '@oxlint/binding-linux-arm-gnueabihf@1.59.0': + resolution: {integrity: sha512-vVUXxYMF9trXCsz4m9H6U0IjehosVHxBzVgJUxly1uz4W1PdDyicaBnpC0KRXsHYretLVe+uS9pJy8iM57Kujw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.51.0': - resolution: {integrity: sha512-dstrlYQgZMnyOssxSbolGCge/sDbko12N/35RBNuqLpoPbft2aeBidBAb0dvQlyBd9RJ6u8D4o4Eh8Un6iTgyQ==} + '@oxlint/binding-linux-arm-musleabihf@1.59.0': + resolution: {integrity: sha512-TULQW8YBPGRWg5yZpFPL54HLOnJ3/HiX6VenDPi6YfxB/jlItwSMFh3/hCeSNbh+DAMaE1Py0j5MOaivHkI/9Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.51.0': - resolution: {integrity: sha512-QEjUpXO7d35rP1/raLGGbAsBLLGZIzV3ZbeSjqWlD3oRnxpRIZ6iL4o51XQHkconn3uKssc+1VKdtHJ81BBhDA==} + '@oxlint/binding-linux-arm64-gnu@1.59.0': + resolution: {integrity: sha512-Gt54Y4eqSgYJ90xipm24xeyaPV854706o/kiT8oZvUt3VDY7qqxdqyGqchMaujd87ib+/MXvnl9WkK8Cc1BExg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.51.0': - resolution: {integrity: sha512-YSJua5irtG4DoMAjUapDTPhkQLHhBIY0G9JqlZS6/SZPzqDkPku/1GdWs0D6h/wyx0Iz31lNCfIaWKBQhzP0wQ==} + '@oxlint/binding-linux-arm64-musl@1.59.0': + resolution: {integrity: sha512-3CtsKp7NFB3OfqQzbuAecrY7GIZeiv7AD+xutU4tefVQzlfmTI7/ygWLrvkzsDEjTlMq41rYHxgsn6Yh8tybmA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.51.0': - resolution: {integrity: sha512-7L4Wj2IEUNDETKssB9IDYt16T6WlF+X2jgC/hBq3diGHda9vJLpAgb09+D3quFq7TdkFtI7hwz/jmuQmQFPc1Q==} + '@oxlint/binding-linux-ppc64-gnu@1.59.0': + resolution: {integrity: sha512-K0diOpT3ncDmOfl9I1HuvpEsAuTxkts0VYwIv/w6Xiy9CdwyPBVX88Ga9l8VlGgMrwBMnSY4xIvVlVY/fkQk7Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.51.0': - resolution: {integrity: sha512-cBUHqtOXy76G41lOB401qpFoKx1xq17qYkhWrLSM7eEjiHM9sOtYqpr6ZdqCnN9s6ZpzudX4EkeHOFH2E9q0vA==} + '@oxlint/binding-linux-riscv64-gnu@1.59.0': + resolution: {integrity: sha512-xAU7+QDU6kTJJ7mJLOGgo7oOjtAtkKyFZ0Yjdb5cEo3DiCCPFLvyr08rWiQh6evZ7RiUTf+o65NY/bqttzJiQQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.51.0': - resolution: {integrity: sha512-WKbg8CysgZcHfZX0ixQFBRSBvFZUHa3SBnEjHY2FVYt2nbNJEjzTxA3ZR5wMU0NOCNKIAFUFvAh5/XJKPRJuJg==} + '@oxlint/binding-linux-riscv64-musl@1.59.0': + resolution: {integrity: sha512-KUmZmKlTTyauOnvUNVxK7G40sSSx0+w5l1UhaGsC6KPpOYHenx2oqJTnabmpLJicok7IC+3Y6fXAUOMyexaeJQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.51.0': - resolution: {integrity: sha512-N1QRUvJTxqXNSu35YOufdjsAVmKVx5bkrggOWAhTWBc3J4qjcBwr1IfyLh/6YCg8sYRSR1GraldS9jUgJL/U4A==} + '@oxlint/binding-linux-s390x-gnu@1.59.0': + resolution: {integrity: sha512-4usRxC8gS0PGdkHnRmwJt/4zrQNZyk6vL0trCxwZSsAKM+OxhB8nKiR+mhjdBbl8lbMh2gc3bZpNN/ik8c4c2A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.51.0': - resolution: {integrity: sha512-e0Mz0DizsCoqNIjeOg6OUKe8JKJWZ5zZlwsd05Bmr51Jo3AOL4UJnPvwKumr4BBtBrDZkCmOLhCvDGm95nJM2g==} + '@oxlint/binding-linux-x64-gnu@1.59.0': + resolution: {integrity: sha512-s/rNE2gDmbwAOOP493xk2X7M8LZfI1LJFSSW1+yanz3vuQCFPiHkx4GY+O1HuLUDtkzGlhtMrIcxxzyYLv308w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.51.0': - resolution: {integrity: sha512-wD8HGTWhYBKXvRDvoBVB1y+fEYV01samhWQSy1Zkxq2vpezvMnjaFKRuiP6tBNITLGuffbNDEXOwcAhJ3gI5Ug==} + '@oxlint/binding-linux-x64-musl@1.59.0': + resolution: {integrity: sha512-+yYj1udJa2UvvIUmEm0IcKgc0UlPMgz0nsSTvkPL2y6n0uU5LgIHSwVu4AHhrve6j9BpVSoRksnz8c9QcvITJA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.51.0': - resolution: {integrity: sha512-5NSwQ2hDEJ0GPXqikjWtwzgAQCsS7P9aLMNenjjKa+gknN3lTCwwwERsT6lKXSirfU3jLjexA2XQvQALh5h27w==} + '@oxlint/binding-openharmony-arm64@1.59.0': + resolution: {integrity: sha512-bUplUb48LYsB3hHlQXP2ZMOenpieWoOyppLAnnAhuPag3MGPnt+7caxE3w/Vl9wpQsTA3gzLntQi9rxWrs7Xqg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.51.0': - resolution: {integrity: sha512-JEZyah1M0RHMw8d+jjSSJmSmO8sABA1J1RtrHYujGPeCkYg1NeH0TGuClpe2h5QtioRTaF57y/TZfn/2IFV6fA==} + '@oxlint/binding-win32-arm64-msvc@1.59.0': + resolution: {integrity: sha512-/HLsLuz42rWl7h7ePdmMTpHm2HIDmPtcEMYgm5BBEHiEiuNOrzMaUpd2z7UnNni5LGN9obJy2YoAYBLXQwazrA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.51.0': - resolution: {integrity: sha512-q3cEoKH6kwjz/WRyHwSf0nlD2F5Qw536kCXvmlSu+kaShzgrA0ojmh45CA81qL+7udfCaZL2SdKCZlLiGBVFlg==} + '@oxlint/binding-win32-ia32-msvc@1.59.0': + resolution: {integrity: sha512-rUPy+JnanpPwV/aJCPnxAD1fW50+XPI0VkWr7f0vEbqcdsS8NpB24Rw6RsS7SdpFv8Dw+8ugCwao5nCFbqOUSg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.51.0': - resolution: {integrity: sha512-Q14+fOGb9T28nWF/0EUsYqERiRA7cl1oy4TJrGmLaqhm+aO2cV+JttboHI3CbdeMCAyDI1+NoSlrM7Melhp/cw==} + '@oxlint/binding-win32-x64-msvc@1.59.0': + resolution: {integrity: sha512-xkE7puteDS/vUyRngLXW0t8WgdWoS/tfxXjhP/P7SMqPDx+hs44SpssO3h3qmTqECYEuXBUPzcAw5257Ka+ofA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@playwright/test@1.58.2': - resolution: {integrity: sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==} + '@playwright/test@1.59.1': + resolution: {integrity: sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==} engines: {node: '>=18'} hasBin: true + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@protobufjs/aspromise@1.1.2': resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} @@ -1350,92 +1295,106 @@ packages: react-redux: optional: true - '@rolldown/binding-android-arm64@1.0.0-beta.53': - resolution: {integrity: sha512-Ok9V8o7o6YfSdTTYA/uHH30r3YtOxLD6G3wih/U9DO0ucBBFq8WPt/DslU53OgfteLRHITZny9N/qCUxMf9kjQ==} + '@rolldown/binding-android-arm64@1.0.0-rc.11': + resolution: {integrity: sha512-SJ+/g+xNnOh6NqYxD0V3uVN4W3VfnrGsC9/hoglicgTNfABFG9JjISvkkU0dNY84MNHLWyOgxP9v9Y9pX4S7+A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-beta.53': - resolution: {integrity: sha512-yIsKqMz0CtRnVa6x3Pa+mzTihr4Ty+Z6HfPbZ7RVbk1Uxnco4+CUn7Qbm/5SBol1JD/7nvY8rphAgyAi7Lj6Vg==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.11': + resolution: {integrity: sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-beta.53': - resolution: {integrity: sha512-GTXe+mxsCGUnJOFMhfGWmefP7Q9TpYUseHvhAhr21nCTgdS8jPsvirb0tJwM3lN0/u/cg7bpFNa16fQrjKrCjQ==} + '@rolldown/binding-darwin-x64@1.0.0-rc.11': + resolution: {integrity: sha512-39Ks6UvIHq4rEogIfQBoBRusj0Q0nPVWIvqmwBLaT6aqQGIakHdESBVOPRRLacy4WwUPIx4ZKzfZ9PMW+IeyUQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-beta.53': - resolution: {integrity: sha512-9Tmp7bBvKqyDkMcL4e089pH3RsjD3SUungjmqWtyhNOxoQMh0fSmINTyYV8KXtE+JkxYMPWvnEt+/mfpVCkk8w==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.11': + resolution: {integrity: sha512-jfsm0ZHfhiqrvWjJAmzsqiIFPz5e7mAoCOPBNTcNgkiid/LaFKiq92+0ojH+nmJmKYkre4t71BWXUZDNp7vsag==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': - resolution: {integrity: sha512-a1y5fiB0iovuzdbjUxa7+Zcvgv+mTmlGGC4XydVIsyl48eoxgaYkA3l9079hyTyhECsPq+mbr0gVQsFU11OJAQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.11': + resolution: {integrity: sha512-zjQaUtSyq1nVe3nxmlSCuR96T1LPlpvmJ0SZy0WJFEsV4kFbXcq2u68L4E6O0XeFj4aex9bEauqjW8UQBeAvfQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': - resolution: {integrity: sha512-bpIGX+ov9PhJYV+wHNXl9rzq4F0QvILiURn0y0oepbQx+7stmQsKA0DhPGwmhfvF856wq+gbM8L92SAa/CBcLg==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': - resolution: {integrity: sha512-bGe5EBB8FVjHBR1mOLOPEFg1Lp3//7geqWkU5NIhxe+yH0W8FVrQ6WRYOap4SUTKdklD/dC4qPLREkMMQ855FA==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.11': + resolution: {integrity: sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': - resolution: {integrity: sha512-qL+63WKVQs1CMvFedlPt0U9PiEKJOAL/bsHMKUDS6Vp2Q+YAv/QLPu8rcvkfIMvQ0FPU2WL0aX4eWwF6e/GAnA==} + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-ZlFgw46NOAGMgcdvdYwAGu2Q+SLFA9LzbJLW+iyMOJyhj5wk6P3KEE9Gct4xWwSzFoPI7JCdYmYMzVtlgQ+zfw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-hIOYmuT6ofM4K04XAZd3OzMySEO4K0/nc9+jmNcxNAxRi6c5UWpqfw3KMFV4MVFWL+jQsSh+bGw2VqmaPMTLyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': + resolution: {integrity: sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': - resolution: {integrity: sha512-VGl9JIGjoJh3H8Mb+7xnVqODajBmrdOOb9lxWXdcmxyI+zjB2sux69br0hZJDTyLJfvBoYm439zPACYbCjGRmw==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.11': + resolution: {integrity: sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': - resolution: {integrity: sha512-B4iIserJXuSnNzA5xBLFUIjTfhNy7d9sq4FUMQY3GhQWGVhS2RWWzzDnkSU6MUt7/aHUrep0CdQfXUJI9D3W7A==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.11': + resolution: {integrity: sha512-mcp3Rio2w72IvdZG0oQ4bM2c2oumtwHfUfKncUM6zGgz0KgPz4YmDPQfnXEiY5t3+KD/i8HG2rOB/LxdmieK2g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-beta.53': - resolution: {integrity: sha512-BUjAEgpABEJXilGq/BPh7jeU3WAJ5o15c1ZEgHaDWSz3LB881LQZnbNJHmUiM4d1JQWMYYyR1Y490IBHi2FPJg==} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.11': + resolution: {integrity: sha512-LXk5Hii1Ph9asuGRjBuz8TUxdc1lWzB7nyfdoRgI0WGPZKmCxvlKk8KfYysqtr4MfGElu/f/pEQRh8fcEgkrWw==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': - resolution: {integrity: sha512-s27uU7tpCWSjHBnxyVXHt3rMrQdJq5MHNv3BzsewCIroIw3DJFjMH1dzCPPMUFxnh1r52Nf9IJ/eWp6LDoyGcw==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11': + resolution: {integrity: sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': - resolution: {integrity: sha512-cjWL/USPJ1g0en2htb4ssMjIycc36RvdQAx1WlXnS6DpULswiUTVXPDesTifSKYSyvx24E0YqQkEm0K/M2Z/AA==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.11': + resolution: {integrity: sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-beta.53': - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + '@rolldown/pluginutils@1.0.0-rc.11': + resolution: {integrity: sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==} - '@rolldown/pluginutils@1.0.0-rc.3': - resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + '@rolldown/pluginutils@1.0.0-rc.7': + resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==} '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} @@ -1627,23 +1586,23 @@ packages: '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} - '@storybook/addon-a11y@10.2.17': - resolution: {integrity: sha512-J0ogEc4/XFC+Ytz+X1we6TOKreEk/shgUs/mtxdsLa0xJ6bp2n2OQPSjNtQHH/nK4SRBSfHWPm8ztfcXTzeG9w==} + '@storybook/addon-a11y@10.3.4': + resolution: {integrity: sha512-TylBS2+MUPRfgzBKiygL1JoUBnTqEKo5oCEfjHneJZKzYE1UNgdMdk/fiyanaGKTZBKBxWbShxZhT2gLs8kqMA==} peerDependencies: - storybook: ^10.2.17 + storybook: ^10.3.4 - '@storybook/addon-docs@10.2.17': - resolution: {integrity: sha512-c414xi7rxlaHn92qWOxtEkcOMm0/+cvBui0gUsgiWOZOM8dHChGZ/RjMuf1pPDyOrSsybLsPjZhP0WthsMDkdQ==} + '@storybook/addon-docs@10.3.4': + resolution: {integrity: sha512-ohS8fX8UIP3LN6+mDZJLCDS4Qd2rsmGwes6V6fD0sbLOmIyCVY5y68r6NHMMGJKFRwadDQOmtOt8Vc6snExrIQ==} peerDependencies: - storybook: ^10.2.17 + storybook: ^10.3.4 - '@storybook/addon-vitest@10.2.17': - resolution: {integrity: sha512-47mo952M/dHZQn1yTVMEUnri5KuIwWynPqamv6Q9KFXrSPOnBt/8IdrTcPUXFo5XO1ZmIWclgQjJtIvGe4z+ag==} + '@storybook/addon-vitest@10.3.4': + resolution: {integrity: sha512-lSn8opaHVzDxLtMy28FnSkyx6uP1oQVnGzodNunTjrbJ8Ue8JVK+fjWtC/JfErIio0avlq79mgC5tfHSWlPr9w==} peerDependencies: '@vitest/browser': ^3.0.0 || ^4.0.0 '@vitest/browser-playwright': ^4.0.0 '@vitest/runner': ^3.0.0 || ^4.0.0 - storybook: ^10.2.17 + storybook: ^10.3.4 vitest: ^3.0.0 || ^4.0.0 peerDependenciesMeta: '@vitest/browser': @@ -1655,18 +1614,18 @@ packages: vitest: optional: true - '@storybook/builder-vite@10.2.17': - resolution: {integrity: sha512-m/OBveTLm5ds/tUgHmmbKzgSi/oeCpQwm5rZa49vP2BpAd41Q7ER6TzkOoISzPoNNMAcbVmVc5vn7k6hdbPSHw==} + '@storybook/builder-vite@10.3.4': + resolution: {integrity: sha512-dNQyBZpBKvwmhSTpjrsuxxY8FqFCh0hgu5+46h2WbgQ2Te3pO458heWkGb+QO7mC6FmkXO6j6zgYzXticD6F2A==} peerDependencies: - storybook: ^10.2.17 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + storybook: ^10.3.4 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/csf-plugin@10.2.17': - resolution: {integrity: sha512-crHH8i/4mwzeXpWRPgwvwX2vjytW42zyzTRySUax5dTU8o9sjk4y+Z9hkGx3Nmu1TvqseS8v1Z20saZr/tQcWw==} + '@storybook/csf-plugin@10.3.4': + resolution: {integrity: sha512-WPP0Z39o82WiohPkhPOs6z+9yJ+bVvqPz4d+QUPfE6FMvOOBLojlwOcGx6Xmclyn5H/CKwywFrjuz4mBO/nHhA==} peerDependencies: esbuild: '*' rollup: '*' - storybook: ^10.2.17 + storybook: ^10.3.4 vite: '*' webpack: '*' peerDependenciesMeta: @@ -1688,27 +1647,27 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@storybook/react-dom-shim@10.2.17': - resolution: {integrity: sha512-x9Kb7eUSZ1zGsEw/TtWrvs1LwWIdNp8qoOQCgPEjdB07reSJcE8R3+ASWHJThmd4eZf66ZALPJyerejake4Osw==} + '@storybook/react-dom-shim@10.3.4': + resolution: {integrity: sha512-VIm9YzreGubnOtQOZ6iqEfj6KncHvAkrCR/IilqnJq7DidPWuykrFszyajTASRMiY+p+TElOW+O1PGpv55qNGw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.17 + storybook: ^10.3.4 - '@storybook/react-vite@10.2.17': - resolution: {integrity: sha512-E/1hNmxVsjy9l3TuaNufSqkdz8saTJUGEs8GRCjKlF7be2wljIwewUxjAT3efk+bxOCw76ZmqGHk6MnRa3y7Gw==} + '@storybook/react-vite@10.3.4': + resolution: {integrity: sha512-xaMt7NdvlAb+CwXn5TOiluQ+0WkkMN3mZhCThocpblWGoyfmHH7bgQ5ZwzT+IIp8DGOsAi/HkNmSyS7Z8HRLJg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.17 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + storybook: ^10.3.4 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@storybook/react@10.2.17': - resolution: {integrity: sha512-875AVMYil2X9Civil6GFZ8koIzlKxcXbl2eJ7+/GPbhIonTNmwx0qbWPHttjZXUvFuQ4RRtb9KkBwy4TCb/LeA==} + '@storybook/react@10.3.4': + resolution: {integrity: sha512-I5ifYqjrqyuhOFjalpy47kMKMXX7QU/qmHj0h/547s9Bg6sEU7xRhJnneXx1RJsEJTySjC4SmGfEU+FJz4Foiw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^10.2.17 + storybook: ^10.3.4 typescript: '>= 4.9.x' peerDependenciesMeta: typescript: @@ -1718,69 +1677,69 @@ packages: resolution: {integrity: sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ==} engines: {node: '>=16.0.0'} - '@tailwindcss/node@4.2.1': - resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==} + '@tailwindcss/node@4.2.2': + resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} - '@tailwindcss/oxide-android-arm64@4.2.1': - resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==} + '@tailwindcss/oxide-android-arm64@4.2.2': + resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.2.1': - resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==} + '@tailwindcss/oxide-darwin-arm64@4.2.2': + resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.2.1': - resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==} + '@tailwindcss/oxide-darwin-x64@4.2.2': + resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.2.1': - resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==} + '@tailwindcss/oxide-freebsd-x64@4.2.2': + resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': - resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': - resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': - resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': - resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.2.1': - resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.2.1': - resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -1791,64 +1750,70 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': - resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==} + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': - resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==} + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.2.1': - resolution: {integrity: sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==} + '@tailwindcss/oxide@4.2.2': + resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} engines: {node: '>= 20'} - '@tailwindcss/vite@4.2.1': - resolution: {integrity: sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==} + '@tailwindcss/vite@4.2.2': + resolution: {integrity: sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==} peerDependencies: - vite: ^5.2.0 || ^6 || ^7 + vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/ai-anthropic@0.6.0': - resolution: {integrity: sha512-xVKq6Co58etETfxrCfLzESyxrmR28D9+sh6FH/mPTeHWnOt3Tyb12OqOD5Gu2Ox4nZKWviHbmLKxavR4iFSYag==} + '@tanstack/ai-anthropic@0.7.2': + resolution: {integrity: sha512-ZV01BPuplBOhnnzPpFqoPBWLQNGFSBPkIUaE23NqGrjzyKfeWed4mkTl/Q5cg2rF1VDTS8iOYXWME206kHuiPA==} peerDependencies: - '@tanstack/ai': ^0.6.1 + '@tanstack/ai': ^0.10.0 zod: ^4.0.0 - '@tanstack/ai-client@0.5.3': - resolution: {integrity: sha512-Q7Ta9B0kUWP4tLmYeBLE33efwyeBvXx8l+z1wQWsHn4wiZRnkkOtRhBnrI33uFWKSV+TqIOoxtOw7/+r/iFMeQ==} + '@tanstack/ai-client@0.7.7': + resolution: {integrity: sha512-Z4BcVgtYMaeSp46UcRzKWvG2SYC3M0VW2jYaWGKRrTouQ71+3C0DREZr8MYZr1gAkCCcQqqWPejKkYdJ7+cLSQ==} - '@tanstack/ai-devtools-core@0.3.8': - resolution: {integrity: sha512-RVg0H2iMriBqopFcjees0Dbz1VbQSShahuuxzuztv9z2tUDGxI8LbwIFc8Gh0iO5066tyXaAlgRDhQtqidDJ/g==} + '@tanstack/ai-devtools-core@0.3.17': + resolution: {integrity: sha512-TI06Nt+zxnPthosnDtmKMZJToR69CnFazMkd7ZeSJ9vSKJ8PYaHP1m4sbOGTRCVJu1dCAM4Uz6KTQILIzALeeQ==} + + '@tanstack/ai-event-client@0.2.0': + resolution: {integrity: sha512-1O7PbBlSo0gCrv4/bmOvnemZ6Cvf+kZmHqug19JEz8Bj4/anup3GkwvKBk8XzEvPIB+vQb4GL9TLN4Tfo6ZCkA==} + peerDependencies: + '@tanstack/ai': 0.10.0 - '@tanstack/ai-gemini@0.8.0': - resolution: {integrity: sha512-SjVoue+hWBmo1JlkfWQPSgdLplAmino9gmv6KmZSfE8UFmMaE2AGDGGIXd4W2W1m/WjaK8fr/AHfC7Z0pBJ2Dw==} + '@tanstack/ai-gemini@0.8.5': + resolution: {integrity: sha512-8WP9TaC157kSORscex1HAvOBlnc4x3mqjs/MiymKeEBABe0AQ3FXmsyxQY7feQ2IuBWBLYPCAaFyKpPkRp7w1A==} peerDependencies: - '@tanstack/ai': ^0.6.2 + '@tanstack/ai': ^0.10.0 - '@tanstack/ai-ollama@0.6.0': - resolution: {integrity: sha512-fWa2PfPZ4xeYdN8PUEoiFx30RUaLhLISOOMfux3MPYKW6lNu+04TDHWC6mKP5JXTCc1wVxpSpeVjBfwbrsnu9w==} + '@tanstack/ai-ollama@0.6.4': + resolution: {integrity: sha512-ZdbXM0SJxTPL09DaiYh+xqrJ7nSFc6zl7gYQ5S02tmDiQNBHVCWJmRVhaSdUDtJf7+xXiTL7Bff/dndSNMWU4g==} peerDependencies: - '@tanstack/ai': ^0.6.1 + '@tanstack/ai': ^0.10.0 - '@tanstack/ai-openai@0.6.0': - resolution: {integrity: sha512-CSDgYr63ftw+nGb1IpB+3qIOngLE1pZjasiaeOdDQ6CbSEJDNcR7VNmyTx3RsoTh9fChKbLhJzYpem1Mpag2og==} + '@tanstack/ai-openai@0.7.3': + resolution: {integrity: sha512-xdxTR7E/BzeQcFte/chDA//2WpZQqDQF4op1TgKNoaTqffW9+JMlSubaZbMkawtJoImVCGjZoPVkUfb8aRldNA==} peerDependencies: - '@tanstack/ai': ^0.6.1 + '@tanstack/ai': ^0.10.0 + '@tanstack/ai-client': ^0.7.7 zod: ^4.0.0 - '@tanstack/ai-react@0.6.3': - resolution: {integrity: sha512-AHvl36+N3J1di4jseh8sB0tW16eCA+5aL/C1mIs7ARyvVkZR3XzxUSr4DdcfoHt9eDar0EWXnYDhJrB8fIO9Ig==} + '@tanstack/ai-react@0.7.8': + resolution: {integrity: sha512-0xhJk2CF5ZFcxIsnhXsnPCkP++TG0ra9vrIT8M28O5USEZVyv0nbQEHWZm7Sm4t1eEk6rjPFohsz+LTnzy6Zjg==} peerDependencies: - '@tanstack/ai': ^0.6.2 + '@tanstack/ai': ^0.10.0 '@types/react': '>=18.0.0' react: '>=18.0.0' - '@tanstack/ai@0.6.2': - resolution: {integrity: sha512-CEldlHRvTzSTZ98bWvVg4TLqLCsSIudqummJ5BEzmdr9igzIiDyAmM9GoohR89iRkeCFsWnlGGiSnN1uIWcbfg==} + '@tanstack/ai@0.10.0': + resolution: {integrity: sha512-b1GDenJs2udQfjFMnAWZ6WX9RLg04O9wC85V4cSD8phuVMJscs+Qp0UkNj7FTc+V1ggqf4Pz1jLFfqjLO2z3mg==} engines: {node: '>=18'} '@tanstack/devtools-client@0.0.6': @@ -1859,19 +1824,21 @@ packages: resolution: {integrity: sha512-cNnJ89Q021Zf883rlbBTfsaxTfi2r73/qejGtyTa7ksErF3hyDyAq1aTbo5crK9dAL7zSHh9viKY1BtMls1QOA==} engines: {node: '>=18'} - '@tanstack/devtools-event-client@0.4.1': - resolution: {integrity: sha512-GRxmPw4OHZ2oZeIEUkEwt/NDvuEqzEYRAjzUVMs+I0pd4C7k1ySOiuJK2CqF+K/yEAR3YZNkW3ExrpDarh9Vwg==} + '@tanstack/devtools-event-client@0.4.3': + resolution: {integrity: sha512-OZI6QyULw0FI0wjgmeYzCIfbgPsOEzwJtCpa69XrfLMtNXLGnz3d/dIabk7frg0TmHo+Ah49w5I4KC7Tufwsvw==} engines: {node: '>=18'} + hasBin: true - '@tanstack/devtools-ui@0.5.0': - resolution: {integrity: sha512-nNZ14054n31fWB61jtWhZYLRdQ3yceCE3G/RINoINUB0RqIGZAIm9DnEDwOTAOfqt4/a/D8vNk8pJu6RQUp74g==} + '@tanstack/devtools-ui@0.5.1': + resolution: {integrity: sha512-T9JjAdqMSnxsVO6AQykD5vhxPF4iFLKtbYxee/bU3OLlk446F5C1220GdCmhDSz7y4lx+m8AvIS0bq6zzvdDUA==} engines: {node: '>=18'} peerDependencies: solid-js: '>=1.9.7' - '@tanstack/devtools-utils@0.3.2': - resolution: {integrity: sha512-fu9wmE2bHigiE1Lc5RFSchgdN35wX15TqfB4O4vJa6SqX9JH2ov57J60u18lheROaBiteloPzcCbkLNpx0aacw==} + '@tanstack/devtools-utils@0.4.0': + resolution: {integrity: sha512-KsGzYhA8L/fCNgyyMyoUy+TKtx+DjNbzWwqH6wXL48Llzo7kvV9RynYJlaO8Qkzwm+NdHXSgsljQNjQ3CKPpZA==} engines: {node: '>=18'} + hasBin: true peerDependencies: '@types/react': '>=17.0.0' preact: '>=10.0.0' @@ -1890,23 +1857,25 @@ packages: vue: optional: true - '@tanstack/devtools-vite@0.5.3': - resolution: {integrity: sha512-S7VK2GthBrEkto0UVODx31IAvxTFUK0RGH6aZEZixsohYTytTdrwcLmPKEREwFrRN8Qc2mIqfBhENPbRG1RFXA==} + '@tanstack/devtools-vite@0.6.0': + resolution: {integrity: sha512-h0r0ct7zlrgjkhmn4QW6wRjgUXd4JMs+r7gtx+BXo9f5H9Y+jtUdtvC0rnZcPto6gw/9yMUq7yOmMK5qDWRExg==} engines: {node: '>=18'} + hasBin: true peerDependencies: - vite: ^6.0.0 || ^7.0.0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@tanstack/devtools@0.10.11': - resolution: {integrity: sha512-Nk1rHsv6S/5Krzz+uL5jldW9gKb3s6rkkVl1L9oVYHNClKthbrk2hGef4Di6yj449QIOqVExTdDujjQ4roq1dg==} + '@tanstack/devtools@0.11.1': + resolution: {integrity: sha512-g3nHgVP76kT9190d6O32AjANoEnujLEB+51PDtBzlah8hvKeEygK53cunN+HXhjlfhM4PoOCi8/B96cdJVSnLg==} engines: {node: '>=18'} + hasBin: true peerDependencies: solid-js: '>=1.9.7' - '@tanstack/form-core@1.28.4': - resolution: {integrity: sha512-2eox5ePrJ6kvA1DXD5QHk/GeGr3VFZ0uYR63UgQOe7bUg6h1JfXaIMqTjZK9sdGyE4oRNqFpoW54H0pZM7nObQ==} + '@tanstack/form-core@1.28.6': + resolution: {integrity: sha512-4zroxL6VDj5O+w7l3dYZnUeL/h30KtNSV7UWzKAL7cl+8clMFdISPDlDlluS37As7oqvPVKo8B83VlIBvgmRog==} - '@tanstack/history@1.161.4': - resolution: {integrity: sha512-Kp/WSt411ZWYvgXy6uiv5RmhHrz9cAml05AQPrtdAp7eUqvIDbMGPnML25OKbzR3RJ1q4wgENxDTvlGPa9+Mww==} + '@tanstack/history@1.161.6': + resolution: {integrity: sha512-NaOGLRrddszbQj9upGat6HG/4TKvXLvu+osAIgfxPYA+eIvYKv8GKDJOrY2D3/U9MRnKfMWD7bU4jeD4xmqyIg==} engines: {node: '>=20.19'} '@tanstack/match-sorter-utils@8.19.4': @@ -1917,20 +1886,20 @@ packages: resolution: {integrity: sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w==} engines: {node: '>=18'} - '@tanstack/query-core@5.90.20': - resolution: {integrity: sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==} + '@tanstack/query-core@5.96.2': + resolution: {integrity: sha512-hzI6cTVh4KNRk8UtoIBS7Lv9g6BnJPXvBKsvYH1aGWvv0347jT3BnSvztOE+kD76XGvZnRC/t6qdW1CaIfwCeA==} - '@tanstack/query-devtools@5.93.0': - resolution: {integrity: sha512-+kpsx1NQnOFTZsw6HAFCW3HkKg0+2cepGtAWXjiiSOJJ1CtQpt72EE2nyZb+AjAbLRPoeRmPJ8MtQd8r8gsPdg==} + '@tanstack/query-devtools@5.96.2': + resolution: {integrity: sha512-vBTB1Qhbm3nHSbEUtQwks/EdcAtFfEapr1WyBW4w2ExYKuXVi3jIxUIHf5MlSltiHuL7zNyUuanqT/7sI2sb6g==} - '@tanstack/react-ai-devtools@0.2.12': - resolution: {integrity: sha512-H1ZclZM9XYhxsSMpejrCxe/liuqJCasmjoQimX+CBEVGPwJnkHruinPBSTJeDrzqzDShs/3CJJUqOJhIjY2wVg==} + '@tanstack/react-ai-devtools@0.2.21': + resolution: {integrity: sha512-6IA7cgPphbzrEt8OvWk27YFFT3+AWzFF9Ig1UxXBa8wdK+HP11+4pYVMmRJbZWWsffGLpD8ELR1N7G/i3I29Ng==} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/react-devtools@0.9.10': - resolution: {integrity: sha512-WKFU8SXN7DLM7EyD2aUAhmk7JGNeONWhQozAH2qDCeOjyc3Yzxs4BxeoyKMYyEiX/eCp8ZkMTf/pJX6vm2LGeA==} + '@tanstack/react-devtools@0.10.1': + resolution: {integrity: sha512-cvcd0EqN7Q2LYatQXxFhOkEa9RUQXZlhXnM1mwuibxmyRX+CMyohUZcgjodtIfgh+RT0Pmvt49liTdZby5ovZw==} engines: {node: '>=18'} peerDependencies: '@types/react': '>=16.8' @@ -1938,8 +1907,8 @@ packages: react: '>=16.8' react-dom: '>=16.8' - '@tanstack/react-form@1.28.4': - resolution: {integrity: sha512-ZGBwl9JM2u0kol7jAWpqAkr2JSHfXJaLPsFDZWPf+ewpVkwngTTW/rGgtoDe5uVpHoDIpOhzpPCAh6O1SjGEOg==} + '@tanstack/react-form@1.28.6': + resolution: {integrity: sha512-dRxwKeNW3uuJvf0sXsIQ2compFMnIJNk9B436Lx0fqkqK+CBvA1tNmEdX+faoCpuQ5Wua3c8ahVibJ65cpkijA==} peerDependencies: '@tanstack/react-start': '*' react: ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -1947,38 +1916,38 @@ packages: '@tanstack/react-start': optional: true - '@tanstack/react-query-devtools@5.91.3': - resolution: {integrity: sha512-nlahjMtd/J1h7IzOOfqeyDh5LNfG0eULwlltPEonYy0QL+nqrBB+nyzJfULV+moL7sZyxc2sHdNJki+vLA9BSA==} + '@tanstack/react-query-devtools@5.96.2': + resolution: {integrity: sha512-nTFKLGuTOFvmFRvcyZ3ArWC/DnMNPoBh6h/2yD6rsf7TCTJCQt+oUWOp2uKPTIuEPtF/vN9Kw5tl5mD1Kbposw==} peerDependencies: - '@tanstack/react-query': ^5.90.20 + '@tanstack/react-query': ^5.96.2 react: ^18 || ^19 - '@tanstack/react-query@5.90.21': - resolution: {integrity: sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==} + '@tanstack/react-query@5.96.2': + resolution: {integrity: sha512-sYyzzJT4G0g02azzJ8o55VFFV31XvFpdUpG+unxS0vSaYsJnSPKGoI6WdPwUucJL1wpgGfwfmntNX/Ub1uOViA==} peerDependencies: react: ^18 || ^19 - '@tanstack/react-router-devtools@1.166.6': - resolution: {integrity: sha512-TheVyOgo8ljD8wHHLceFsnKrX7nhTIQv9WokSrPjNTP4H3synUMADxh8yZafVYdr6lS2CBvldd5s7JI8DcwBUg==} + '@tanstack/react-router-devtools@1.166.11': + resolution: {integrity: sha512-WYR3q4Xui5yPT/5PXtQh8i03iUA7q8dONBjWpV3nsGdM8Cs1FxpfhLstW0wZO1dOvSyElscwTRCJ6nO5N8r3Lg==} engines: {node: '>=20.19'} peerDependencies: - '@tanstack/react-router': ^1.166.6 - '@tanstack/router-core': ^1.166.6 + '@tanstack/react-router': ^1.168.2 + '@tanstack/router-core': ^1.168.2 react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' peerDependenciesMeta: '@tanstack/router-core': optional: true - '@tanstack/react-router@1.166.6': - resolution: {integrity: sha512-lfymPCfTkLQaNj/KIPElt+6B9REwPw2/Of3KtMwhNINs7h2xFQMSAOYk+ItCv8i93lBczlg89BRHtRS99qmzyA==} + '@tanstack/react-router@1.168.10': + resolution: {integrity: sha512-/RmDlOwDkCug609KdPB3U+U1zmrtadJpvsmRg2zEn8TRCKRNri7dYZIjQZbNg8PgUiRL4T6njrZBV1ChzblNaA==} engines: {node: '>=20.19'} peerDependencies: react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-store@0.9.2': - resolution: {integrity: sha512-Vt5usJE5sHG/cMechQfmwvwne6ktGCELe89Lmvoxe3LKRoFrhPa8OCKWs0NliG8HTJElEIj7PLtaBQIcux5pAQ==} + '@tanstack/react-store@0.9.3': + resolution: {integrity: sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -1990,25 +1959,26 @@ packages: react: '>=16.8' react-dom: '>=16.8' - '@tanstack/router-core@1.166.6': - resolution: {integrity: sha512-SwVPMQxjoY4jwiNgD9u5kDFp/iSaf3wgf1t93xRCC6qDHmv/xLaawhvwEPNIJaPepWuSYRpywpJWH9hGlBqVbw==} + '@tanstack/router-core@1.168.9': + resolution: {integrity: sha512-18oeEwEDyXOIuO1VBP9ACaK7tYHZUjynGDCoUh/5c/BNhia9vCJCp9O0LfhZXOorDc/PmLSgvmweFhVmIxF10g==} engines: {node: '>=20.19'} + hasBin: true - '@tanstack/router-devtools-core@1.166.6': - resolution: {integrity: sha512-ndPnCDeSGW3bd33u3EMe3+EJGLiFOHZaIKRJRLdZClOB6J6pvzKMELJgizBtjaR6X56FdCsC/STgjPkOeR9paA==} + '@tanstack/router-devtools-core@1.167.1': + resolution: {integrity: sha512-ECMM47J4KmifUvJguGituSiBpfN8SyCUEoxQks5RY09hpIBfR2eswCv2e6cJimjkKwBQXOVTPkTUk/yRvER+9w==} engines: {node: '>=20.19'} peerDependencies: - '@tanstack/router-core': ^1.166.6 + '@tanstack/router-core': ^1.168.2 csstype: ^3.0.10 peerDependenciesMeta: csstype: optional: true - '@tanstack/router-devtools@1.166.6': - resolution: {integrity: sha512-PcTCzBNdZxJ+PMaK/PtTANOWVM757OtsarIuDWzpxXTNL5grYFAhx6W96BXKl262sBS2ugeciHjbwNaTwW6kLA==} + '@tanstack/router-devtools@1.166.11': + resolution: {integrity: sha512-jvFKr1fQ5pWMOZTILhitJc1kJt1wj8qqtRClVJvyD1AjHc1XINihkqK+R6+FmC8F2m+XOhKME4CSnTtJ6Nf34w==} engines: {node: '>=20.19'} peerDependencies: - '@tanstack/react-router': ^1.166.6 + '@tanstack/react-router': ^1.168.2 csstype: ^3.0.10 react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' @@ -2016,16 +1986,17 @@ packages: csstype: optional: true - '@tanstack/router-generator@1.166.6': - resolution: {integrity: sha512-D7Z6oLP2IfflXUzOOxIgeCD8v3/SXU//cgBon0pbF13HkKdf9Zlt97kQqcaOkbnruJJ6i5xtUIsoAQbMmj+EsQ==} + '@tanstack/router-generator@1.166.24': + resolution: {integrity: sha512-vdaGKwuH+r+DPe6R1mjk+TDDmDH6NTG7QqwxHqGEvOH4aGf9sPjhmRKNJZqQr8cPIbfp6u5lXyZ1TeDcSNMVEA==} engines: {node: '>=20.19'} - '@tanstack/router-plugin@1.166.6': - resolution: {integrity: sha512-07ZwOMNDlKIoaRtrfP5zO3VfqXNg2Zm7qvqZOBaTbbqgMvaKclW0ylqakweXtDwiNs9GPf/+lH/xyc+CgLGUyg==} + '@tanstack/router-plugin@1.167.12': + resolution: {integrity: sha512-StEHcctCuFI5taSjO+lhR/yQ+EK63BdyYa+ne6FoNQPB3MMrOUrz2ZVnbqILRLkh2b+p2EfBKt65sgAKdKygPQ==} engines: {node: '>=20.19'} + hasBin: true peerDependencies: '@rsbuild/core': '>=1.0.2' - '@tanstack/react-router': ^1.166.6 + '@tanstack/react-router': ^1.168.10 vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' vite-plugin-solid: ^2.11.10 webpack: '>=5.92.0' @@ -2041,20 +2012,21 @@ packages: webpack: optional: true - '@tanstack/router-utils@1.161.4': - resolution: {integrity: sha512-r8TpjyIZoqrXXaf2DDyjd44gjGBoyE+/oEaaH68yLI9ySPO1gUWmQENZ1MZnmBnpUGN24NOZxdjDLc8npK0SAw==} + '@tanstack/router-utils@1.161.6': + resolution: {integrity: sha512-nRcYw+w2OEgK6VfjirYvGyPLOK+tZQz1jkYcmH5AjMamQ9PycnlxZF2aEZtPpNoUsaceX2bHptn6Ub5hGXqNvw==} engines: {node: '>=20.19'} - '@tanstack/store@0.9.2': - resolution: {integrity: sha512-K013lUJEFJK2ofFQ/hZKJUmCnpcV00ebLyOyFOWQvyQHUOZp/iYO84BM6aOGiV81JzwbX0APTVmW8YI7yiG5oA==} + '@tanstack/store@0.9.3': + resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==} '@tanstack/table-core@8.21.3': resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} engines: {node: '>=12'} - '@tanstack/virtual-file-routes@1.161.4': - resolution: {integrity: sha512-42WoRePf8v690qG8yGRe/YOh+oHni9vUaUUfoqlS91U2scd3a5rkLtVsc6b7z60w3RogH0I00vdrC5AaeiZ18w==} + '@tanstack/virtual-file-routes@1.161.7': + resolution: {integrity: sha512-olW33+Cn+bsCsZKPwEGhlkqS6w3M2slFv11JIobdnCFKMLG97oAI2kWKdx5/zsywTL8flpnoIgaZZPlQTFYhdQ==} engines: {node: '>=20.19'} + hasBin: true '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} @@ -2097,32 +2069,98 @@ packages: '@types/d3-array@3.2.2': resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + '@types/d3-color@3.1.3': resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + '@types/d3-ease@3.0.2': resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + '@types/d3-interpolate@3.0.4': resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} '@types/d3-path@3.1.1': resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + '@types/d3-scale@4.0.9': resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + '@types/d3-shape@3.1.8': resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + '@types/d3-time@3.0.4': resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} '@types/d3-timer@3.0.2': resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -2136,6 +2174,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -2151,8 +2192,8 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@25.4.0': - resolution: {integrity: sha512-9wLpoeWuBlcbBpOY3XmzSTG3oscB6xjBEEtn+pYXTfhyXhIxC5FsBer2KTopBlvKEiW9l13po9fq+SJY/5lkhw==} + '@types/node@25.5.2': + resolution: {integrity: sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==} '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} @@ -2171,6 +2212,9 @@ packages: '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -2183,65 +2227,86 @@ packages: '@types/validate-npm-package-name@4.0.2': resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260304.1': - resolution: {integrity: sha512-TnTUxYt+dShRSoeOldx7VlKoEG+bvPHnyPEBImlNc7c3WP0AHYyNHrNg6EbLbzkOorARtd06J3Vk+XYzkrRzZg==} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260324.1': + resolution: {integrity: sha512-Yg4zANP69mquBH4VwgfaSGj98Bc1o1mKFX4kk6WFEGvUX7BKvakiMXmKRKc79zY8HtpSKXiqTYcbOtumoRKfTA==} cpu: [arm64] os: [darwin] - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260304.1': - resolution: {integrity: sha512-1nwXX1zbyYI3sDKdaR8NsBdM7LmE0J6OzVtlWgEJ/8YR7oC2/HY6/SfShF3DHHcEOHOFxRLbkJ9zVTJJspWLCw==} + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260324.1': + resolution: {integrity: sha512-hlMIJQjlbwNTH3iS8IivAxeu7I4OLm645kErSynAR4i8O6lZiSeaZndUqIDYx/+er4bb01X0Fnxa8BTW2Emv2A==} cpu: [x64] os: [darwin] - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260304.1': - resolution: {integrity: sha512-cw+xqroXtsk/yVTKbelcPWMd6oZdET9kNWmigyc189KWwzOu2eq2EPXPQsrhEigq8O3j0xW0z3q2oqG+smOiXg==} + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260324.1': + resolution: {integrity: sha512-1oCTzfOOujaa0DhFj7epM3xqhoI4l+d2f584zeQjPCvk8FJBj4kwfOMZV139bEe+G5IoGsvhJzzRYzfu2diZkA==} cpu: [arm64] os: [linux] - '@typescript/native-preview-linux-arm@7.0.0-dev.20260304.1': - resolution: {integrity: sha512-TXZClCJVteK2f9gcI+I7o1Sxgq3qdMtraXOP9GZF8o0sKCLdDWENN8uORfZSeQv2qOJohcKvrrEz6LLSSngvEg==} + '@typescript/native-preview-linux-arm@7.0.0-dev.20260324.1': + resolution: {integrity: sha512-uWcNrDuCdJb3TCAWI7TvrEzgluDiWmnNFeyE48mlgiVpcf7XVD9PwD0AIxvlO27NyF+NkQ3guHFssmjkhi0E9w==} cpu: [arm] os: [linux] - '@typescript/native-preview-linux-x64@7.0.0-dev.20260304.1': - resolution: {integrity: sha512-EXufnN4PG0HYBHYbHXQXXRXtaQKuKBT3e6nxPhKnwpBBgy2MgWDIxzroTLvI9+SllhbJQzHNZOWiB+SU+KdCNw==} + '@typescript/native-preview-linux-x64@7.0.0-dev.20260324.1': + resolution: {integrity: sha512-MzGh802vVwm9pCuFD6n7MrfaHn44ewayqZ5MSnSMmOZZzaOGwmGCCNDJUvsSsDSwIrYt8bU6LbUxx7TvlpJ8dQ==} cpu: [x64] os: [linux] - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260304.1': - resolution: {integrity: sha512-Be9yyDDbT/PEdNlhG+NXT47fwuiIeN0+/9BkeRKkiLgzY8DqQIC9w5FRWmwAJ+9PVa2sKr5cjD1SpJDHGrPIrA==} + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260324.1': + resolution: {integrity: sha512-CyxCw3Rj+nqI2cVP4CmdEAn+8UkGJM1vWmNQ2q3z5ZF3V+JdnlmhALEzk4bu0ddu5pyHwM1fOHLsD7xcGUcKtQ==} cpu: [arm64] os: [win32] - '@typescript/native-preview-win32-x64@7.0.0-dev.20260304.1': - resolution: {integrity: sha512-lg/w+rZ9NIUoqSsk2TbtDsqyD9nW0/rhTMYd14RFP7vuNijLrTbl7GPiMhFtMxaqCSOFapwbql7/3lU4BKHB6g==} + '@typescript/native-preview-win32-x64@7.0.0-dev.20260324.1': + resolution: {integrity: sha512-6J8V5cHOrh7Cjl6lv8+zsDY5NkbMYBwXroKlFUzThZ7vpJlEaa51DPQyCyILIXodv5XODd5arRcbaY+cC6Et8Q==} cpu: [x64] os: [win32] - '@typescript/native-preview@7.0.0-dev.20260304.1': - resolution: {integrity: sha512-Xj0ZeHEy+yJ/bIg6psPwl0POvBf1j5u7IZAXsUqgvgWbMIvdM9JOGmhpifcj6j28LcXM6GTvXUoXwlatxJ73Qg==} + '@typescript/native-preview@7.0.0-dev.20260324.1': + resolution: {integrity: sha512-AzuC/jEAucVCay7ckwexa8Ao4NfDUeVYBTIxGG9fc1qh2q1JphdUW50PLRyNJXCDcnLtghSIDBi+wfFgVBtcMQ==} hasBin: true '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - '@vitejs/plugin-react@5.1.4': - resolution: {integrity: sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==} + '@upsetjs/venn.js@2.0.0': + resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} + + '@vitejs/plugin-react@6.0.1': + resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + + '@vitest/browser-playwright@4.1.2': + resolution: {integrity: sha512-N0Z2HzMLvMR6k/tWPTS6Q/DaRscrkax/f2f9DIbNQr+Cd1l4W4wTf/I6S983PAMr0tNqqoTL+xNkLh9M5vbkLg==} + peerDependencies: + playwright: '*' + vitest: 4.1.2 + + '@vitest/browser@4.1.2': + resolution: {integrity: sha512-CwdIf90LNf1Zitgqy63ciMAzmyb4oIGs8WZ40VGYrWkssQKeEKr32EzO8MKUrDPPcPVHFI9oQ5ni2Hp24NaNRQ==} + peerDependencies: + vitest: 4.1.2 '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} + '@vitest/expect@4.1.2': + resolution: {integrity: sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==} - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} + '@vitest/mocker@4.1.2': + resolution: {integrity: sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: msw: optional: true @@ -2251,36 +2316,34 @@ packages: '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} + '@vitest/pretty-format@4.1.2': + resolution: {integrity: sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==} - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} + '@vitest/runner@4.1.2': + resolution: {integrity: sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==} - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} + '@vitest/snapshot@4.1.2': + resolution: {integrity: sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==} '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} + '@vitest/spy@4.1.2': + resolution: {integrity: sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==} '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} + '@vitest/utils@4.1.2': + resolution: {integrity: sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==} + + '@webcontainer/env@1.1.1': + resolution: {integrity: sha512-6aN99yL695Hi9SuIk1oC88l9o0gmxL1nGWWQ/kNy81HigJ0FoaoTXpytCj6ItzgyCEwA9kF1wixsTuv5cjsgng==} accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} @@ -2298,9 +2361,6 @@ packages: ajv: optional: true - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} @@ -2324,10 +2384,6 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} - engines: {node: '>=12'} - ansis@4.2.0: resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} engines: {node: '>=14'} @@ -2361,12 +2417,12 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - axe-core@4.11.1: - resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==} + axe-core@4.11.2: + resolution: {integrity: sha512-byD6KPdvo72y/wj2T/4zGEvvlis+PsZsn/yPS3pEO+sFpcrqRpX/TJCxvVaEsNeMrfQbCr7w163YqoD9IYwHXw==} engines: {node: '>=4'} - axios@1.13.6: - resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==} + axios@1.14.0: + resolution: {integrity: sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==} babel-dead-code-elimination@1.0.12: resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} @@ -2377,9 +2433,6 @@ packages: bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - balanced-match@4.0.4: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} @@ -2387,8 +2440,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.0: - resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + baseline-browser-mapping@2.10.16: + resolution: {integrity: sha512-Lyf3aK28zpsD1yQMiiHD4RvVb6UdMoo8xzG2XzFIfR9luPzOpcBlAsT/qfB1XWS1bxWT+UtE4WmQgsp297FYOA==} engines: {node: '>=6.0.0'} hasBin: true @@ -2403,22 +2456,16 @@ packages: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - - brace-expansion@5.0.4: - resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} engines: {node: 18 || 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -2453,8 +2500,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001777: - resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} + caniuse-lite@1.0.30001786: + resolution: {integrity: sha512-4oxTZEvqmLLrERwxO76yfKM7acZo310U+v4kqexI2TL1DkkUEMT8UijrxxcnVdxR3qkVf5awGRX+4Z6aPHVKrA==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -2467,10 +2514,6 @@ packages: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - chalk@5.6.2: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} @@ -2491,6 +2534,14 @@ packages: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} + chevrotain-allstar@0.3.1: + resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} + peerDependencies: + chevrotain: ^11.0.0 + + chevrotain@11.1.2: + resolution: {integrity: sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -2502,8 +2553,8 @@ packages: citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - citty@0.2.1: - resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} + citty@0.2.2: + resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -2563,8 +2614,16 @@ packages: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} confbox@0.2.4: resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} @@ -2584,8 +2643,8 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-es@2.0.0: - resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + cookie-es@2.0.1: + resolution: {integrity: sha512-aVf4A4hI2w70LnF7GG+7xDQUkliwiXWXFvTjkip4+b64ygDQ2sJPRSKFDHbxn8o0xu9QzPkMuuiWIXyFSE2slA==} cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} @@ -2603,6 +2662,12 @@ packages: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + cosmiconfig@9.0.1: resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==} engines: {node: '>=14'} @@ -2627,34 +2692,129 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.33.2: + resolution: {integrity: sha512-sj4HXd3DokGhzZAdjDejGvTPLqlt84vNFN8m7bGsOzDY5DyVcxIb2ejIXat2Iy7HxWhdT/N1oKyheJ5YdpsGuw==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + d3-array@3.2.4: resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} engines: {node: '>=12'} + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + d3-color@3.1.0: resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} engines: {node: '>=12'} + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + d3-ease@3.0.1: resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} engines: {node: '>=12'} + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + d3-format@3.1.2: resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} engines: {node: '>=12'} + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + d3-interpolate@3.0.1: resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} engines: {node: '>=12'} + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + d3-path@3.1.0: resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} engines: {node: '>=12'} + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + d3-scale@4.0.2: resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} engines: {node: '>=12'} + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + d3-shape@3.2.0: resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} engines: {node: '>=12'} @@ -2671,6 +2831,23 @@ packages: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.14: + resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} + data-uri-to-buffer@4.0.1: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} @@ -2681,8 +2858,8 @@ packages: date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} - dayjs@1.11.19: - resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} @@ -2711,9 +2888,6 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -2730,8 +2904,11 @@ packages: resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} engines: {node: '>=12'} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + defu@6.1.6: + resolution: {integrity: sha512-f8mefEW4WIVg4LckePx3mALjQSPQgFlg9U8yaPdlsbdYcHQyj9n2zL2LJEA52smeYxOvmd/nB7TpMtHGMTHcug==} + + delaunator@5.1.0: + resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} @@ -2758,8 +2935,8 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - diff@8.0.3: - resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} engines: {node: '>=0.3.1'} doctrine@3.0.0: @@ -2772,17 +2949,17 @@ packages: dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - dotenv@17.3.1: - resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} + dompurify@3.3.3: + resolution: {integrity: sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==} + + dotenv@17.4.1: + resolution: {integrity: sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==} engines: {node: '>=12'} dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} @@ -2793,8 +2970,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.307: - resolution: {integrity: sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==} + electron-to-chromium@1.5.332: + resolution: {integrity: sha512-7OOtytmh/rINMLwaFTbcMVvYXO3AUm029X0LcyfYk0B557RlPkdpTpnH9+htMlfu5dKwOmT0+Zs2Aw+lnn6TeQ==} embla-carousel-react@8.6.0: resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==} @@ -2815,9 +2992,6 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - empathic@2.0.0: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} @@ -2826,8 +3000,8 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} - enhanced-resolve@5.20.0: - resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} + enhanced-resolve@5.20.1: + resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} entities@6.0.1: @@ -2849,8 +3023,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} @@ -2863,8 +3037,8 @@ packages: es-toolkit@1.45.1: resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==} - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} hasBin: true @@ -2875,63 +3049,15 @@ packages: escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - eslint-plugin-react-hooks@7.0.1: - resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint@9.39.3: - resolution: {integrity: sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - estree-util-is-identifier-name@3.0.0: resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} @@ -2972,8 +3098,8 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - express-rate-limit@8.3.1: - resolution: {integrity: sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==} + express-rate-limit@8.3.2: + resolution: {integrity: sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==} engines: {node: '>= 16'} peerDependencies: express: '>= 4.11' @@ -2995,12 +3121,6 @@ packages: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} @@ -3024,10 +3144,6 @@ packages: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -3036,17 +3152,6 @@ packages: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.4.1: - resolution: {integrity: sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==} - follow-redirects@1.15.11: resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} engines: {node: '>=4.0'} @@ -3056,10 +3161,6 @@ packages: debug: optional: true - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - form-data@4.0.5: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} @@ -3096,11 +3197,8 @@ packages: fuzzysort@3.1.0: resolution: {integrity: sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==} - fzf@0.5.2: - resolution: {integrity: sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==} - - gaxios@7.1.3: - resolution: {integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==} + gaxios@7.1.4: + resolution: {integrity: sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==} engines: {node: '>=18'} gcp-metadata@8.1.2: @@ -3146,6 +3244,9 @@ packages: get-tsconfig@4.13.6: resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} + get-tsconfig@4.13.7: + resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} + giget@2.0.0: resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} hasBin: true @@ -3154,33 +3255,17 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob@10.5.0: - resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - hasBin: true - glob@13.0.6: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - goober@2.1.18: resolution: {integrity: sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==} peerDependencies: csstype: ^3.0.10 - google-auth-library@10.6.1: - resolution: {integrity: sha512-5awwuLrzNol+pFDmKJd0dKtZ0fPLAtoA5p7YO4ODsDu6ONJUVqbYwvv8y2ZBO5MBNp9TJXigB19710kYpBPdtA==} + google-auth-library@10.6.2: + resolution: {integrity: sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==} engines: {node: '>=18'} google-logging-utils@1.1.3: @@ -3194,13 +3279,12 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphql@16.13.1: - resolution: {integrity: sha512-gGgrVCoDKlIZ8fIqXBBb0pPKqDgki0Z/FSKNiQzSGj2uEYHr1tq5wmBegGwJx6QB5S5cM0khSBpi/JFHMCvsmQ==} + graphql@16.13.2: + resolution: {integrity: sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} @@ -3241,18 +3325,12 @@ packages: headers-polyfill@4.0.3: resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} - hermes-estree@0.25.1: - resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - - hermes-parser@0.25.1: - resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - highlight.js@11.11.1: resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} engines: {node: '>=12.0.0'} - hono@4.12.5: - resolution: {integrity: sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==} + hono@4.12.12: + resolution: {integrity: sha512-p1JfQMKaceuCbpJKAPKVqyqviZdS0eUxH9v82oWo1kb9xjQ5wA6iP3FNVAPDFlz5/p7d45lO+BpSk1tuSZMF4Q==} engines: {node: '>=16.9.0'} html-url-attributes@3.0.1: @@ -3277,6 +3355,10 @@ packages: resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} engines: {node: '>=18.18.0'} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} @@ -3295,10 +3377,6 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} @@ -3315,6 +3393,9 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + internmap@2.0.3: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} @@ -3422,8 +3503,8 @@ packages: resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} - isbot@5.1.35: - resolution: {integrity: sha512-waFfC72ZNfwLLuJ2iLaoVaqcNo+CAaLR7xCpAn0Y5WfGzkNHv7ZN39Vbi1y+kb+Zs46XHOX3tZNExroFUPX+Kg==} + isbot@5.1.37: + resolution: {integrity: sha512-5bcicX81xf6NlTEV8rWdg7Pk01LFizDetuYGHx6d/f6y3lR2/oo8IfxjzJqn1UdDEyCcwT9e7NRloj8DwCYujQ==} engines: {node: '>=18'} isexe@2.0.0: @@ -3433,15 +3514,12 @@ packages: resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} engines: {node: '>=18'} - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - jose@6.2.1: - resolution: {integrity: sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw==} + jose@6.2.2: + resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3458,9 +3536,6 @@ packages: json-bigint@1.0.0: resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -3468,18 +3543,12 @@ packages: resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} engines: {node: '>=16'} - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} json-schema-typed@8.0.2: resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -3494,8 +3563,12 @@ packages: jws@4.0.1: resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + katex@0.16.45: + resolution: {integrity: sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==} + hasBin: true + + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} @@ -3505,18 +3578,18 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - launch-editor@2.13.1: - resolution: {integrity: sha512-lPSddlAAluRKJ7/cjRFoXUFzaX7q/YKI7yPHuEvSJVqoXvFnJov1/Ud87Aa4zULIbA9Nja4mSPK8l0z/7eV2wA==} + langium@4.2.1: + resolution: {integrity: sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==} + engines: {node: '>=20.10.0', npm: '>=10.2.3'} - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + launch-editor@2.13.2: + resolution: {integrity: sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==} - lightningcss-android-arm64@1.31.1: - resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} @@ -3524,61 +3597,30 @@ packages: cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.31.1: - resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - lightningcss-darwin-arm64@1.32.0: resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.31.1: - resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - lightningcss-darwin-x64@1.32.0: resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.31.1: - resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - lightningcss-freebsd-x64@1.32.0: resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.31.1: - resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - lightningcss-linux-arm-gnueabihf@1.32.0: resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.31.1: - resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - lightningcss-linux-arm64-gnu@1.32.0: resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} @@ -3586,27 +3628,13 @@ packages: os: [linux] libc: [glibc] - lightningcss-linux-arm64-musl@1.31.1: - resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [musl] - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - lightningcss-linux-x64-gnu@1.31.1: - resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} @@ -3614,13 +3642,6 @@ packages: os: [linux] libc: [glibc] - lightningcss-linux-x64-musl@1.31.1: - resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} @@ -3628,34 +3649,18 @@ packages: os: [linux] libc: [musl] - lightningcss-win32-arm64-msvc@1.31.1: - resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.31.1: - resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - lightningcss-win32-x64-msvc@1.32.0: resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.31.1: - resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} - engines: {node: '>= 12.0.0'} - lightningcss@1.32.0: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} @@ -3663,12 +3668,11 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + lodash-es@4.17.23: + resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} log-symbols@6.0.0: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} @@ -3683,21 +3687,13 @@ packages: loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@11.2.6: - resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} + lru-cache@11.3.2: + resolution: {integrity: sha512-wgWa6FWQ3QRRJbIjbsldRJZxdxYngT/dO0I5Ynmlnin8qy7tC6xYzbcJjtN4wHLXtkbVwHzk0C+OejVw1XM+DQ==} engines: {node: 20 || >=22} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@0.577.0: - resolution: {integrity: sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -3708,8 +3704,13 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - marked@17.0.4: - resolution: {integrity: sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ==} + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + + marked@17.0.6: + resolution: {integrity: sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA==} engines: {node: '>= 20'} hasBin: true @@ -3777,6 +3778,9 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + mermaid@11.14.0: + resolution: {integrity: sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==} + micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -3893,17 +3897,10 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - - minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -3911,11 +3908,18 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - msw@2.12.10: - resolution: {integrity: sha512-G3VUymSE0/iegFnuipujpwyTM2GuZAKXNeerUSrG2+Eg391wW63xFs5ixWsK9MWzr1AGoSkYGmyAzNgbR3+urw==} + msw@2.13.0: + resolution: {integrity: sha512-5PPWf7I7DBHb4ZUZ0NUI+/VBDk/eiNYDNJZGt/jZ7+rbCSIK5hRcNTGqWMnn0vT6NrHiQlb0nfpenVGz1vrqpg==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -3933,9 +3937,6 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} @@ -3958,8 +3959,8 @@ packages: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - node-releases@2.0.36: - resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + node-releases@2.0.37: + resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==} normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -4022,8 +4023,8 @@ packages: resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} engines: {node: '>=20'} - openai@6.27.0: - resolution: {integrity: sha512-osTKySlrdYrLYTt0zjhY8yp0JUBmWDCN+Q+QxsV4xMQnnoVFpylgKGgxwN8sSdTNw0G4y+WUXs4eCMWpyDNWZQ==} + openai@6.33.0: + resolution: {integrity: sha512-xAYN1W3YsDXJWA5F277135YfkEk6H7D3D6vWwRhJ3OEkzRgcyK8z/P5P9Gyi/wB4N8kK9kM5ZjprfvyHagKmpw==} hasBin: true peerDependencies: ws: ^8.18.0 @@ -4034,10 +4035,6 @@ packages: zod: optional: true - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - ora@8.2.0: resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} engines: {node: '>=18'} @@ -4045,36 +4042,25 @@ packages: outvariant@1.4.3: resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} - oxfmt@0.36.0: - resolution: {integrity: sha512-/ejJ+KoSW6J9bcNT9a9UtJSJNWhJ3yOLSBLbkoFHJs/8CZjmaZVZAJe4YgO1KMJlKpNQasrn/G9JQUEZI3p0EQ==} + oxfmt@0.42.0: + resolution: {integrity: sha512-QhejGErLSMReNuZ6vxgFHDyGoPbjTRNi6uGHjy0cvIjOQFqD6xmr/T+3L41ixR3NIgzcNiJ6ylQKpvShTgDfqg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - oxlint@1.51.0: - resolution: {integrity: sha512-g6DNPaV9/WI9MoX2XllafxQuxwY1TV++j7hP8fTJByVBuCoVtm3dy9f/2vtH/HU40JztcgWF4G7ua+gkainklQ==} + oxlint@1.59.0: + resolution: {integrity: sha512-0xBLeGGjP4vD9pygRo8iuOkOzEU1MqOnfiOl7KYezL/QvWL8NUg6n03zXc7ZVqltiOpUxBk2zgHI3PnRIEdAvw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - oxlint-tsgolint: '>=0.15.0' + oxlint-tsgolint: '>=0.18.0' peerDependenciesMeta: oxlint-tsgolint: optional: true - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - p-retry@4.6.2: resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} engines: {node: '>=8'} - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - package-manager-detector@1.6.0: resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} @@ -4106,9 +4092,8 @@ packages: path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} @@ -4121,10 +4106,6 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.2: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} @@ -4132,8 +4113,8 @@ packages: path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -4148,31 +4129,44 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} pkce-challenge@5.0.1: resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - playwright-core@1.58.2: - resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==} + playwright-core@1.59.1: + resolution: {integrity: sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==} engines: {node: '>=18'} hasBin: true - playwright@1.58.2: - resolution: {integrity: sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==} + playwright@1.59.1: + resolution: {integrity: sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==} engines: {node: '>=18'} hasBin: true + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + postcss-selector-parser@7.1.1: resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} @@ -4181,18 +4175,14 @@ packages: resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} - postgres@3.4.8: - resolution: {integrity: sha512-d+JFcLM17njZaOLkv6SCev7uoLaBtfK86vMUXhW1Z4glPWh4jozno9APvW/XKFJ3CCxVoC7OL38BqRydtu5nGg==} + postgres@3.4.9: + resolution: {integrity: sha512-GD3qdB0x1z9xgFI6cdRD6xu2Sp2WCOEoe3mtnyB5Ee0XrrL5Pe+e4CCnJrRMnL1zYtRDZmQQVbvOttLnKDLnaw==} engines: {node: '>=12'} powershell-utils@0.1.0: resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} engines: {node: '>=20'} - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - prettier@3.8.1: resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} engines: {node: '>=14'} @@ -4221,12 +4211,9 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} qs@6.15.0: resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} @@ -4257,8 +4244,8 @@ packages: peerDependencies: typescript: '>= 4.3.x' - react-docgen@8.0.2: - resolution: {integrity: sha512-+NRMYs2DyTP4/tqWz371Oo50JqmWltR1h2gcdgUMAWZJIAvrd0/SqlCfx7tpzpl/s36rzw6qH2MjoNrxtRNYhA==} + react-docgen@8.0.3: + resolution: {integrity: sha512-aEZ9qP+/M+58x2qgfSFEWH1BxLyHe5+qkLNJOZQb5iGS017jpbRnoKhNRrXPeA6RfBrZO5wZrT9DMC1UqE1f1w==} engines: {node: ^20.9.0 || >=22} react-dom@19.2.4: @@ -4266,11 +4253,6 @@ packages: peerDependencies: react: ^19.2.4 - react-icons@5.6.0: - resolution: {integrity: sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==} - peerDependencies: - react: '*' - react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} @@ -4289,10 +4271,6 @@ packages: redux: optional: true - react-refresh@0.18.0: - resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} - engines: {node: '>=0.10.0'} - react-remove-scroll-bar@2.3.8: resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} @@ -4313,8 +4291,8 @@ packages: '@types/react': optional: true - react-resizable-panels@4.7.2: - resolution: {integrity: sha512-1L2vyeBG96hp7N6x6rzYXJ8EjYiDiffMsqj3cd+T9aOKwscvuyCn2CuZ5q3PoUSTIJUM6Q5DgXH1bdDe6uvh2w==} + react-resizable-panels@4.9.0: + resolution: {integrity: sha512-sEl+hA6y9/kxa0aPlrUC+G1lcShAf/PiIjoeC8kWXxa53RfAVplVCIxEl01Nwa4L2iRa5JXBXq1/mI8ch6qOZQ==} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 @@ -4345,8 +4323,8 @@ packages: resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} engines: {node: '>= 4'} - recharts@3.7.0: - resolution: {integrity: sha512-l2VCsy3XXeraxIID9fx23eCb6iCBsxUQDnE8tWm6DFdszVAO7WVY/ChAD9wVit01y6B2PMupYiMmQwhgPHc9Ew==} + recharts@3.8.0: + resolution: {integrity: sha512-Z/m38DX3L73ExO4Tpc9/iZWHmHnlzWG4njQbxsF5aSjwqmHNDDIm0rdEBArkwsBvR8U6EirlEHiQNYWCVh9sGQ==} engines: {node: '>=18'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -4386,8 +4364,8 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} - remend@1.2.2: - resolution: {integrity: sha512-4ZJgIB9EG9fQE41mOJCRHMmnxDTKHWawQoJWZyUbZuj680wVyogu2ihnj8Edqm7vh2mo/TWHyEZpn2kqeDvS7w==} + remend@1.3.0: + resolution: {integrity: sha512-iIhggPkhW3hFImKtB10w0dz4EZbs28mV/dmbcYVonWEJ6UGHHpP+bFZnTh6GNWJONg5m+U56JrL+8IxZRdgWjw==} remove-accents@0.5.0: resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} @@ -4430,52 +4408,11 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@5.0.10: - resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} - hasBin: true - - rolldown-vite@7.3.1: - resolution: {integrity: sha512-LYzdNAjRHhF2yA4JUQm/QyARyi216N2rpJ0lJZb8E9FU2y5v6Vk+xq/U4XBOxMefpWixT5H3TslmAHm1rqIq2w==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - esbuild: ^0.27.0 - jiti: '>=1.21.0' - less: ^4.0.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - esbuild: - optional: true - jiti: - optional: true - less: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true + robust-predicates@3.0.3: + resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} - rolldown@1.0.0-beta.53: - resolution: {integrity: sha512-Qd9c2p0XKZdgT5AYd+KgAMggJ8ZmCs3JnS9PTMWkyUfteKlfmKtxJbWTHkVakxwXs1Ub7jrRYVeFeF7N0sQxyw==} + rolldown@1.0.0-rc.11: + resolution: {integrity: sha512-NRjoKMusSjfRbSYiH3VSumlkgFe7kYAa3pzVOsVYVFY3zb5d7nS+a3KGQ7hJKXuYWbzJKPVQ9Wxq2UvyK+ENpw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -4484,6 +4421,9 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} @@ -4495,6 +4435,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -4522,14 +4465,14 @@ packages: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} - seroval-plugins@1.5.1: - resolution: {integrity: sha512-4FbuZ/TMl02sqv0RTFexu0SP6V+ywaIe5bAWCCEik0fk17BhALgwvUDVF7e3Uvf9pxmwCEJsRPmlkUE6HdzLAw==} + seroval-plugins@1.5.2: + resolution: {integrity: sha512-qpY0Cl+fKYFn4GOf3cMiq6l72CpuVaawb6ILjubOQ+diJ54LfOWaSSPsaswN8DRPIPW4Yq+tE1k5aKd7ILyaFg==} engines: {node: '>=10'} peerDependencies: seroval: ^1.0 - seroval@1.5.1: - resolution: {integrity: sha512-OwrZRZAfhHww0WEnKHDY8OM0U/Qs8OTfIDWhUD4BLpNJUfXK4cGmjiagGze086m+mhI+V2nD0gfbHEnJjb9STA==} + seroval@1.5.2: + resolution: {integrity: sha512-xcRN39BdsnO9Tf+VzsE7b3JyTJASItIV1FVFewJKCFcW4s4haIKS3e6vj8PGB9qBwC7tnuOywQMdv5N4qkzi7Q==} engines: {node: '>=10'} serve-static@2.2.1: @@ -4539,8 +4482,8 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shadcn@3.8.5: - resolution: {integrity: sha512-jPRx44e+eyeV7xwY3BLJXcfrks00+M0h5BGB9l6DdcBW4BpAj4x3lVmVy0TXPEs2iHEisxejr62sZAAw6B1EVA==} + shadcn@4.1.2: + resolution: {integrity: sha512-qNQcCavkbYsgBj+X09tF2bTcwRd8abR880bsFkDU2kMqceMCLAm5c+cLg7kWDhfh1H9g08knpQ5ZEf6y/co16g==} hasBin: true shebang-command@2.0.0: @@ -4581,11 +4524,15 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} + sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - solid-js@1.9.11: - resolution: {integrity: sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q==} + solid-js@1.9.12: + resolution: {integrity: sha512-QzKaSJq2/iDrWR1As6MHZQ8fQkdOBf8GReYb7L5iKwMGceg7HxDcaOHk0at66tNgn9U2U7dXo8ZZpLIAmGMzgw==} sonner@2.0.7: resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} @@ -4615,15 +4562,15 @@ packages: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.0.0: + resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} stdin-discarder@0.2.2: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} engines: {node: '>=18'} - storybook@10.2.17: - resolution: {integrity: sha512-yueTpl5YJqLzQqs3CanxNdAAfFU23iP0j+JVJURE4ghfEtRmWfWoZWLGkVcyjmgum7UmjwAlqRuOjQDNvH89kw==} + storybook@10.3.4: + resolution: {integrity: sha512-866YXZy9k59tLPl9SN3KZZOFeBC/swxkuBVtW8iQjJIzfCrvk7zXQd8RSQ4ignmCdArVvY4lGMCAT4yNaZSt1g==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -4631,8 +4578,8 @@ packages: prettier: optional: true - streamdown@2.4.0: - resolution: {integrity: sha512-fRk4HEYNznRLmxoVeT8wsGBwHF6/Yrdey6k+ZrE1Qtp4NyKwm7G/6e2Iw8penY4yLx31TlAHWT5Bsg1weZ9FZg==} + streamdown@2.5.0: + resolution: {integrity: sha512-/tTnURfIOxZK/pqJAxsfCvETG/XCJHoWnk3jq9xLcuz6CSpnjjuxSRBTTL4PKGhxiZQf0lqPxGhImdpwcZ2XwA==} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 @@ -4644,10 +4591,6 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} @@ -4687,19 +4630,14 @@ packages: resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} engines: {node: '>=12'} - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - style-to-js@1.1.21: resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} style-to-object@1.0.14: resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} @@ -4715,24 +4653,21 @@ packages: tailwind-merge@3.5.0: resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} - tailwindcss@4.2.1: - resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==} + tailwindcss@4.2.2: + resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + tapable@2.3.2: + resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - tiny-warning@1.0.3: - resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} - tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + tinyexec@1.0.4: + resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} engines: {node: '>=18'} tinyglobby@0.2.15: @@ -4747,19 +4682,19 @@ packages: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} tinyspy@4.0.4: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} - tldts-core@7.0.25: - resolution: {integrity: sha512-ZjCZK0rppSBu7rjHYDYsEaMOIbbT+nWF57hKkv4IUmZWBNrBWBOjIElc0mKRgLM8bm7x/BBlof6t2gi/Oq/Asw==} + tldts-core@7.0.28: + resolution: {integrity: sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ==} - tldts@7.0.25: - resolution: {integrity: sha512-keinCnPbwXEUG3ilrWQZU+CqcTTzHq9m2HhoUP2l7Xmi8l1LuijAXLpAJ5zRW+ifKTNscs4NdCkfkDCBYm352w==} + tldts@7.0.28: + resolution: {integrity: sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw==} hasBin: true to-regex-range@5.0.1: @@ -4770,8 +4705,12 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - tough-cookie@6.0.0: - resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + tough-cookie@6.0.1: + resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} engines: {node: '>=16'} trim-lines@3.0.1: @@ -4790,16 +4729,6 @@ packages: ts-morph@26.0.0: resolution: {integrity: sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==} - tsconfck@3.1.6: - resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} - engines: {node: ^18 || >=20} - hasBin: true - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - tsconfig-paths@4.2.0: resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} engines: {node: '>=6'} @@ -4815,12 +4744,8 @@ packages: tw-animate-css@1.4.0: resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-fest@5.4.4: - resolution: {integrity: sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==} + type-fest@5.5.0: + resolution: {integrity: sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==} engines: {node: '>=20'} type-is@2.0.1: @@ -4832,6 +4757,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} @@ -4878,9 +4806,6 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - use-callback-ref@1.3.3: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} @@ -4909,6 +4834,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + validate-npm-package-name@7.0.2: resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} engines: {node: ^20.17.0 || >=22.9.0} @@ -4935,20 +4864,16 @@ packages: victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} - vite-tsconfig-paths@6.1.1: - resolution: {integrity: sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg==} - peerDependencies: - vite: '*' - - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + vite@8.0.2: + resolution: {integrity: sha512-1gFhNi+bHhRE/qKZOJXACm6tX4bA3Isy9KuKF15AgSRuRazNBOJfdDemPBU16/mpMxApDPrWvZ08DcLPEoRnuA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 jiti: '>=1.21.0' less: ^4.0.0 - lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -4959,12 +4884,14 @@ packages: peerDependenciesMeta: '@types/node': optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true jiti: optional: true less: optional: true - lightningcss: - optional: true sass: optional: true sass-embedded: @@ -4980,20 +4907,21 @@ packages: yaml: optional: true - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} + vitest@4.1.2: + resolution: {integrity: sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 + '@vitest/browser-playwright': 4.1.2 + '@vitest/browser-preview': 4.1.2 + '@vitest/browser-webdriverio': 4.1.2 + '@vitest/ui': 4.1.2 happy-dom: '*' jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -5014,6 +4942,26 @@ packages: jsdom: optional: true + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} @@ -5021,8 +4969,8 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} - web-vitals@5.1.0: - resolution: {integrity: sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==} + web-vitals@5.2.0: + resolution: {integrity: sha512-i2z98bEmaCqSDiHEDu+gHl/dmR4Q+TxFmG3/13KkMO+o8UxQzCqWaDRCiLgEa41nlO4VpXSI0ASa1xWmO9sBlA==} webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} @@ -5045,10 +4993,6 @@ packages: engines: {node: '>=8'} hasBin: true - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -5057,15 +5001,11 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -5099,9 +5039,9 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} + yocto-spinner@1.1.0: + resolution: {integrity: sha512-/BY0AUXnS7IKO354uLLA2eRcWiqDifEbd6unXCsOxkFDAkhgUL3PH9X2bFoaU0YchnDXsF+iKleeTLJGckbXfA==} + engines: {node: '>=18.19'} yoctocolors-cjs@2.1.3: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} @@ -5111,16 +5051,10 @@ packages: resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} engines: {node: '>=18'} - zod-to-json-schema@3.25.1: - resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} peerDependencies: - zod: ^3.25 || ^4 - - zod-validation-error@4.0.2: - resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.25.0 || ^4.0.0 + zod: ^3.25.28 || ^4 zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} @@ -5135,12 +5069,10 @@ snapshots: '@adobe/css-tools@4.4.4': {} - '@antfu/ni@25.0.0': + '@antfu/install-pkg@1.1.0': dependencies: - ansis: 4.2.0 - fzf: 0.5.2 package-manager-detector: 1.6.0 - tinyexec: 1.0.2 + tinyexec: 1.0.4 '@anthropic-ai/sdk@0.71.2(zod@4.3.6)': dependencies: @@ -5162,8 +5094,8 @@ snapshots: '@babel/generator': 7.29.1 '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.2 '@babel/template': 7.28.6 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 @@ -5178,7 +5110,7 @@ snapshots: '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 @@ -5192,7 +5124,7 @@ snapshots: dependencies: '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 + browserslist: 4.28.2 lru-cache: 5.1.1 semver: 6.3.1 @@ -5262,12 +5194,12 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.28.6': + '@babel/helpers@7.29.2': dependencies: '@babel/template': 7.28.6 '@babel/types': 7.29.0 - '@babel/parser@7.29.0': + '@babel/parser@7.29.2': dependencies: '@babel/types': 7.29.0 @@ -5289,16 +5221,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -5321,12 +5243,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/runtime@7.28.6': {} + '@babel/runtime@7.29.2': {} '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@babel/traverse@7.29.0': @@ -5334,7 +5256,7 @@ snapshots: '@babel/code-frame': 7.29.0 '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/template': 7.28.6 '@babel/types': 7.29.0 debug: 4.4.3 @@ -5346,10 +5268,10 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@base-ui/react@1.2.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@base-ui/react@1.3.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@babel/runtime': 7.28.6 - '@base-ui/utils': 0.2.5(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@babel/runtime': 7.29.2 + '@base-ui/utils': 0.2.6(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@floating-ui/utils': 0.2.11 react: 19.2.4 @@ -5359,9 +5281,9 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - '@base-ui/utils@0.2.5(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@base-ui/utils@0.2.6(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 '@floating-ui/utils': 0.2.11 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) @@ -5370,165 +5292,141 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + '@blazediff/core@1.9.1': {} + + '@braintree/sanitize-url@7.1.2': {} + + '@chevrotain/cst-dts-gen@11.1.2': + dependencies: + '@chevrotain/gast': 11.1.2 + '@chevrotain/types': 11.1.2 + lodash-es: 4.17.23 + + '@chevrotain/gast@11.1.2': + dependencies: + '@chevrotain/types': 11.1.2 + lodash-es: 4.17.23 + + '@chevrotain/regexp-to-ast@11.1.2': {} + + '@chevrotain/types@11.1.2': {} + + '@chevrotain/utils@11.1.2': {} + '@date-fns/tz@1.4.1': {} - '@dotenvx/dotenvx@1.54.1': + '@dotenvx/dotenvx@1.60.1': dependencies: commander: 11.1.0 - dotenv: 17.3.1 + dotenv: 17.4.1 eciesjs: 0.4.18 execa: 5.1.1 - fdir: 6.5.0(picomatch@4.0.3) + fdir: 6.5.0(picomatch@4.0.4) ignore: 5.3.2 object-treeify: 1.1.33 - picomatch: 4.0.3 + picomatch: 4.0.4 which: 4.0.0 + yocto-spinner: 1.1.0 - '@ecies/ciphers@0.2.5(@noble/ciphers@1.3.0)': + '@ecies/ciphers@0.2.6(@noble/ciphers@1.3.0)': dependencies: '@noble/ciphers': 1.3.0 - '@emnapi/core@1.8.1': + '@emnapi/core@1.9.1': dependencies: - '@emnapi/wasi-threads': 1.1.0 + '@emnapi/wasi-threads': 1.2.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.8.1': + '@emnapi/runtime@1.9.1': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.1.0': + '@emnapi/wasi-threads@1.2.0': dependencies: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.27.3': + '@esbuild/aix-ppc64@0.27.7': optional: true - '@esbuild/android-arm64@0.27.3': + '@esbuild/android-arm64@0.27.7': optional: true - '@esbuild/android-arm@0.27.3': + '@esbuild/android-arm@0.27.7': optional: true - '@esbuild/android-x64@0.27.3': + '@esbuild/android-x64@0.27.7': optional: true - '@esbuild/darwin-arm64@0.27.3': + '@esbuild/darwin-arm64@0.27.7': optional: true - '@esbuild/darwin-x64@0.27.3': + '@esbuild/darwin-x64@0.27.7': optional: true - '@esbuild/freebsd-arm64@0.27.3': + '@esbuild/freebsd-arm64@0.27.7': optional: true - '@esbuild/freebsd-x64@0.27.3': + '@esbuild/freebsd-x64@0.27.7': optional: true - '@esbuild/linux-arm64@0.27.3': + '@esbuild/linux-arm64@0.27.7': optional: true - '@esbuild/linux-arm@0.27.3': + '@esbuild/linux-arm@0.27.7': optional: true - '@esbuild/linux-ia32@0.27.3': + '@esbuild/linux-ia32@0.27.7': optional: true - '@esbuild/linux-loong64@0.27.3': + '@esbuild/linux-loong64@0.27.7': optional: true - '@esbuild/linux-mips64el@0.27.3': + '@esbuild/linux-mips64el@0.27.7': optional: true - '@esbuild/linux-ppc64@0.27.3': + '@esbuild/linux-ppc64@0.27.7': optional: true - '@esbuild/linux-riscv64@0.27.3': + '@esbuild/linux-riscv64@0.27.7': optional: true - '@esbuild/linux-s390x@0.27.3': + '@esbuild/linux-s390x@0.27.7': optional: true - '@esbuild/linux-x64@0.27.3': + '@esbuild/linux-x64@0.27.7': optional: true - '@esbuild/netbsd-arm64@0.27.3': + '@esbuild/netbsd-arm64@0.27.7': optional: true - '@esbuild/netbsd-x64@0.27.3': + '@esbuild/netbsd-x64@0.27.7': optional: true - '@esbuild/openbsd-arm64@0.27.3': + '@esbuild/openbsd-arm64@0.27.7': optional: true - '@esbuild/openbsd-x64@0.27.3': + '@esbuild/openbsd-x64@0.27.7': optional: true - '@esbuild/openharmony-arm64@0.27.3': + '@esbuild/openharmony-arm64@0.27.7': optional: true - '@esbuild/sunos-x64@0.27.3': + '@esbuild/sunos-x64@0.27.7': optional: true - '@esbuild/win32-arm64@0.27.3': + '@esbuild/win32-arm64@0.27.7': optional: true - '@esbuild/win32-ia32@0.27.3': + '@esbuild/win32-ia32@0.27.7': optional: true - '@esbuild/win32-x64@0.27.3': + '@esbuild/win32-x64@0.27.7': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.3(jiti@2.6.1))': - dependencies: - eslint: 9.39.3(jiti@2.6.1) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/config-array@0.21.2': - dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.5 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.4.2': - dependencies: - '@eslint/core': 0.17.0 - - '@eslint/core@0.17.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/eslintrc@3.3.5': - dependencies: - ajv: 6.14.0 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.39.3': {} - - '@eslint/object-schema@2.1.7': {} - - '@eslint/plugin-kit@0.4.1': - dependencies: - '@eslint/core': 0.17.0 - levn: 0.4.1 - - '@faker-js/faker@10.3.0': {} + '@faker-js/faker@10.4.0': {} '@floating-ui/core@1.7.5': dependencies: @@ -5551,26 +5449,25 @@ snapshots: '@fontsource-variable/urbanist@5.2.7': {} - '@google/genai@1.44.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))': + '@google/genai@1.48.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))': dependencies: - google-auth-library: 10.6.1 + google-auth-library: 10.6.2 p-retry: 4.6.2 protobufjs: 7.5.4 - ws: 8.19.0 + ws: 8.20.0 optionalDependencies: - '@modelcontextprotocol/sdk': 1.27.1(zod@4.3.6) + '@modelcontextprotocol/sdk': 1.29.0(zod@4.3.6) transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@hey-api/codegen-core@0.7.0(typescript@6.0.0-beta)': + '@hey-api/codegen-core@0.7.4': dependencies: - '@hey-api/types': 0.1.3(typescript@6.0.0-beta) + '@hey-api/types': 0.1.4 ansi-colors: 4.1.3 c12: 3.3.3 color-support: 1.1.3 - typescript: 6.0.0-beta transitivePeerDependencies: - magicast @@ -5580,99 +5477,85 @@ snapshots: '@types/json-schema': 7.0.15 js-yaml: 4.1.1 - '@hey-api/openapi-ts@0.93.1(typescript@6.0.0-beta)': + '@hey-api/openapi-ts@0.94.4(typescript@6.0.0-beta)': dependencies: - '@hey-api/codegen-core': 0.7.0(typescript@6.0.0-beta) + '@hey-api/codegen-core': 0.7.4 '@hey-api/json-schema-ref-parser': 1.3.1 - '@hey-api/shared': 0.2.1(typescript@6.0.0-beta) - '@hey-api/types': 0.1.3(typescript@6.0.0-beta) + '@hey-api/shared': 0.2.5 + '@hey-api/types': 0.1.4 ansi-colors: 4.1.3 color-support: 1.1.3 commander: 14.0.3 + get-tsconfig: 4.13.6 typescript: 6.0.0-beta transitivePeerDependencies: - magicast - '@hey-api/shared@0.2.1(typescript@6.0.0-beta)': + '@hey-api/shared@0.2.5': dependencies: - '@hey-api/codegen-core': 0.7.0(typescript@6.0.0-beta) + '@hey-api/codegen-core': 0.7.4 '@hey-api/json-schema-ref-parser': 1.3.1 - '@hey-api/types': 0.1.3(typescript@6.0.0-beta) + '@hey-api/types': 0.1.4 ansi-colors: 4.1.3 cross-spawn: 7.0.6 open: 11.0.0 semver: 7.7.3 - typescript: 6.0.0-beta transitivePeerDependencies: - magicast - '@hey-api/types@0.1.3(typescript@6.0.0-beta)': - dependencies: - typescript: 6.0.0-beta + '@hey-api/types@0.1.4': {} - '@hono/node-server@1.19.11(hono@4.12.5)': + '@hono/node-server@1.19.13(hono@4.12.12)': dependencies: - hono: 4.12.5 + hono: 4.12.12 - '@hugeicons/core-free-icons@3.3.0': {} + '@hugeicons/core-free-icons@4.1.1': {} - '@hugeicons/react@1.1.5(react@19.2.4)': + '@hugeicons/react@1.1.6(react@19.2.4)': dependencies: react: 19.2.4 - '@humanfs/core@0.19.1': {} + '@iconify/types@2.0.0': {} - '@humanfs/node@0.16.7': + '@iconify/utils@3.1.0': dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.4.3 - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + mlly: 1.8.2 '@inquirer/ansi@1.0.2': {} - '@inquirer/confirm@5.1.21(@types/node@25.4.0)': + '@inquirer/confirm@5.1.21(@types/node@25.5.2)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.4.0) - '@inquirer/type': 3.0.10(@types/node@25.4.0) + '@inquirer/core': 10.3.2(@types/node@25.5.2) + '@inquirer/type': 3.0.10(@types/node@25.5.2) optionalDependencies: - '@types/node': 25.4.0 + '@types/node': 25.5.2 - '@inquirer/core@10.3.2(@types/node@25.4.0)': + '@inquirer/core@10.3.2(@types/node@25.5.2)': dependencies: '@inquirer/ansi': 1.0.2 '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.4.0) + '@inquirer/type': 3.0.10(@types/node@25.5.2) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.4.0 + '@types/node': 25.5.2 '@inquirer/figures@1.0.15': {} - '@inquirer/type@3.0.10(@types/node@25.4.0)': + '@inquirer/type@3.0.10(@types/node@25.5.2)': optionalDependencies: - '@types/node': 25.4.0 - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.2.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 + '@types/node': 25.5.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(typescript@6.0.0-beta)': + '@joshwooding/vite-plugin-react-docgen-typescript@0.7.0(typescript@6.0.0-beta)(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': dependencies: glob: 13.0.6 react-docgen-typescript: 2.4.0(typescript@6.0.0-beta) - vite: rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) + vite: 8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) optionalDependencies: typescript: 6.0.0-beta @@ -5703,9 +5586,13 @@ snapshots: '@types/react': 19.2.14 react: 19.2.4 - '@modelcontextprotocol/sdk@1.27.1(zod@3.25.76)': + '@mermaid-js/parser@1.1.0': + dependencies: + langium: 4.2.1 + + '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': dependencies: - '@hono/node-server': 1.19.11(hono@4.12.5) + '@hono/node-server': 1.19.13(hono@4.12.12) ajv: 8.18.0 ajv-formats: 3.0.1(ajv@8.18.0) content-type: 1.0.5 @@ -5714,20 +5601,20 @@ snapshots: eventsource: 3.0.7 eventsource-parser: 3.0.6 express: 5.2.1 - express-rate-limit: 8.3.1(express@5.2.1) - hono: 4.12.5 - jose: 6.2.1 + express-rate-limit: 8.3.2(express@5.2.1) + hono: 4.12.12 + jose: 6.2.2 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 zod: 3.25.76 - zod-to-json-schema: 3.25.1(zod@3.25.76) + zod-to-json-schema: 3.25.2(zod@3.25.76) transitivePeerDependencies: - supports-color - '@modelcontextprotocol/sdk@1.27.1(zod@4.3.6)': + '@modelcontextprotocol/sdk@1.29.0(zod@4.3.6)': dependencies: - '@hono/node-server': 1.19.11(hono@4.12.5) + '@hono/node-server': 1.19.13(hono@4.12.12) ajv: 8.18.0 ajv-formats: 3.0.1(ajv@8.18.0) content-type: 1.0.5 @@ -5736,14 +5623,14 @@ snapshots: eventsource: 3.0.7 eventsource-parser: 3.0.6 express: 5.2.1 - express-rate-limit: 8.3.1(express@5.2.1) - hono: 4.12.5 - jose: 6.2.1 + express-rate-limit: 8.3.2(express@5.2.1) + hono: 4.12.12 + jose: 6.2.2 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 zod: 4.3.6 - zod-to-json-schema: 3.25.1(zod@4.3.6) + zod-to-json-schema: 3.25.2(zod@4.3.6) transitivePeerDependencies: - supports-color @@ -5756,10 +5643,10 @@ snapshots: outvariant: 1.4.3 strict-event-emitter: 0.5.1 - '@napi-rs/wasm-runtime@1.1.1': + '@napi-rs/wasm-runtime@1.1.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': dependencies: - '@emnapi/core': 1.8.1 - '@emnapi/runtime': 1.8.1 + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 '@tybys/wasm-util': 0.10.1 optional: true @@ -5792,130 +5679,127 @@ snapshots: '@open-draft/until@2.1.0': {} - '@oxc-project/runtime@0.101.0': {} - - '@oxc-project/types@0.101.0': {} + '@oxc-project/types@0.122.0': {} - '@oxfmt/binding-android-arm-eabi@0.36.0': + '@oxfmt/binding-android-arm-eabi@0.42.0': optional: true - '@oxfmt/binding-android-arm64@0.36.0': + '@oxfmt/binding-android-arm64@0.42.0': optional: true - '@oxfmt/binding-darwin-arm64@0.36.0': + '@oxfmt/binding-darwin-arm64@0.42.0': optional: true - '@oxfmt/binding-darwin-x64@0.36.0': + '@oxfmt/binding-darwin-x64@0.42.0': optional: true - '@oxfmt/binding-freebsd-x64@0.36.0': + '@oxfmt/binding-freebsd-x64@0.42.0': optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.36.0': + '@oxfmt/binding-linux-arm-gnueabihf@0.42.0': optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.36.0': + '@oxfmt/binding-linux-arm-musleabihf@0.42.0': optional: true - '@oxfmt/binding-linux-arm64-gnu@0.36.0': + '@oxfmt/binding-linux-arm64-gnu@0.42.0': optional: true - '@oxfmt/binding-linux-arm64-musl@0.36.0': + '@oxfmt/binding-linux-arm64-musl@0.42.0': optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.36.0': + '@oxfmt/binding-linux-ppc64-gnu@0.42.0': optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.36.0': + '@oxfmt/binding-linux-riscv64-gnu@0.42.0': optional: true - '@oxfmt/binding-linux-riscv64-musl@0.36.0': + '@oxfmt/binding-linux-riscv64-musl@0.42.0': optional: true - '@oxfmt/binding-linux-s390x-gnu@0.36.0': + '@oxfmt/binding-linux-s390x-gnu@0.42.0': optional: true - '@oxfmt/binding-linux-x64-gnu@0.36.0': + '@oxfmt/binding-linux-x64-gnu@0.42.0': optional: true - '@oxfmt/binding-linux-x64-musl@0.36.0': + '@oxfmt/binding-linux-x64-musl@0.42.0': optional: true - '@oxfmt/binding-openharmony-arm64@0.36.0': + '@oxfmt/binding-openharmony-arm64@0.42.0': optional: true - '@oxfmt/binding-win32-arm64-msvc@0.36.0': + '@oxfmt/binding-win32-arm64-msvc@0.42.0': optional: true - '@oxfmt/binding-win32-ia32-msvc@0.36.0': + '@oxfmt/binding-win32-ia32-msvc@0.42.0': optional: true - '@oxfmt/binding-win32-x64-msvc@0.36.0': + '@oxfmt/binding-win32-x64-msvc@0.42.0': optional: true - '@oxlint/binding-android-arm-eabi@1.51.0': + '@oxlint/binding-android-arm-eabi@1.59.0': optional: true - '@oxlint/binding-android-arm64@1.51.0': + '@oxlint/binding-android-arm64@1.59.0': optional: true - '@oxlint/binding-darwin-arm64@1.51.0': + '@oxlint/binding-darwin-arm64@1.59.0': optional: true - '@oxlint/binding-darwin-x64@1.51.0': + '@oxlint/binding-darwin-x64@1.59.0': optional: true - '@oxlint/binding-freebsd-x64@1.51.0': + '@oxlint/binding-freebsd-x64@1.59.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.51.0': + '@oxlint/binding-linux-arm-gnueabihf@1.59.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.51.0': + '@oxlint/binding-linux-arm-musleabihf@1.59.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.51.0': + '@oxlint/binding-linux-arm64-gnu@1.59.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.51.0': + '@oxlint/binding-linux-arm64-musl@1.59.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.51.0': + '@oxlint/binding-linux-ppc64-gnu@1.59.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.51.0': + '@oxlint/binding-linux-riscv64-gnu@1.59.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.51.0': + '@oxlint/binding-linux-riscv64-musl@1.59.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.51.0': + '@oxlint/binding-linux-s390x-gnu@1.59.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.51.0': + '@oxlint/binding-linux-x64-gnu@1.59.0': optional: true - '@oxlint/binding-linux-x64-musl@1.51.0': + '@oxlint/binding-linux-x64-musl@1.59.0': optional: true - '@oxlint/binding-openharmony-arm64@1.51.0': + '@oxlint/binding-openharmony-arm64@1.59.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.51.0': + '@oxlint/binding-win32-arm64-msvc@1.59.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.51.0': + '@oxlint/binding-win32-ia32-msvc@1.59.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.51.0': + '@oxlint/binding-win32-x64-msvc@1.59.0': optional: true - '@pkgjs/parseargs@0.11.0': - optional: true - - '@playwright/test@1.58.2': + '@playwright/test@1.59.1': dependencies: - playwright: 1.58.2 + playwright: 1.59.1 + + '@polka/url@1.0.0-next.29': {} '@protobufjs/aspromise@1.1.2': {} @@ -6111,56 +5995,65 @@ snapshots: react: 19.2.4 react-redux: 9.2.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1) - '@rolldown/binding-android-arm64@1.0.0-beta.53': + '@rolldown/binding-android-arm64@1.0.0-rc.11': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.11': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.11': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-beta.53': + '@rolldown/binding-freebsd-x64@1.0.0-rc.11': optional: true - '@rolldown/binding-darwin-x64@1.0.0-beta.53': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.11': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-beta.53': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.11': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.11': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.11': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': + '@rolldown/binding-linux-x64-musl@1.0.0-rc.11': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': + '@rolldown/binding-openharmony-arm64@1.0.0-rc.11': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.53': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.11(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': dependencies: - '@napi-rs/wasm-runtime': 1.1.1 + '@napi-rs/wasm-runtime': 1.1.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.11': optional: true - '@rolldown/pluginutils@1.0.0-beta.53': {} + '@rolldown/pluginutils@1.0.0-rc.11': {} - '@rolldown/pluginutils@1.0.0-rc.3': {} + '@rolldown/pluginutils@1.0.0-rc.7': {} '@rollup/pluginutils@5.3.0(rollup@4.59.0)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 - picomatch: 4.0.3 + picomatch: 4.0.4 optionalDependencies: rollup: 4.59.0 @@ -6243,59 +6136,59 @@ snapshots: '@sindresorhus/merge-streams@4.0.0': {} - '@solid-primitives/event-listener@2.4.5(solid-js@1.9.11)': + '@solid-primitives/event-listener@2.4.5(solid-js@1.9.12)': dependencies: - '@solid-primitives/utils': 6.4.0(solid-js@1.9.11) - solid-js: 1.9.11 + '@solid-primitives/utils': 6.4.0(solid-js@1.9.12) + solid-js: 1.9.12 - '@solid-primitives/keyboard@1.3.5(solid-js@1.9.11)': + '@solid-primitives/keyboard@1.3.5(solid-js@1.9.12)': dependencies: - '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.11) - '@solid-primitives/rootless': 1.5.3(solid-js@1.9.11) - '@solid-primitives/utils': 6.4.0(solid-js@1.9.11) - solid-js: 1.9.11 + '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.12) + '@solid-primitives/rootless': 1.5.3(solid-js@1.9.12) + '@solid-primitives/utils': 6.4.0(solid-js@1.9.12) + solid-js: 1.9.12 - '@solid-primitives/resize-observer@2.1.5(solid-js@1.9.11)': + '@solid-primitives/resize-observer@2.1.5(solid-js@1.9.12)': dependencies: - '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.11) - '@solid-primitives/rootless': 1.5.3(solid-js@1.9.11) - '@solid-primitives/static-store': 0.1.3(solid-js@1.9.11) - '@solid-primitives/utils': 6.4.0(solid-js@1.9.11) - solid-js: 1.9.11 + '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.12) + '@solid-primitives/rootless': 1.5.3(solid-js@1.9.12) + '@solid-primitives/static-store': 0.1.3(solid-js@1.9.12) + '@solid-primitives/utils': 6.4.0(solid-js@1.9.12) + solid-js: 1.9.12 - '@solid-primitives/rootless@1.5.3(solid-js@1.9.11)': + '@solid-primitives/rootless@1.5.3(solid-js@1.9.12)': dependencies: - '@solid-primitives/utils': 6.4.0(solid-js@1.9.11) - solid-js: 1.9.11 + '@solid-primitives/utils': 6.4.0(solid-js@1.9.12) + solid-js: 1.9.12 - '@solid-primitives/static-store@0.1.3(solid-js@1.9.11)': + '@solid-primitives/static-store@0.1.3(solid-js@1.9.12)': dependencies: - '@solid-primitives/utils': 6.4.0(solid-js@1.9.11) - solid-js: 1.9.11 + '@solid-primitives/utils': 6.4.0(solid-js@1.9.12) + solid-js: 1.9.12 - '@solid-primitives/utils@6.4.0(solid-js@1.9.11)': + '@solid-primitives/utils@6.4.0(solid-js@1.9.12)': dependencies: - solid-js: 1.9.11 + solid-js: 1.9.12 '@standard-schema/spec@1.1.0': {} '@standard-schema/utils@0.3.0': {} - '@storybook/addon-a11y@10.2.17(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/addon-a11y@10.3.4(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: '@storybook/global': 5.0.0 - axe-core: 4.11.1 - storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + axe-core: 4.11.2 + storybook: 10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@storybook/addon-docs@10.2.17(@types/react@19.2.14)(esbuild@0.27.3)(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/addon-docs@10.3.4(@types/react@19.2.14)(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.4) - '@storybook/csf-plugin': 10.2.17(esbuild@0.27.3)(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + '@storybook/csf-plugin': 10.3.4(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@storybook/react-dom-shim': 10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + '@storybook/react-dom-shim': 10.3.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' @@ -6304,37 +6197,39 @@ snapshots: - vite - webpack - '@storybook/addon-vitest@10.2.17(@vitest/runner@4.0.18)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vitest@4.0.18(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@25.4.0)(typescript@6.0.0-beta))(tsx@4.21.0))': + '@storybook/addon-vitest@10.3.4(@vitest/browser-playwright@4.1.2)(@vitest/browser@4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))(vitest@4.1.2))(@vitest/runner@4.1.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vitest@4.1.2)': dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) optionalDependencies: - '@vitest/runner': 4.0.18 - vitest: 4.0.18(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@25.4.0)(typescript@6.0.0-beta))(tsx@4.21.0) + '@vitest/browser': 4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))(vitest@4.1.2) + '@vitest/browser-playwright': 4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(playwright@1.59.1)(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))(vitest@4.1.2) + '@vitest/runner': 4.1.2 + vitest: 4.1.2(@types/node@25.5.2)(@vitest/browser-playwright@4.1.2)(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) transitivePeerDependencies: - react - react-dom - '@storybook/builder-vite@10.2.17(esbuild@0.27.3)(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/builder-vite@10.3.4(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': dependencies: - '@storybook/csf-plugin': 10.2.17(esbuild@0.27.3)(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) - storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@storybook/csf-plugin': 10.3.4(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) + storybook: 10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ts-dedent: 2.2.0 - vite: rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) + vite: 8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup - webpack - '@storybook/csf-plugin@10.2.17(esbuild@0.27.3)(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/csf-plugin@10.3.4(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': dependencies: - storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) unplugin: 2.3.11 optionalDependencies: - esbuild: 0.27.3 + esbuild: 0.27.7 rollup: 4.59.0 - vite: rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) + vite: 8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) '@storybook/global@5.0.0': {} @@ -6343,27 +6238,27 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/react-dom-shim@10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': + '@storybook/react-dom-shim@10.3.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@storybook/react-vite@10.2.17(esbuild@0.27.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@6.0.0-beta)': + '@storybook/react-vite@10.3.4(esbuild@0.27.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@6.0.0-beta)(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(typescript@6.0.0-beta) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@6.0.0-beta)(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) '@rollup/pluginutils': 5.3.0(rollup@4.59.0) - '@storybook/builder-vite': 10.2.17(esbuild@0.27.3)(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(rollup@4.59.0)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) - '@storybook/react': 10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@6.0.0-beta) + '@storybook/builder-vite': 10.3.4(esbuild@0.27.7)(rollup@4.59.0)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) + '@storybook/react': 10.3.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@6.0.0-beta) empathic: 2.0.0 magic-string: 0.30.21 react: 19.2.4 - react-docgen: 8.0.2 + react-docgen: 8.0.3 react-dom: 19.2.4(react@19.2.4) resolve: 1.22.11 - storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tsconfig-paths: 4.2.0 - vite: rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) + vite: 8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup @@ -6371,14 +6266,15 @@ snapshots: - typescript - webpack - '@storybook/react@10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@6.0.0-beta)': + '@storybook/react@10.3.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@6.0.0-beta)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.2.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + '@storybook/react-dom-shim': 10.3.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) react: 19.2.4 - react-docgen: 8.0.2 + react-docgen: 8.0.3 + react-docgen-typescript: 2.4.0(typescript@6.0.0-beta) react-dom: 19.2.4(react@19.2.4) - storybook: 10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + storybook: 10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) optionalDependencies: typescript: 6.0.0-beta transitivePeerDependencies: @@ -6386,91 +6282,93 @@ snapshots: '@tabby_ai/hijri-converter@1.0.5': {} - '@tailwindcss/node@4.2.1': + '@tailwindcss/node@4.2.2': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.20.0 + enhanced-resolve: 5.20.1 jiti: 2.6.1 - lightningcss: 1.31.1 + lightningcss: 1.32.0 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.2.1 + tailwindcss: 4.2.2 - '@tailwindcss/oxide-android-arm64@4.2.1': + '@tailwindcss/oxide-android-arm64@4.2.2': optional: true - '@tailwindcss/oxide-darwin-arm64@4.2.1': + '@tailwindcss/oxide-darwin-arm64@4.2.2': optional: true - '@tailwindcss/oxide-darwin-x64@4.2.1': + '@tailwindcss/oxide-darwin-x64@4.2.2': optional: true - '@tailwindcss/oxide-freebsd-x64@4.2.1': + '@tailwindcss/oxide-freebsd-x64@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.2.1': + '@tailwindcss/oxide-linux-x64-musl@4.2.2': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.2.1': + '@tailwindcss/oxide-wasm32-wasi@4.2.2': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': optional: true - '@tailwindcss/oxide@4.2.1': + '@tailwindcss/oxide@4.2.2': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-x64': 4.2.1 - '@tailwindcss/oxide-freebsd-x64': 4.2.1 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.1 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.1 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-x64-musl': 4.2.1 - '@tailwindcss/oxide-wasm32-wasi': 4.2.1 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 - - '@tailwindcss/vite@4.2.1(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))': - dependencies: - '@tailwindcss/node': 4.2.1 - '@tailwindcss/oxide': 4.2.1 - tailwindcss: 4.2.1 - vite: rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) - - '@tanstack/ai-anthropic@0.6.0(@tanstack/ai@0.6.2)(zod@4.3.6)': + '@tailwindcss/oxide-android-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-x64': 4.2.2 + '@tailwindcss/oxide-freebsd-x64': 4.2.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-x64-musl': 4.2.2 + '@tailwindcss/oxide-wasm32-wasi': 4.2.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 + + '@tailwindcss/vite@4.2.2(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': + dependencies: + '@tailwindcss/node': 4.2.2 + '@tailwindcss/oxide': 4.2.2 + tailwindcss: 4.2.2 + vite: 8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) + + '@tanstack/ai-anthropic@0.7.2(@tanstack/ai@0.10.0)(zod@4.3.6)': dependencies: '@anthropic-ai/sdk': 0.71.2(zod@4.3.6) - '@tanstack/ai': 0.6.2 + '@tanstack/ai': 0.10.0 zod: 4.3.6 - '@tanstack/ai-client@0.5.3': + '@tanstack/ai-client@0.7.7': dependencies: - '@tanstack/ai': 0.6.2 + '@tanstack/ai': 0.10.0 + '@tanstack/ai-event-client': 0.2.0(@tanstack/ai@0.10.0) - '@tanstack/ai-devtools-core@0.3.8(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4)': + '@tanstack/ai-devtools-core@0.3.17(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4)': dependencies: - '@tanstack/ai': 0.6.2 - '@tanstack/devtools-ui': 0.5.0(csstype@3.2.3)(solid-js@1.9.11) - '@tanstack/devtools-utils': 0.3.2(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11) + '@tanstack/ai': 0.10.0 + '@tanstack/ai-event-client': 0.2.0(@tanstack/ai@0.10.0) + '@tanstack/devtools-ui': 0.5.1(csstype@3.2.3)(solid-js@1.9.12) + '@tanstack/devtools-utils': 0.4.0(@types/react@19.2.14)(react@19.2.4)(solid-js@1.9.12) goober: 2.1.18(csstype@3.2.3) - solid-js: 1.9.11 + solid-js: 1.9.12 transitivePeerDependencies: - '@types/react' - csstype @@ -6478,114 +6376,116 @@ snapshots: - react - vue - '@tanstack/ai-gemini@0.8.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6))(@tanstack/ai@0.6.2)': + '@tanstack/ai-event-client@0.2.0(@tanstack/ai@0.10.0)': dependencies: - '@google/genai': 1.44.0(@modelcontextprotocol/sdk@1.27.1(zod@4.3.6)) - '@tanstack/ai': 0.6.2 + '@tanstack/ai': 0.10.0 + '@tanstack/devtools-event-client': 0.4.3 + + '@tanstack/ai-gemini@0.8.5(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6))(@tanstack/ai@0.10.0)': + dependencies: + '@google/genai': 1.48.0(@modelcontextprotocol/sdk@1.29.0(zod@4.3.6)) + '@tanstack/ai': 0.10.0 transitivePeerDependencies: - '@modelcontextprotocol/sdk' - bufferutil - supports-color - utf-8-validate - '@tanstack/ai-ollama@0.6.0(@tanstack/ai@0.6.2)': + '@tanstack/ai-ollama@0.6.4(@tanstack/ai@0.10.0)': dependencies: - '@tanstack/ai': 0.6.2 + '@tanstack/ai': 0.10.0 ollama: 0.6.3 - '@tanstack/ai-openai@0.6.0(@tanstack/ai@0.6.2)(ws@8.19.0)(zod@4.3.6)': + '@tanstack/ai-openai@0.7.3(@tanstack/ai-client@0.7.7)(@tanstack/ai@0.10.0)(ws@8.20.0)(zod@4.3.6)': dependencies: - '@tanstack/ai': 0.6.2 - openai: 6.27.0(ws@8.19.0)(zod@4.3.6) + '@tanstack/ai': 0.10.0 + '@tanstack/ai-client': 0.7.7 + openai: 6.33.0(ws@8.20.0)(zod@4.3.6) zod: 4.3.6 transitivePeerDependencies: - ws - '@tanstack/ai-react@0.6.3(@tanstack/ai@0.6.2)(@types/react@19.2.14)(react@19.2.4)': + '@tanstack/ai-react@0.7.8(@tanstack/ai@0.10.0)(@types/react@19.2.14)(react@19.2.4)': dependencies: - '@tanstack/ai': 0.6.2 - '@tanstack/ai-client': 0.5.3 + '@tanstack/ai': 0.10.0 + '@tanstack/ai-client': 0.7.7 '@types/react': 19.2.14 react: 19.2.4 - '@tanstack/ai@0.6.2': + '@tanstack/ai@0.10.0': dependencies: - '@tanstack/devtools-event-client': 0.4.1 + '@tanstack/ai-event-client': 0.2.0(@tanstack/ai@0.10.0) partial-json: 0.1.7 '@tanstack/devtools-client@0.0.6': dependencies: - '@tanstack/devtools-event-client': 0.4.1 + '@tanstack/devtools-event-client': 0.4.3 '@tanstack/devtools-event-bus@0.4.1': dependencies: - ws: 8.19.0 + ws: 8.20.0 transitivePeerDependencies: - bufferutil - utf-8-validate - '@tanstack/devtools-event-client@0.4.1': {} + '@tanstack/devtools-event-client@0.4.3': {} - '@tanstack/devtools-ui@0.5.0(csstype@3.2.3)(solid-js@1.9.11)': + '@tanstack/devtools-ui@0.5.1(csstype@3.2.3)(solid-js@1.9.12)': dependencies: clsx: 2.1.1 - dayjs: 1.11.19 + dayjs: 1.11.20 goober: 2.1.18(csstype@3.2.3) - solid-js: 1.9.11 + solid-js: 1.9.12 transitivePeerDependencies: - csstype - '@tanstack/devtools-utils@0.3.2(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11)': - dependencies: - '@tanstack/devtools-ui': 0.5.0(csstype@3.2.3)(solid-js@1.9.11) + '@tanstack/devtools-utils@0.4.0(@types/react@19.2.14)(react@19.2.4)(solid-js@1.9.12)': optionalDependencies: '@types/react': 19.2.14 react: 19.2.4 - solid-js: 1.9.11 - transitivePeerDependencies: - - csstype + solid-js: 1.9.12 - '@tanstack/devtools-vite@0.5.3(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))': + '@tanstack/devtools-vite@0.6.0(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 '@tanstack/devtools-client': 0.0.6 '@tanstack/devtools-event-bus': 0.4.1 chalk: 5.6.2 - launch-editor: 2.13.1 - picomatch: 4.0.3 - vite: rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) + launch-editor: 2.13.2 + picomatch: 4.0.4 + vite: 8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@tanstack/devtools@0.10.11(csstype@3.2.3)(solid-js@1.9.11)': + '@tanstack/devtools@0.11.1(csstype@3.2.3)(solid-js@1.9.12)': dependencies: - '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.11) - '@solid-primitives/keyboard': 1.3.5(solid-js@1.9.11) - '@solid-primitives/resize-observer': 2.1.5(solid-js@1.9.11) + '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.12) + '@solid-primitives/keyboard': 1.3.5(solid-js@1.9.12) + '@solid-primitives/resize-observer': 2.1.5(solid-js@1.9.12) '@tanstack/devtools-client': 0.0.6 '@tanstack/devtools-event-bus': 0.4.1 - '@tanstack/devtools-ui': 0.5.0(csstype@3.2.3)(solid-js@1.9.11) + '@tanstack/devtools-ui': 0.5.1(csstype@3.2.3)(solid-js@1.9.12) clsx: 2.1.1 goober: 2.1.18(csstype@3.2.3) - solid-js: 1.9.11 + solid-js: 1.9.12 transitivePeerDependencies: - bufferutil - csstype - utf-8-validate - '@tanstack/form-core@1.28.4': + '@tanstack/form-core@1.28.6': dependencies: - '@tanstack/devtools-event-client': 0.4.1 + '@tanstack/devtools-event-client': 0.4.3 '@tanstack/pacer-lite': 0.1.1 - '@tanstack/store': 0.9.2 + '@tanstack/store': 0.9.3 - '@tanstack/history@1.161.4': {} + '@tanstack/history@1.161.6': {} '@tanstack/match-sorter-utils@8.19.4': dependencies: @@ -6593,14 +6493,14 @@ snapshots: '@tanstack/pacer-lite@0.1.1': {} - '@tanstack/query-core@5.90.20': {} + '@tanstack/query-core@5.96.2': {} - '@tanstack/query-devtools@5.93.0': {} + '@tanstack/query-devtools@5.96.2': {} - '@tanstack/react-ai-devtools@0.2.12(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11)': + '@tanstack/react-ai-devtools@0.2.21(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.12)': dependencies: - '@tanstack/ai-devtools-core': 0.3.8(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4) - '@tanstack/devtools-utils': 0.3.2(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11) + '@tanstack/ai-devtools-core': 0.3.17(@types/react@19.2.14)(csstype@3.2.3)(react@19.2.4) + '@tanstack/devtools-utils': 0.4.0(@types/react@19.2.14)(react@19.2.4)(solid-js@1.9.12) '@types/react': 19.2.14 react: 19.2.4 transitivePeerDependencies: @@ -6609,9 +6509,9 @@ snapshots: - solid-js - vue - '@tanstack/react-devtools@0.9.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11)': + '@tanstack/react-devtools@0.10.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.12)': dependencies: - '@tanstack/devtools': 0.10.11(csstype@3.2.3)(solid-js@1.9.11) + '@tanstack/devtools': 0.11.1(csstype@3.2.3)(solid-js@1.9.12) '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) react: 19.2.4 @@ -6622,50 +6522,48 @@ snapshots: - solid-js - utf-8-validate - '@tanstack/react-form@1.28.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-form@1.28.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/form-core': 1.28.4 - '@tanstack/react-store': 0.9.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/form-core': 1.28.6 + '@tanstack/react-store': 0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 transitivePeerDependencies: - react-dom - '@tanstack/react-query-devtools@5.91.3(@tanstack/react-query@5.90.21(react@19.2.4))(react@19.2.4)': + '@tanstack/react-query-devtools@5.96.2(@tanstack/react-query@5.96.2(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/query-devtools': 5.93.0 - '@tanstack/react-query': 5.90.21(react@19.2.4) + '@tanstack/query-devtools': 5.96.2 + '@tanstack/react-query': 5.96.2(react@19.2.4) react: 19.2.4 - '@tanstack/react-query@5.90.21(react@19.2.4)': + '@tanstack/react-query@5.96.2(react@19.2.4)': dependencies: - '@tanstack/query-core': 5.90.20 + '@tanstack/query-core': 5.96.2 react: 19.2.4 - '@tanstack/react-router-devtools@1.166.6(@tanstack/react-router@1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.166.6)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-router-devtools@1.166.11(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.168.9)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/react-router': 1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/router-devtools-core': 1.166.6(@tanstack/router-core@1.166.6)(csstype@3.2.3) + '@tanstack/react-router': 1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-devtools-core': 1.167.1(@tanstack/router-core@1.168.9)(csstype@3.2.3) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@tanstack/router-core': 1.166.6 + '@tanstack/router-core': 1.168.9 transitivePeerDependencies: - csstype - '@tanstack/react-router@1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/history': 1.161.4 - '@tanstack/react-store': 0.9.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/router-core': 1.166.6 - isbot: 5.1.35 + '@tanstack/history': 1.161.6 + '@tanstack/react-store': 0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.168.9 + isbot: 5.1.37 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 - '@tanstack/react-store@0.9.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/react-store@0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/store': 0.9.2 + '@tanstack/store': 0.9.3 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) use-sync-external-store: 1.6.0(react@19.2.4) @@ -6676,29 +6574,25 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@tanstack/router-core@1.166.6': + '@tanstack/router-core@1.168.9': dependencies: - '@tanstack/history': 1.161.4 - '@tanstack/store': 0.9.2 - cookie-es: 2.0.0 - seroval: 1.5.1 - seroval-plugins: 1.5.1(seroval@1.5.1) - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 + '@tanstack/history': 1.161.6 + cookie-es: 2.0.1 + seroval: 1.5.2 + seroval-plugins: 1.5.2(seroval@1.5.2) - '@tanstack/router-devtools-core@1.166.6(@tanstack/router-core@1.166.6)(csstype@3.2.3)': + '@tanstack/router-devtools-core@1.167.1(@tanstack/router-core@1.168.9)(csstype@3.2.3)': dependencies: - '@tanstack/router-core': 1.166.6 + '@tanstack/router-core': 1.168.9 clsx: 2.1.1 goober: 2.1.18(csstype@3.2.3) - tiny-invariant: 1.3.3 optionalDependencies: csstype: 3.2.3 - '@tanstack/router-devtools@1.166.6(@tanstack/react-router@1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.166.6)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@tanstack/router-devtools@1.166.11(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.168.9)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@tanstack/react-router': 1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-router-devtools': 1.166.6(@tanstack/react-router@1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.166.6)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router': 1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router-devtools': 1.166.11(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.168.9)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) clsx: 2.1.1 goober: 2.1.18(csstype@3.2.3) react: 19.2.4 @@ -6708,11 +6602,11 @@ snapshots: transitivePeerDependencies: - '@tanstack/router-core' - '@tanstack/router-generator@1.166.6': + '@tanstack/router-generator@1.166.24': dependencies: - '@tanstack/router-core': 1.166.6 - '@tanstack/router-utils': 1.161.4 - '@tanstack/virtual-file-routes': 1.161.4 + '@tanstack/router-core': 1.168.9 + '@tanstack/router-utils': 1.161.6 + '@tanstack/virtual-file-routes': 1.161.7 prettier: 3.8.1 recast: 0.23.11 source-map: 0.7.6 @@ -6721,7 +6615,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.166.6(@tanstack/react-router@1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))': + '@tanstack/router-plugin@1.167.12(@tanstack/react-router@1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) @@ -6729,43 +6623,43 @@ snapshots: '@babel/template': 7.28.6 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 - '@tanstack/router-core': 1.166.6 - '@tanstack/router-generator': 1.166.6 - '@tanstack/router-utils': 1.161.4 - '@tanstack/virtual-file-routes': 1.161.4 + '@tanstack/router-core': 1.168.9 + '@tanstack/router-generator': 1.166.24 + '@tanstack/router-utils': 1.161.6 + '@tanstack/virtual-file-routes': 1.161.7 chokidar: 3.6.0 unplugin: 2.3.11 zod: 3.25.76 optionalDependencies: - '@tanstack/react-router': 1.166.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - vite: rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) + '@tanstack/react-router': 1.168.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + vite: 8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) transitivePeerDependencies: - supports-color - '@tanstack/router-utils@1.161.4': + '@tanstack/router-utils@1.161.6': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 ansis: 4.2.0 babel-dead-code-elimination: 1.0.12 - diff: 8.0.3 + diff: 8.0.4 pathe: 2.0.3 tinyglobby: 0.2.15 transitivePeerDependencies: - supports-color - '@tanstack/store@0.9.2': {} + '@tanstack/store@0.9.3': {} '@tanstack/table-core@8.21.3': {} - '@tanstack/virtual-file-routes@1.161.4': {} + '@tanstack/virtual-file-routes@1.161.7': {} '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 '@types/aria-query': 5.0.4 aria-query: 5.3.0 dom-accessibility-api: 0.5.16 @@ -6789,7 +6683,7 @@ snapshots: '@ts-morph/common@0.27.0': dependencies: fast-glob: 3.3.3 - minimatch: 10.2.4 + minimatch: 10.2.5 path-browserify: 1.0.1 '@tybys/wasm-util@0.10.1': @@ -6801,7 +6695,7 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 @@ -6813,7 +6707,7 @@ snapshots: '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@types/babel__traverse@7.28.0': @@ -6827,42 +6721,137 @@ snapshots: '@types/d3-array@3.2.2': {} + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + '@types/d3-color@3.1.3': {} + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + '@types/d3-ease@3.0.2': {} + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + '@types/d3-interpolate@3.0.4': dependencies: '@types/d3-color': 3.1.3 '@types/d3-path@3.1.1': {} + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + '@types/d3-scale@4.0.9': dependencies: '@types/d3-time': 3.0.4 + '@types/d3-selection@3.0.11': {} + '@types/d3-shape@3.1.8': dependencies: '@types/d3-path': 3.1.1 + '@types/d3-time-format@4.0.3': {} + '@types/d3-time@3.0.4': {} '@types/d3-timer@3.0.2': {} - '@types/debug@4.1.12': + '@types/d3-transition@3.0.9': dependencies: - '@types/ms': 2.1.0 - - '@types/deep-eql@4.0.2': {} - - '@types/doctrine@0.0.9': {} + '@types/d3-selection': 3.0.11 - '@types/estree-jsx@1.0.5': + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/deep-eql@4.0.2': {} + + '@types/doctrine@0.0.9': {} + + '@types/estree-jsx@1.0.5': dependencies: '@types/estree': 1.0.8 '@types/estree@1.0.8': {} + '@types/geojson@7946.0.16': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -6877,7 +6866,7 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@25.4.0': + '@types/node@25.5.2': dependencies: undici-types: 7.18.2 @@ -6895,6 +6884,9 @@ snapshots: '@types/statuses@2.0.6': {} + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -6903,50 +6895,80 @@ snapshots: '@types/validate-npm-package-name@4.0.2': {} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260304.1': + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260324.1': optional: true - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260304.1': + '@typescript/native-preview-darwin-x64@7.0.0-dev.20260324.1': optional: true - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260304.1': + '@typescript/native-preview-linux-arm64@7.0.0-dev.20260324.1': optional: true - '@typescript/native-preview-linux-arm@7.0.0-dev.20260304.1': + '@typescript/native-preview-linux-arm@7.0.0-dev.20260324.1': optional: true - '@typescript/native-preview-linux-x64@7.0.0-dev.20260304.1': + '@typescript/native-preview-linux-x64@7.0.0-dev.20260324.1': optional: true - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260304.1': + '@typescript/native-preview-win32-arm64@7.0.0-dev.20260324.1': optional: true - '@typescript/native-preview-win32-x64@7.0.0-dev.20260304.1': + '@typescript/native-preview-win32-x64@7.0.0-dev.20260324.1': optional: true - '@typescript/native-preview@7.0.0-dev.20260304.1': + '@typescript/native-preview@7.0.0-dev.20260324.1': optionalDependencies: - '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260304.1 - '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260304.1 - '@typescript/native-preview-linux-arm': 7.0.0-dev.20260304.1 - '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260304.1 - '@typescript/native-preview-linux-x64': 7.0.0-dev.20260304.1 - '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260304.1 - '@typescript/native-preview-win32-x64': 7.0.0-dev.20260304.1 + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260324.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260324.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20260324.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260324.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20260324.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260324.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20260324.1 '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-react@5.1.4(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))': + '@upsetjs/venn.js@2.0.0': + optionalDependencies: + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + '@vitejs/plugin-react@6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) - '@rolldown/pluginutils': 1.0.0-rc.3 - '@types/babel__core': 7.20.5 - react-refresh: 0.18.0 - vite: rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) + '@rolldown/pluginutils': 1.0.0-rc.7 + vite: 8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) + optionalDependencies: + babel-plugin-react-compiler: 1.0.0 + + '@vitest/browser-playwright@4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(playwright@1.59.1)(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))(vitest@4.1.2)': + dependencies: + '@vitest/browser': 4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))(vitest@4.1.2) + '@vitest/mocker': 4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) + playwright: 1.59.1 + tinyrainbow: 3.1.0 + vitest: 4.1.2(@types/node@25.5.2)(@vitest/browser-playwright@4.1.2)(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) transitivePeerDependencies: - - supports-color + - bufferutil + - msw + - utf-8-validate + - vite + + '@vitest/browser@4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))(vitest@4.1.2)': + dependencies: + '@blazediff/core': 1.9.1 + '@vitest/mocker': 4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) + '@vitest/utils': 4.1.2 + magic-string: 0.30.21 + pngjs: 7.0.0 + sirv: 3.0.2 + tinyrainbow: 3.1.0 + vitest: 4.1.2(@types/node@25.5.2)(@vitest/browser-playwright@4.1.2)(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) + ws: 8.20.0 + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite '@vitest/expect@3.2.4': dependencies: @@ -6956,40 +6978,41 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/expect@4.0.18': + '@vitest/expect@4.1.2': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 + '@vitest/spy': 4.1.2 + '@vitest/utils': 4.1.2 chai: 6.2.2 - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 - '@vitest/mocker@4.0.18(msw@2.12.10(@types/node@25.4.0)(typescript@6.0.0-beta))(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))': + '@vitest/mocker@4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))': dependencies: - '@vitest/spy': 4.0.18 + '@vitest/spy': 4.1.2 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.12.10(@types/node@25.4.0)(typescript@6.0.0-beta) - vite: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) + msw: 2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta) + vite: 8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@4.0.18': + '@vitest/pretty-format@4.1.2': dependencies: - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 - '@vitest/runner@4.0.18': + '@vitest/runner@4.1.2': dependencies: - '@vitest/utils': 4.0.18 + '@vitest/utils': 4.1.2 pathe: 2.0.3 - '@vitest/snapshot@4.0.18': + '@vitest/snapshot@4.1.2': dependencies: - '@vitest/pretty-format': 4.0.18 + '@vitest/pretty-format': 4.1.2 + '@vitest/utils': 4.1.2 magic-string: 0.30.21 pathe: 2.0.3 @@ -6997,7 +7020,7 @@ snapshots: dependencies: tinyspy: 4.0.4 - '@vitest/spy@4.0.18': {} + '@vitest/spy@4.1.2': {} '@vitest/utils@3.2.4': dependencies: @@ -7005,20 +7028,19 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 - '@vitest/utils@4.0.18': + '@vitest/utils@4.1.2': dependencies: - '@vitest/pretty-format': 4.0.18 - tinyrainbow: 3.0.3 + '@vitest/pretty-format': 4.1.2 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + + '@webcontainer/env@1.1.1': {} accepts@2.0.0: dependencies: mime-types: 3.0.2 negotiator: 1.0.0 - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - acorn@8.16.0: {} agent-base@7.1.4: {} @@ -7027,13 +7049,6 @@ snapshots: optionalDependencies: ajv: 8.18.0 - ajv@6.14.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 @@ -7053,14 +7068,12 @@ snapshots: ansi-styles@5.2.0: {} - ansi-styles@6.2.3: {} - ansis@4.2.0: {} anymatch@3.1.3: dependencies: normalize-path: 3.0.0 - picomatch: 2.3.1 + picomatch: 2.3.2 argparse@2.0.1: {} @@ -7082,20 +7095,20 @@ snapshots: asynckit@0.4.0: {} - axe-core@4.11.1: {} + axe-core@4.11.2: {} - axios@1.13.6: + axios@1.14.0: dependencies: follow-redirects: 1.15.11 form-data: 4.0.5 - proxy-from-env: 1.1.0 + proxy-from-env: 2.1.0 transitivePeerDependencies: - debug babel-dead-code-elimination@1.0.12: dependencies: '@babel/core': 7.29.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 transitivePeerDependencies: @@ -7107,13 +7120,11 @@ snapshots: bail@2.0.2: {} - balanced-match@1.0.2: {} - balanced-match@4.0.4: {} base64-js@1.5.1: {} - baseline-browser-mapping@2.10.0: {} + baseline-browser-mapping@2.10.16: {} bignumber.js@9.3.1: {} @@ -7133,16 +7144,7 @@ snapshots: transitivePeerDependencies: - supports-color - brace-expansion@1.1.12: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.2: - dependencies: - balanced-match: 1.0.2 - - brace-expansion@5.0.4: + brace-expansion@5.0.5: dependencies: balanced-match: 4.0.4 @@ -7150,13 +7152,13 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.28.1: + browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.0 - caniuse-lite: 1.0.30001777 - electron-to-chromium: 1.5.307 - node-releases: 2.0.36 - update-browserslist-db: 1.2.3(browserslist@4.28.1) + baseline-browser-mapping: 2.10.16 + caniuse-lite: 1.0.30001786 + electron-to-chromium: 1.5.332 + node-releases: 2.0.37 + update-browserslist-db: 1.2.3(browserslist@4.28.2) buffer-equal-constant-time@1.0.1: {} @@ -7170,8 +7172,8 @@ snapshots: dependencies: chokidar: 5.0.0 confbox: 0.2.4 - defu: 6.1.4 - dotenv: 17.3.1 + defu: 6.1.6 + dotenv: 17.4.1 exsolve: 1.0.8 giget: 2.0.0 jiti: 2.6.1 @@ -7193,7 +7195,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001777: {} + caniuse-lite@1.0.30001786: {} ccount@2.0.1: {} @@ -7207,11 +7209,6 @@ snapshots: chai@6.2.2: {} - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - chalk@5.6.2: {} character-entities-html4@2.1.0: {} @@ -7224,6 +7221,20 @@ snapshots: check-error@2.1.3: {} + chevrotain-allstar@0.3.1(chevrotain@11.1.2): + dependencies: + chevrotain: 11.1.2 + lodash-es: 4.18.1 + + chevrotain@11.1.2: + dependencies: + '@chevrotain/cst-dts-gen': 11.1.2 + '@chevrotain/gast': 11.1.2 + '@chevrotain/regexp-to-ast': 11.1.2 + '@chevrotain/types': 11.1.2 + '@chevrotain/utils': 11.1.2 + lodash-es: 4.17.23 + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -7244,7 +7255,7 @@ snapshots: dependencies: consola: 3.4.2 - citty@0.2.1: {} + citty@0.2.2: {} class-variance-authority@0.7.1: dependencies: @@ -7298,7 +7309,11 @@ snapshots: commander@14.0.3: {} - concat-map@0.0.1: {} + commander@7.2.0: {} + + commander@8.3.0: {} + + confbox@0.1.8: {} confbox@0.2.4: {} @@ -7310,7 +7325,7 @@ snapshots: convert-source-map@2.0.0: {} - cookie-es@2.0.0: {} + cookie-es@2.0.1: {} cookie-signature@1.2.2: {} @@ -7323,6 +7338,14 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + cosmiconfig@9.0.1(typescript@6.0.0-beta): dependencies: env-paths: 2.2.1 @@ -7344,22 +7367,107 @@ snapshots: csstype@3.2.3: {} + cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.2): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.33.2 + + cytoscape-fcose@2.2.0(cytoscape@3.33.2): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.33.2 + + cytoscape@3.33.2: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + d3-array@3.2.4: dependencies: internmap: 2.0.3 + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + d3-color@3.1.0: {} + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.1.0 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + d3-ease@3.0.1: {} + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + d3-format@3.1.2: {} + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + d3-interpolate@3.0.1: dependencies: d3-color: 3.1.0 + d3-path@1.0.9: {} + d3-path@3.1.0: {} + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + d3-scale@4.0.2: dependencies: d3-array: 3.2.4 @@ -7368,6 +7476,12 @@ snapshots: d3-time: 3.1.0 d3-time-format: 4.1.0 + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + d3-shape@3.2.0: dependencies: d3-path: 3.1.0 @@ -7382,13 +7496,68 @@ snapshots: d3-timer@3.0.1: {} + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.2 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.14: + dependencies: + d3: 7.9.0 + lodash-es: 4.18.1 + data-uri-to-buffer@4.0.1: {} date-fns-jalali@4.1.0-0: {} date-fns@4.1.0: {} - dayjs@1.11.19: {} + dayjs@1.11.20: {} debug@4.4.3: dependencies: @@ -7404,8 +7573,6 @@ snapshots: deep-eql@5.0.2: {} - deep-is@0.1.4: {} - deepmerge@4.3.1: {} default-browser-id@5.0.1: {} @@ -7417,7 +7584,11 @@ snapshots: define-lazy-prop@3.0.0: {} - defu@6.1.4: {} + defu@6.1.6: {} + + delaunator@5.1.0: + dependencies: + robust-predicates: 3.0.3 delayed-stream@1.0.0: {} @@ -7435,7 +7606,7 @@ snapshots: dependencies: dequal: 2.0.3 - diff@8.0.3: {} + diff@8.0.4: {} doctrine@3.0.0: dependencies: @@ -7445,7 +7616,11 @@ snapshots: dom-accessibility-api@0.6.3: {} - dotenv@17.3.1: {} + dompurify@3.3.3: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + dotenv@17.4.1: {} dunder-proto@1.0.1: dependencies: @@ -7453,22 +7628,20 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - eastasianwidth@0.2.0: {} - ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 eciesjs@0.4.18: dependencies: - '@ecies/ciphers': 0.2.5(@noble/ciphers@1.3.0) + '@ecies/ciphers': 0.2.6(@noble/ciphers@1.3.0) '@noble/ciphers': 1.3.0 '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 ee-first@1.1.1: {} - electron-to-chromium@1.5.307: {} + electron-to-chromium@1.5.332: {} embla-carousel-react@8.6.0(react@19.2.4): dependencies: @@ -7486,16 +7659,14 @@ snapshots: emoji-regex@8.0.0: {} - emoji-regex@9.2.2: {} - empathic@2.0.0: {} encodeurl@2.0.0: {} - enhanced-resolve@5.20.0: + enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 + tapable: 2.3.2 entities@6.0.1: {} @@ -7509,7 +7680,7 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} es-object-atoms@1.1.1: dependencies: @@ -7524,122 +7695,43 @@ snapshots: es-toolkit@1.45.1: {} - esbuild@0.27.3: + esbuild@0.27.7: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 escalade@3.2.0: {} escape-html@1.0.3: {} - escape-string-regexp@4.0.0: {} - escape-string-regexp@5.0.0: {} - eslint-plugin-react-hooks@7.0.1(eslint@9.39.3(jiti@2.6.1)): - dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.0 - eslint: 9.39.3(jiti@2.6.1) - hermes-parser: 0.25.1 - zod: 4.3.6 - zod-validation-error: 4.0.2(zod@4.3.6) - transitivePeerDependencies: - - supports-color - - eslint-scope@8.4.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.1: {} - - eslint@9.39.3(jiti@2.6.1): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.6.1)) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.5 - '@eslint/js': 9.39.3 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.14.0 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.5 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.6.1 - transitivePeerDependencies: - - supports-color - - espree@10.4.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 4.2.1 - esprima@4.0.1: {} - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - estree-util-is-identifier-name@3.0.0: {} estree-walker@2.0.2: {} @@ -7689,7 +7781,7 @@ snapshots: expect-type@1.3.0: {} - express-rate-limit@8.3.1(express@5.2.1): + express-rate-limit@8.3.2(express@5.2.1): dependencies: express: 5.2.1 ip-address: 10.1.0 @@ -7741,19 +7833,15 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - fast-uri@3.1.0: {} fastq@1.20.1: dependencies: reusify: 1.1.0 - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.4 fetch-blob@3.2.0: dependencies: @@ -7764,10 +7852,6 @@ snapshots: dependencies: is-unicode-supported: 2.1.0 - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -7783,25 +7867,8 @@ snapshots: transitivePeerDependencies: - supports-color - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.4.1 - keyv: 4.5.4 - - flatted@3.4.1: {} - follow-redirects@1.15.11: {} - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - form-data@4.0.5: dependencies: asynckit: 0.4.0 @@ -7834,20 +7901,17 @@ snapshots: fuzzysort@3.1.0: {} - fzf@0.5.2: {} - - gaxios@7.1.3: + gaxios@7.1.4: dependencies: extend: 3.0.2 https-proxy-agent: 7.0.6 node-fetch: 3.3.2 - rimraf: 5.0.10 transitivePeerDependencies: - supports-color gcp-metadata@8.1.2: dependencies: - gaxios: 7.1.3 + gaxios: 7.1.4 google-logging-utils: 1.1.3 json-bigint: 1.0.0 transitivePeerDependencies: @@ -7892,11 +7956,15 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-tsconfig@4.13.7: + dependencies: + resolve-pkg-maps: 1.0.0 + giget@2.0.0: dependencies: citty: 0.1.6 consola: 3.4.2 - defu: 6.1.4 + defu: 6.1.6 node-fetch-native: 1.6.7 nypm: 0.6.5 pathe: 2.0.3 @@ -7905,38 +7973,21 @@ snapshots: dependencies: is-glob: 4.0.3 - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob@10.5.0: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.9 - minipass: 7.1.3 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - glob@13.0.6: dependencies: - minimatch: 10.2.4 + minimatch: 10.2.5 minipass: 7.1.3 path-scurry: 2.0.2 - globals@14.0.0: {} - - globrex@0.1.2: {} - goober@2.1.18(csstype@3.2.3): dependencies: csstype: 3.2.3 - google-auth-library@10.6.1: + google-auth-library@10.6.2: dependencies: base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - gaxios: 7.1.3 + gaxios: 7.1.4 gcp-metadata: 8.1.2 google-logging-utils: 1.1.3 jws: 4.0.1 @@ -7949,9 +8000,9 @@ snapshots: graceful-fs@4.2.11: {} - graphql@16.13.1: {} + graphql@16.13.2: {} - has-flag@4.0.0: {} + hachure-fill@0.5.2: {} has-symbols@1.1.0: {} @@ -8044,15 +8095,9 @@ snapshots: headers-polyfill@4.0.3: {} - hermes-estree@0.25.1: {} - - hermes-parser@0.25.1: - dependencies: - hermes-estree: 0.25.1 - highlight.js@11.11.1: {} - hono@4.12.5: {} + hono@4.12.12: {} html-url-attributes@3.0.1: {} @@ -8077,6 +8122,10 @@ snapshots: human-signals@8.0.1: {} + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 @@ -8092,8 +8141,6 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 - imurmurhash@0.1.4: {} - indent-string@4.0.0: {} inherits@2.0.4: {} @@ -8105,6 +8152,8 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + internmap@1.0.1: {} + internmap@2.0.3: {} ip-address@10.1.0: {} @@ -8174,21 +8223,15 @@ snapshots: dependencies: is-inside-container: 1.0.0 - isbot@5.1.35: {} + isbot@5.1.37: {} isexe@2.0.0: {} isexe@3.1.5: {} - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - jiti@2.6.1: {} - jose@6.2.1: {} + jose@6.2.2: {} js-tokens@4.0.0: {} @@ -8202,23 +8245,17 @@ snapshots: dependencies: bignumber.js: 9.3.1 - json-buffer@3.0.1: {} - json-parse-even-better-errors@2.3.1: {} json-schema-to-ts@3.1.1: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 ts-algebra: 2.0.0 - json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: {} json-schema-typed@8.0.2: {} - json-stable-stringify-without-jsonify@1.0.1: {} - json5@2.2.3: {} jsonfile@6.2.0: @@ -8238,106 +8275,66 @@ snapshots: jwa: 2.0.1 safe-buffer: 5.2.1 - keyv@4.5.4: + katex@0.16.45: dependencies: - json-buffer: 3.0.1 + commander: 8.3.0 + + khroma@2.1.0: {} kleur@3.0.3: {} kleur@4.1.5: {} - launch-editor@2.13.1: + langium@4.2.1: + dependencies: + chevrotain: 11.1.2 + chevrotain-allstar: 0.3.1(chevrotain@11.1.2) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + launch-editor@2.13.2: dependencies: picocolors: 1.1.1 shell-quote: 1.8.3 - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 + layout-base@1.0.2: {} - lightningcss-android-arm64@1.31.1: - optional: true + layout-base@2.0.1: {} lightningcss-android-arm64@1.32.0: optional: true - lightningcss-darwin-arm64@1.31.1: - optional: true - lightningcss-darwin-arm64@1.32.0: optional: true - lightningcss-darwin-x64@1.31.1: - optional: true - lightningcss-darwin-x64@1.32.0: optional: true - lightningcss-freebsd-x64@1.31.1: - optional: true - lightningcss-freebsd-x64@1.32.0: optional: true - lightningcss-linux-arm-gnueabihf@1.31.1: - optional: true - lightningcss-linux-arm-gnueabihf@1.32.0: optional: true - lightningcss-linux-arm64-gnu@1.31.1: - optional: true - lightningcss-linux-arm64-gnu@1.32.0: optional: true - lightningcss-linux-arm64-musl@1.31.1: - optional: true - lightningcss-linux-arm64-musl@1.32.0: optional: true - lightningcss-linux-x64-gnu@1.31.1: - optional: true - lightningcss-linux-x64-gnu@1.32.0: optional: true - lightningcss-linux-x64-musl@1.31.1: - optional: true - lightningcss-linux-x64-musl@1.32.0: optional: true - lightningcss-win32-arm64-msvc@1.31.1: - optional: true - lightningcss-win32-arm64-msvc@1.32.0: optional: true - lightningcss-win32-x64-msvc@1.31.1: - optional: true - lightningcss-win32-x64-msvc@1.32.0: optional: true - lightningcss@1.31.1: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.31.1 - lightningcss-darwin-arm64: 1.31.1 - lightningcss-darwin-x64: 1.31.1 - lightningcss-freebsd-x64: 1.31.1 - lightningcss-linux-arm-gnueabihf: 1.31.1 - lightningcss-linux-arm64-gnu: 1.31.1 - lightningcss-linux-arm64-musl: 1.31.1 - lightningcss-linux-x64-gnu: 1.31.1 - lightningcss-linux-x64-musl: 1.31.1 - lightningcss-win32-arm64-msvc: 1.31.1 - lightningcss-win32-x64-msvc: 1.31.1 - lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 @@ -8356,11 +8353,9 @@ snapshots: lines-and-columns@1.2.4: {} - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 + lodash-es@4.17.23: {} - lodash.merge@4.6.2: {} + lodash-es@4.18.1: {} log-symbols@6.0.0: dependencies: @@ -8373,18 +8368,12 @@ snapshots: loupe@3.2.1: {} - lru-cache@10.4.3: {} - - lru-cache@11.2.6: {} + lru-cache@11.3.2: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 - lucide-react@0.577.0(react@19.2.4): - dependencies: - react: 19.2.4 - lz-string@1.5.0: {} magic-string@0.30.21: @@ -8393,7 +8382,9 @@ snapshots: markdown-table@3.0.4: {} - marked@17.0.4: {} + marked@16.4.2: {} + + marked@17.0.6: {} math-intrinsics@1.1.0: {} @@ -8558,6 +8549,30 @@ snapshots: merge2@1.4.1: {} + mermaid@11.14.0: + dependencies: + '@braintree/sanitize-url': 7.1.2 + '@iconify/utils': 3.1.0 + '@mermaid-js/parser': 1.1.0 + '@types/d3': 7.4.3 + '@upsetjs/venn.js': 2.0.0 + cytoscape: 3.33.2 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.2) + cytoscape-fcose: 2.2.0(cytoscape@3.33.2) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.14 + dayjs: 1.11.20 + dompurify: 3.3.3 + katex: 0.16.45 + khroma: 2.1.0 + lodash-es: 4.18.1 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.3.6 + ts-dedent: 2.2.0 + uuid: 11.1.0 + micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.3.0 @@ -8729,7 +8744,7 @@ snapshots: micromark@4.0.2: dependencies: - '@types/debug': 4.1.12 + '@types/debug': 4.1.13 debug: 4.4.3 decode-named-character-reference: 1.3.0 devlop: 1.1.0 @@ -8752,7 +8767,7 @@ snapshots: micromatch@4.0.8: dependencies: braces: 3.0.3 - picomatch: 2.3.1 + picomatch: 2.3.2 mime-db@1.52.0: {} @@ -8772,32 +8787,33 @@ snapshots: min-indent@1.0.1: {} - minimatch@10.2.4: - dependencies: - brace-expansion: 5.0.4 - - minimatch@3.1.5: + minimatch@10.2.5: dependencies: - brace-expansion: 1.1.12 - - minimatch@9.0.9: - dependencies: - brace-expansion: 2.0.2 + brace-expansion: 5.0.5 minimist@1.2.8: {} minipass@7.1.3: {} + mlly@1.8.2: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.3 + + mrmime@2.0.1: {} + ms@2.1.3: {} - msw@2.12.10(@types/node@25.4.0)(typescript@6.0.0-beta): + msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta): dependencies: - '@inquirer/confirm': 5.1.21(@types/node@25.4.0) + '@inquirer/confirm': 5.1.21(@types/node@25.5.2) '@mswjs/interceptors': 0.41.3 '@open-draft/deferred-promise': 2.2.0 '@types/statuses': 2.0.6 cookie: 1.1.1 - graphql: 16.13.1 + graphql: 16.13.2 headers-polyfill: 4.0.3 is-node-process: 1.2.0 outvariant: 1.4.3 @@ -8806,8 +8822,8 @@ snapshots: rettime: 0.10.1 statuses: 2.0.2 strict-event-emitter: 0.5.1 - tough-cookie: 6.0.0 - type-fest: 5.4.4 + tough-cookie: 6.0.1 + type-fest: 5.5.0 until-async: 3.0.2 yargs: 17.7.2 optionalDependencies: @@ -8819,8 +8835,6 @@ snapshots: nanoid@3.3.11: {} - natural-compare@1.4.0: {} - negotiator@1.0.0: {} next-themes@0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4): @@ -8838,7 +8852,7 @@ snapshots: fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 - node-releases@2.0.36: {} + node-releases@2.0.37: {} normalize-path@3.0.0: {} @@ -8853,9 +8867,9 @@ snapshots: nypm@0.6.5: dependencies: - citty: 0.2.1 + citty: 0.2.2 pathe: 2.0.3 - tinyexec: 1.0.2 + tinyexec: 1.0.4 object-assign@4.1.1: {} @@ -8903,20 +8917,11 @@ snapshots: powershell-utils: 0.1.0 wsl-utils: 0.3.1 - openai@6.27.0(ws@8.19.0)(zod@4.3.6): + openai@6.33.0(ws@8.20.0)(zod@4.3.6): optionalDependencies: - ws: 8.19.0 + ws: 8.20.0 zod: 4.3.6 - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - ora@8.2.0: dependencies: chalk: 5.6.2 @@ -8931,67 +8936,57 @@ snapshots: outvariant@1.4.3: {} - oxfmt@0.36.0: + oxfmt@0.42.0: dependencies: tinypool: 2.1.0 optionalDependencies: - '@oxfmt/binding-android-arm-eabi': 0.36.0 - '@oxfmt/binding-android-arm64': 0.36.0 - '@oxfmt/binding-darwin-arm64': 0.36.0 - '@oxfmt/binding-darwin-x64': 0.36.0 - '@oxfmt/binding-freebsd-x64': 0.36.0 - '@oxfmt/binding-linux-arm-gnueabihf': 0.36.0 - '@oxfmt/binding-linux-arm-musleabihf': 0.36.0 - '@oxfmt/binding-linux-arm64-gnu': 0.36.0 - '@oxfmt/binding-linux-arm64-musl': 0.36.0 - '@oxfmt/binding-linux-ppc64-gnu': 0.36.0 - '@oxfmt/binding-linux-riscv64-gnu': 0.36.0 - '@oxfmt/binding-linux-riscv64-musl': 0.36.0 - '@oxfmt/binding-linux-s390x-gnu': 0.36.0 - '@oxfmt/binding-linux-x64-gnu': 0.36.0 - '@oxfmt/binding-linux-x64-musl': 0.36.0 - '@oxfmt/binding-openharmony-arm64': 0.36.0 - '@oxfmt/binding-win32-arm64-msvc': 0.36.0 - '@oxfmt/binding-win32-ia32-msvc': 0.36.0 - '@oxfmt/binding-win32-x64-msvc': 0.36.0 - - oxlint@1.51.0: + '@oxfmt/binding-android-arm-eabi': 0.42.0 + '@oxfmt/binding-android-arm64': 0.42.0 + '@oxfmt/binding-darwin-arm64': 0.42.0 + '@oxfmt/binding-darwin-x64': 0.42.0 + '@oxfmt/binding-freebsd-x64': 0.42.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.42.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.42.0 + '@oxfmt/binding-linux-arm64-gnu': 0.42.0 + '@oxfmt/binding-linux-arm64-musl': 0.42.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.42.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.42.0 + '@oxfmt/binding-linux-riscv64-musl': 0.42.0 + '@oxfmt/binding-linux-s390x-gnu': 0.42.0 + '@oxfmt/binding-linux-x64-gnu': 0.42.0 + '@oxfmt/binding-linux-x64-musl': 0.42.0 + '@oxfmt/binding-openharmony-arm64': 0.42.0 + '@oxfmt/binding-win32-arm64-msvc': 0.42.0 + '@oxfmt/binding-win32-ia32-msvc': 0.42.0 + '@oxfmt/binding-win32-x64-msvc': 0.42.0 + + oxlint@1.59.0: optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.51.0 - '@oxlint/binding-android-arm64': 1.51.0 - '@oxlint/binding-darwin-arm64': 1.51.0 - '@oxlint/binding-darwin-x64': 1.51.0 - '@oxlint/binding-freebsd-x64': 1.51.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.51.0 - '@oxlint/binding-linux-arm-musleabihf': 1.51.0 - '@oxlint/binding-linux-arm64-gnu': 1.51.0 - '@oxlint/binding-linux-arm64-musl': 1.51.0 - '@oxlint/binding-linux-ppc64-gnu': 1.51.0 - '@oxlint/binding-linux-riscv64-gnu': 1.51.0 - '@oxlint/binding-linux-riscv64-musl': 1.51.0 - '@oxlint/binding-linux-s390x-gnu': 1.51.0 - '@oxlint/binding-linux-x64-gnu': 1.51.0 - '@oxlint/binding-linux-x64-musl': 1.51.0 - '@oxlint/binding-openharmony-arm64': 1.51.0 - '@oxlint/binding-win32-arm64-msvc': 1.51.0 - '@oxlint/binding-win32-ia32-msvc': 1.51.0 - '@oxlint/binding-win32-x64-msvc': 1.51.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 + '@oxlint/binding-android-arm-eabi': 1.59.0 + '@oxlint/binding-android-arm64': 1.59.0 + '@oxlint/binding-darwin-arm64': 1.59.0 + '@oxlint/binding-darwin-x64': 1.59.0 + '@oxlint/binding-freebsd-x64': 1.59.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.59.0 + '@oxlint/binding-linux-arm-musleabihf': 1.59.0 + '@oxlint/binding-linux-arm64-gnu': 1.59.0 + '@oxlint/binding-linux-arm64-musl': 1.59.0 + '@oxlint/binding-linux-ppc64-gnu': 1.59.0 + '@oxlint/binding-linux-riscv64-gnu': 1.59.0 + '@oxlint/binding-linux-riscv64-musl': 1.59.0 + '@oxlint/binding-linux-s390x-gnu': 1.59.0 + '@oxlint/binding-linux-x64-gnu': 1.59.0 + '@oxlint/binding-linux-x64-musl': 1.59.0 + '@oxlint/binding-openharmony-arm64': 1.59.0 + '@oxlint/binding-win32-arm64-msvc': 1.59.0 + '@oxlint/binding-win32-ia32-msvc': 1.59.0 + '@oxlint/binding-win32-x64-msvc': 1.59.0 p-retry@4.6.2: dependencies: '@types/retry': 0.12.0 retry: 0.13.1 - package-json-from-dist@1.0.1: {} - package-manager-detector@1.6.0: {} parent-module@1.0.1: @@ -9027,7 +9022,7 @@ snapshots: path-browserify@1.0.1: {} - path-exists@4.0.0: {} + path-data-parser@0.1.0: {} path-key@3.1.1: {} @@ -9035,19 +9030,14 @@ snapshots: path-parse@1.0.7: {} - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.3 - path-scurry@2.0.2: dependencies: - lru-cache: 11.2.6 + lru-cache: 11.3.2 minipass: 7.1.3 path-to-regexp@6.3.0: {} - path-to-regexp@8.3.0: {} + path-to-regexp@8.4.2: {} pathe@2.0.3: {} @@ -9057,26 +9047,41 @@ snapshots: picocolors@1.1.1: {} - picomatch@2.3.1: {} + picomatch@2.3.2: {} - picomatch@4.0.3: {} + picomatch@4.0.4: {} pkce-challenge@5.0.1: {} + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + pkg-types@2.3.0: dependencies: confbox: 0.2.4 exsolve: 1.0.8 pathe: 2.0.3 - playwright-core@1.58.2: {} + playwright-core@1.59.1: {} - playwright@1.58.2: + playwright@1.59.1: dependencies: - playwright-core: 1.58.2 + playwright-core: 1.59.1 optionalDependencies: fsevents: 2.3.2 + pngjs@7.0.0: {} + + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + postcss-selector-parser@7.1.1: dependencies: cssesc: 3.0.0 @@ -9088,12 +9093,10 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postgres@3.4.8: {} + postgres@3.4.9: {} powershell-utils@0.1.0: {} - prelude-ls@1.2.1: {} - prettier@3.8.1: {} pretty-format@27.5.1: @@ -9125,7 +9128,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 25.4.0 + '@types/node': 25.5.2 long: 5.3.2 proxy-addr@2.0.7: @@ -9133,9 +9136,7 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - proxy-from-env@1.1.0: {} - - punycode@2.3.1: {} + proxy-from-env@2.1.0: {} qs@6.15.0: dependencies: @@ -9154,7 +9155,7 @@ snapshots: rc9@2.1.2: dependencies: - defu: 6.1.4 + defu: 6.1.6 destr: 2.0.5 react-day-picker@9.14.0(react@19.2.4): @@ -9169,7 +9170,7 @@ snapshots: dependencies: typescript: 6.0.0-beta - react-docgen@8.0.2: + react-docgen@8.0.3: dependencies: '@babel/core': 7.29.0 '@babel/traverse': 7.29.0 @@ -9189,10 +9190,6 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 - react-icons@5.6.0(react@19.2.4): - dependencies: - react: 19.2.4 - react-is@17.0.2: {} react-is@19.2.4: {} @@ -9206,8 +9203,6 @@ snapshots: '@types/react': 19.2.14 redux: 5.0.1 - react-refresh@0.18.0: {} - react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.4): dependencies: react: 19.2.4 @@ -9227,7 +9222,7 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - react-resizable-panels@4.7.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-resizable-panels@4.9.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) @@ -9244,7 +9239,7 @@ snapshots: readdirp@3.6.0: dependencies: - picomatch: 2.3.1 + picomatch: 2.3.2 readdirp@5.0.0: {} @@ -9256,7 +9251,7 @@ snapshots: tiny-invariant: 1.3.3 tslib: 2.8.1 - recharts@3.7.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@19.2.4)(react@19.2.4)(redux@5.0.1): + recharts@3.8.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@19.2.4)(react@19.2.4)(redux@5.0.1): dependencies: '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1))(react@19.2.4) clsx: 2.1.1 @@ -9336,7 +9331,7 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 - remend@1.2.2: {} + remend@1.3.0: {} remove-accents@0.5.0: {} @@ -9367,44 +9362,31 @@ snapshots: reusify@1.1.0: {} - rimraf@5.0.10: - dependencies: - glob: 10.5.0 + robust-predicates@3.0.3: {} - rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0): + rolldown@1.0.0-rc.11(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1): dependencies: - '@oxc-project/runtime': 0.101.0 - fdir: 6.5.0(picomatch@4.0.3) - lightningcss: 1.32.0 - picomatch: 4.0.3 - postcss: 8.5.8 - rolldown: 1.0.0-beta.53 - tinyglobby: 0.2.15 + '@oxc-project/types': 0.122.0 + '@rolldown/pluginutils': 1.0.0-rc.11 optionalDependencies: - '@types/node': 25.4.0 - esbuild: 0.27.3 - fsevents: 2.3.3 - jiti: 2.6.1 - tsx: 4.21.0 - - rolldown@1.0.0-beta.53: - dependencies: - '@oxc-project/types': 0.101.0 - '@rolldown/pluginutils': 1.0.0-beta.53 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.53 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.53 - '@rolldown/binding-darwin-x64': 1.0.0-beta.53 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.53 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.53 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.53 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.53 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.53 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.53 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.53 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.53 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.53 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.53 + '@rolldown/binding-android-arm64': 1.0.0-rc.11 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.11 + '@rolldown/binding-darwin-x64': 1.0.0-rc.11 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.11 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.11 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.11 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.11 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.11 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.11 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.11(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.11 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.11 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' rollup@4.59.0: dependencies: @@ -9436,6 +9418,14 @@ snapshots: '@rollup/rollup-win32-x64-gnu': 4.59.0 '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 + optional: true + + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 router@2.2.0: dependencies: @@ -9443,7 +9433,7 @@ snapshots: depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 - path-to-regexp: 8.3.0 + path-to-regexp: 8.4.2 transitivePeerDependencies: - supports-color @@ -9453,6 +9443,8 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: {} + safe-buffer@5.2.1: {} safer-buffer@2.1.2: {} @@ -9481,11 +9473,11 @@ snapshots: transitivePeerDependencies: - supports-color - seroval-plugins@1.5.1(seroval@1.5.1): + seroval-plugins@1.5.2(seroval@1.5.2): dependencies: - seroval: 1.5.1 + seroval: 1.5.2 - seroval@1.5.1: {} + seroval@1.5.2: {} serve-static@2.2.1: dependencies: @@ -9498,29 +9490,28 @@ snapshots: setprototypeof@1.2.0: {} - shadcn@3.8.5(@types/node@25.4.0)(typescript@6.0.0-beta): + shadcn@4.1.2(@types/node@25.5.2)(typescript@6.0.0-beta): dependencies: - '@antfu/ni': 25.0.0 '@babel/core': 7.29.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@dotenvx/dotenvx': 1.54.1 - '@modelcontextprotocol/sdk': 1.27.1(zod@3.25.76) + '@dotenvx/dotenvx': 1.60.1 + '@modelcontextprotocol/sdk': 1.29.0(zod@3.25.76) '@types/validate-npm-package-name': 4.0.2 - browserslist: 4.28.1 + browserslist: 4.28.2 commander: 14.0.3 cosmiconfig: 9.0.1(typescript@6.0.0-beta) dedent: 1.7.2 deepmerge: 4.3.1 - diff: 8.0.3 + diff: 8.0.4 execa: 9.6.1 fast-glob: 3.3.3 fs-extra: 11.3.4 fuzzysort: 3.1.0 https-proxy-agent: 7.0.6 kleur: 4.1.5 - msw: 2.12.10(@types/node@25.4.0)(typescript@6.0.0-beta) + msw: 2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta) node-fetch: 3.3.2 open: 11.0.0 ora: 8.2.0 @@ -9534,7 +9525,7 @@ snapshots: tsconfig-paths: 4.2.0 validate-npm-package-name: 7.0.2 zod: 3.25.76 - zod-to-json-schema: 3.25.1(zod@3.25.76) + zod-to-json-schema: 3.25.2(zod@3.25.76) transitivePeerDependencies: - '@cfworker/json-schema' - '@types/node' @@ -9584,13 +9575,19 @@ snapshots: signal-exit@4.1.0: {} + sirv@3.0.2: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + sisteransi@1.0.5: {} - solid-js@1.9.11: + solid-js@1.9.12: dependencies: csstype: 3.2.3 - seroval: 1.5.1 - seroval-plugins: 1.5.1(seroval@1.5.1) + seroval: 1.5.2 + seroval-plugins: 1.5.2(seroval@1.5.2) sonner@2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: @@ -9609,11 +9606,11 @@ snapshots: statuses@2.0.2: {} - std-env@3.10.0: {} + std-env@4.0.0: {} stdin-discarder@0.2.2: {} - storybook@10.2.17(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -9621,12 +9618,13 @@ snapshots: '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) '@vitest/expect': 3.2.4 '@vitest/spy': 3.2.4 - esbuild: 0.27.3 + '@webcontainer/env': 1.1.1 + esbuild: 0.27.7 open: 10.2.0 recast: 0.23.11 semver: 7.7.4 use-sync-external-store: 1.6.0(react@19.2.4) - ws: 8.19.0 + ws: 8.20.0 optionalDependencies: prettier: 3.8.1 transitivePeerDependencies: @@ -9636,12 +9634,13 @@ snapshots: - react-dom - utf-8-validate - streamdown@2.4.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + streamdown@2.5.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: clsx: 2.1.1 hast-util-to-jsx-runtime: 2.3.6 html-url-attributes: 3.0.1 - marked: 17.0.4 + marked: 17.0.6 + mermaid: 11.14.0 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) rehype-harden: 1.1.8 @@ -9650,7 +9649,7 @@ snapshots: remark-gfm: 4.0.1 remark-parse: 11.0.0 remark-rehype: 11.1.2 - remend: 1.2.2 + remend: 1.3.0 tailwind-merge: 3.5.0 unified: 11.0.5 unist-util-visit: 5.1.0 @@ -9666,12 +9665,6 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.2.0 - string-width@7.2.0: dependencies: emoji-regex: 10.6.0 @@ -9709,8 +9702,6 @@ snapshots: strip-indent@4.1.1: {} - strip-json-comments@3.1.1: {} - style-to-js@1.1.21: dependencies: style-to-object: 1.0.14 @@ -9719,9 +9710,7 @@ snapshots: dependencies: inline-style-parser: 0.2.7 - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 + stylis@4.3.6: {} supports-preserve-symlinks-flag@1.0.0: {} @@ -9731,36 +9720,34 @@ snapshots: tailwind-merge@3.5.0: {} - tailwindcss@4.2.1: {} + tailwindcss@4.2.2: {} - tapable@2.3.0: {} + tapable@2.3.2: {} tiny-invariant@1.3.3: {} - tiny-warning@1.0.3: {} - tinybench@2.9.0: {} - tinyexec@1.0.2: {} + tinyexec@1.0.4: {} tinyglobby@0.2.15: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 tinypool@2.1.0: {} tinyrainbow@2.0.0: {} - tinyrainbow@3.0.3: {} + tinyrainbow@3.1.0: {} tinyspy@4.0.4: {} - tldts-core@7.0.25: {} + tldts-core@7.0.28: {} - tldts@7.0.25: + tldts@7.0.28: dependencies: - tldts-core: 7.0.25 + tldts-core: 7.0.28 to-regex-range@5.0.1: dependencies: @@ -9768,9 +9755,11 @@ snapshots: toidentifier@1.0.1: {} - tough-cookie@6.0.0: + totalist@3.0.1: {} + + tough-cookie@6.0.1: dependencies: - tldts: 7.0.25 + tldts: 7.0.28 trim-lines@3.0.1: {} @@ -9785,10 +9774,6 @@ snapshots: '@ts-morph/common': 0.27.0 code-block-writer: 13.0.3 - tsconfck@3.1.6(typescript@6.0.0-beta): - optionalDependencies: - typescript: 6.0.0-beta - tsconfig-paths@4.2.0: dependencies: json5: 2.2.3 @@ -9799,18 +9784,14 @@ snapshots: tsx@4.21.0: dependencies: - esbuild: 0.27.3 - get-tsconfig: 4.13.6 + esbuild: 0.27.7 + get-tsconfig: 4.13.7 optionalDependencies: fsevents: 2.3.3 tw-animate-css@1.4.0: {} - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-fest@5.4.4: + type-fest@5.5.0: dependencies: tagged-tag: 1.0.0 @@ -9822,6 +9803,8 @@ snapshots: typescript@6.0.0-beta: {} + ufo@1.6.3: {} + undici-types@7.18.2: {} unicorn-magic@0.3.0: {} @@ -9867,21 +9850,17 @@ snapshots: dependencies: '@jridgewell/remapping': 2.3.5 acorn: 8.16.0 - picomatch: 4.0.3 + picomatch: 4.0.4 webpack-virtual-modules: 0.6.2 until-async@3.0.2: {} - update-browserslist-db@1.2.3(browserslist@4.28.1): + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 escalade: 3.2.0 picocolors: 1.1.1 - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.4): dependencies: react: 19.2.4 @@ -9903,6 +9882,8 @@ snapshots: util-deprecate@1.0.2: {} + uuid@11.1.0: {} + validate-npm-package-name@7.0.2: {} vary@1.1.2: {} @@ -9948,73 +9929,73 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-tsconfig-paths@6.1.1(rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))(typescript@6.0.0-beta): + vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0): dependencies: - debug: 4.4.3 - globrex: 0.1.2 - tsconfck: 3.1.6(typescript@6.0.0-beta) - vite: rolldown-vite@7.3.1(@types/node@25.4.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) - transitivePeerDependencies: - - supports-color - - typescript - - vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0): - dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + lightningcss: 1.32.0 + picomatch: 4.0.4 postcss: 8.5.8 - rollup: 4.59.0 + rolldown: 1.0.0-rc.11(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.4.0 + '@types/node': 25.5.2 + esbuild: 0.27.7 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.32.0 tsx: 4.21.0 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' - vitest@4.0.18(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.32.0)(msw@2.12.10(@types/node@25.4.0)(typescript@6.0.0-beta))(tsx@4.21.0): + vitest@4.1.2(@types/node@25.5.2)(@vitest/browser-playwright@4.1.2)(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)): dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(msw@2.12.10(@types/node@25.4.0)(typescript@6.0.0-beta))(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 + '@vitest/expect': 4.1.2 + '@vitest/mocker': 4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)) + '@vitest/pretty-format': 4.1.2 + '@vitest/runner': 4.1.2 + '@vitest/snapshot': 4.1.2 + '@vitest/spy': 4.1.2 + '@vitest/utils': 4.1.2 + es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 + picomatch: 4.0.4 + std-env: 4.0.0 tinybench: 2.9.0 - tinyexec: 1.0.2 + tinyexec: 1.0.4 tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) + tinyrainbow: 3.1.0 + vite: 8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 25.4.0 + '@types/node': 25.5.2 + '@vitest/browser-playwright': 4.1.2(msw@2.13.0(@types/node@25.5.2)(typescript@6.0.0-beta))(playwright@1.59.1)(vite@8.0.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.2)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0))(vitest@4.1.2) transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml + + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-uri@3.1.0: {} web-namespaces@2.0.1: {} web-streams-polyfill@3.3.3: {} - web-vitals@5.1.0: {} + web-vitals@5.2.0: {} webpack-virtual-modules@0.6.2: {} @@ -10033,8 +10014,6 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - word-wrap@1.2.5: {} - wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -10047,15 +10026,9 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.3 - string-width: 5.1.2 - strip-ansi: 7.2.0 - wrappy@1.0.2: {} - ws@8.19.0: {} + ws@8.20.0: {} wsl-utils@0.1.0: dependencies: @@ -10082,21 +10055,19 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yocto-queue@0.1.0: {} + yocto-spinner@1.1.0: + dependencies: + yoctocolors: 2.1.2 yoctocolors-cjs@2.1.3: {} yoctocolors@2.1.2: {} - zod-to-json-schema@3.25.1(zod@3.25.76): + zod-to-json-schema@3.25.2(zod@3.25.76): dependencies: zod: 3.25.76 - zod-to-json-schema@3.25.1(zod@4.3.6): - dependencies: - zod: 4.3.6 - - zod-validation-error@4.0.2(zod@4.3.6): + zod-to-json-schema@3.25.2(zod@4.3.6): dependencies: zod: 4.3.6 diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx deleted file mode 100644 index 3e065d1..0000000 --- a/frontend/src/App.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { ComponentExample } from '@/components/component-example' - -export function App() { - return -} - -export default App diff --git a/frontend/src/components/CardGrid.tsx b/frontend/src/components/CardGrid.tsx index ba88bd6..9ae47e2 100644 --- a/frontend/src/components/CardGrid.tsx +++ b/frontend/src/components/CardGrid.tsx @@ -1,6 +1,6 @@ -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar.tsx' -import { Button } from '@/components/ui/button.tsx' -import { Card, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card.tsx' +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' +import { Button } from '@/components/ui/button' +import { Card, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' export default function CardGrid() { const variants = ['subtle', 'outline', 'elevated'] as const diff --git a/frontend/src/components/CensusDataCard.tsx b/frontend/src/components/CensusDataCard.tsx index 1d31162..511a7cb 100644 --- a/frontend/src/components/CensusDataCard.tsx +++ b/frontend/src/components/CensusDataCard.tsx @@ -1,6 +1,11 @@ -import { AlertCircle, GraduationCap } from 'lucide-react' +import { + AlertCircleIcon, + GlobalEducationIcon, + Location01Icon, + UserGroupIcon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { useEffect, useState } from 'react' -import { FiMapPin, FiUsers } from 'react-icons/fi' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Badge } from '@/components/ui/badge' @@ -101,7 +106,7 @@ function CensusDataCard({ censusDataId, showGradeBreakdown = false }: CensusData - + Error loading census data {error} @@ -155,12 +160,12 @@ function CensusDataCard({ censusDataId, showGradeBreakdown = false }: CensusData
- +

{data.school_name}

- + {data.district_name}
@@ -182,7 +187,7 @@ function CensusDataCard({ censusDataId, showGradeBreakdown = false }: CensusData
- + Total Enrollment
diff --git a/frontend/src/components/Dashboard/DashboardD09.tsx b/frontend/src/components/Dashboard/DashboardD09.tsx deleted file mode 100644 index fbc8cc1..0000000 --- a/frontend/src/components/Dashboard/DashboardD09.tsx +++ /dev/null @@ -1,287 +0,0 @@ -import { Suspense } from 'react' -import { - FiActivity, - FiArrowDown, - FiArrowUp, - FiDollarSign, - FiSettings, - FiShoppingCart, - FiUser, -} from 'react-icons/fi' - -import { Badge } from '@/components/ui/badge' -import { Button } from '@/components/ui/button' -import { Card, CardContent, CardFooter, CardHeader } from '@/components/ui/card' -import { Gauge, GaugeSkeleton } from '@/components/ui/gauge' -import { useDashboardDataSuspense } from '@/lib/hooks/useDashboardData' - -import DashboardCardD655 from './card/DashboardCardD655' - -interface DashboardD09Data { - organization?: string - queryKey?: string -} - -function DashboardGaugeContent({ cds }: { cds: string }) { - const { data } = useDashboardDataSuspense(cds) - - const performanceLevel = (data.statuslevel ?? 0) as 0 | 1 | 2 | 3 | 4 | 5 - - return ( -
-

- {data.schoolname || data.districtname || 'Academic Performance'} -

-
- - {data.currstatus != null && ( -

- Current Status: {data.currstatus.toFixed(1)} - {data.change != null && ( - = 0 ? 'ml-2 text-green-600' : 'ml-2 text-red-600'}> - ({data.change >= 0 ? '+' : ''} - {data.change.toFixed(1)}) - - )} -

- )} -
-
- ) -} - -function DashboardGauge({ cds }: { cds: string | undefined }) { - if (!cds) { - return ( -
-

- Enter a CDS code in the URL to view academic indicator data. -

-

- Example: /dashboard?q=01234567890123 -

-
- ) - } - - return ( - }> - - - ) -} - -export default function DashboardD09({ data }: { data: DashboardD09Data }) { - return ( -
-
- {/* Page Header */} -
-

{data.organization}

-

- Welcome back! Here's an overview of your application. -

-
- - {/* Stats Cards */} -
- - - -
-
-

- 2023-2024 Average Distance from Standard -

-

$45,231

-
- - +8.2% -
-
-
- -
-
-
-
- - - -
-
-

2023-2024 Growth

-

1,234

-
- - -3.1% -
-
-
- -
-
-
-
-
-
- -
- {/* Main Content Cards */} -
- {/* Activity Card */} - - -
-

Recent Activity

- Live -
-
- -
-
-
- -
-
-

New user registered

-

- john.doe@example.com joined 2 minutes ago -

-
- 2m ago -
- -
-
- -
-
-

Payment received

-

- $299.00 from Premium subscription -

-
- 5m ago -
- -
-
- -
-
-

New order placed

-

Order #1234 for $89.99

-
- 15m ago -
-
-
- - - -
- - {/* Quick Actions Card */} - - -

Quick Actions

-
- -
- - - -
-
-
-
- - {/* Additional Example Cards */} -
- - -

System Status

-
- -
-
- API Status - - Operational - -
-
- Database - - Healthy - -
-
- Cache - - Warning - -
-
-
-
- - - -

Performance

-
- -
-
-

Response Time

-

234ms

-
- - -12ms from last hour -
-
-
-
-
- - - -

Storage Usage

-
- -
-
- Used - 45.2 GB -
-
- Available - 54.8 GB -
-
-
-
-
- - -
-
-
- ) -} diff --git a/frontend/src/components/Dashboard/IndicatorGrid.tsx b/frontend/src/components/Dashboard/IndicatorGrid.tsx deleted file mode 100644 index 314ac27..0000000 --- a/frontend/src/components/Dashboard/IndicatorGrid.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import type { IndicatorSummary } from '@/lib/client' -import { INDICATOR_ORDER, type IndicatorCode } from '@/lib/constants/indicators' - -import { IndicatorCard, IndicatorCardSkeleton, type ColorKey } from './card/IndicatorCard' - -interface IndicatorGridProps { - indicators: IndicatorSummary[] - onIndicatorClick?: (code: IndicatorCode) => void - onColorClick?: (code: IndicatorCode, color: ColorKey) => void - compact?: boolean - columns?: 1 | 2 | 4 | 5 - cds?: string - reportingyear?: string -} - -export function IndicatorGrid({ - indicators, - onIndicatorClick, - onColorClick, - compact = false, - columns = 5, - cds, - reportingyear, -}: IndicatorGridProps) { - // Create a map for quick lookup - const indicatorMap = new Map(indicators.map((ind) => [ind.indicator, ind])) - - // Sort indicators by the defined order - const sortedIndicators = INDICATOR_ORDER.map((code) => { - const ind = indicatorMap.get(code) - if (ind) return ind - // Return placeholder for missing indicators - return { - indicator: code, - currstatus: null, - priorstatus: null, - change: null, - statuslevel: null, - changelevel: null, - color: null, - currdenom: null, - } - }) - - const gridClasses = { - 1: 'grid-cols-1', - 2: 'grid-cols-1 sm:grid-cols-2', - 4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4', - 5: 'grid-cols-1 grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5', - } - - return ( -
- {sortedIndicators.map((ind) => ( - onIndicatorClick?.(ind.indicator as IndicatorCode)} - onColorClick={(color) => onColorClick?.(ind.indicator as IndicatorCode, color)} - compact={compact} - cds={cds} - reportingyear={reportingyear} - /> - ))} -
- ) -} - -export function IndicatorGridSkeleton({ - compact = false, - columns = 4, - count = 8, -}: { - compact?: boolean - columns?: 1 | 2 | 4 | 5 - count?: number -}) { - const gridClasses = { - 1: 'grid-cols-1', - 2: 'grid-cols-1 sm:grid-cols-2', - 4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4', - 5: 'grid-cols-1 grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5', - } - - return ( -
- {Array.from({ length: count }).map((_, i) => ( - - ))} -
- ) -} diff --git a/frontend/src/components/Dashboard/card/IndicatorCard.tsx b/frontend/src/components/Dashboard/card/IndicatorCard.tsx deleted file mode 100644 index 983c302..0000000 --- a/frontend/src/components/Dashboard/card/IndicatorCard.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { Gauge } from '@/components/ui/gauge' -import type { IndicatorSummary } from '@/lib/client' -import { COLOR_LEVELS, type IndicatorCode, INDICATORS } from '@/lib/constants/indicators' -import { useEquityReport } from '@/lib/hooks/useDashboardData' -import { cn } from '@/lib/utils' - -export type ColorKey = 'red' | 'orange' | 'yellow' | 'green' | 'blue' - -interface IndicatorCardProps { - indicator: IndicatorSummary - onClick?: () => void - onColorClick?: (color: ColorKey) => void - compact?: boolean - cds?: string - reportingyear?: string -} - -export function IndicatorCard({ - indicator, - onClick, - onColorClick, - compact = false, - cds, - reportingyear, -}: IndicatorCardProps) { - const config = INDICATORS[indicator.indicator as IndicatorCode] - const performanceLevel = (indicator.statuslevel ?? 0) as 0 | 1 | 2 | 3 | 4 | 5 - const { data: equityData } = useEquityReport( - cds ?? null, - indicator.indicator, - reportingyear ?? '2025', - ) - - if (!config) return null - - const hasData = indicator.currstatus !== null || indicator.statuslevel !== null - const colorCounts = equityData?.color_counts - const total = colorCounts - ? colorCounts.red + - colorCounts.orange + - colorCounts.yellow + - colorCounts.green + - colorCounts.blue - : 0 - - const segments = colorCounts - ? [ - { - key: 'red' as ColorKey, - count: colorCounts.red, - color: COLOR_LEVELS[1].color, - textColor: 'white', - }, - { - key: 'orange' as ColorKey, - count: colorCounts.orange, - color: COLOR_LEVELS[2].color, - textColor: 'white', - }, - { - key: 'yellow' as ColorKey, - count: colorCounts.yellow, - color: COLOR_LEVELS[3].color, - textColor: 'black', - }, - { - key: 'green' as ColorKey, - count: colorCounts.green, - color: COLOR_LEVELS[4].color, - textColor: 'white', - }, - { - key: 'blue' as ColorKey, - count: colorCounts.blue, - color: COLOR_LEVELS[5].color, - textColor: 'white', - }, - ].filter((s) => s.count > 0) - : [] - - const handleColorClick = (e: React.MouseEvent, colorKey: ColorKey) => { - e.stopPropagation() - onColorClick?.(colorKey) - } - - return ( - - ))} -
- )} - - ) -} - -export function IndicatorCardSkeleton({ compact = false }: { compact?: boolean }) { - return ( -
-
-
-
-
-
-
-
- ) -} diff --git a/frontend/src/components/Dashboard/detail/EquityReport.tsx b/frontend/src/components/Dashboard/detail/EquityReport.tsx deleted file mode 100644 index b772947..0000000 --- a/frontend/src/components/Dashboard/detail/EquityReport.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import type { EquityGroupSummary } from '@/lib/client' -import { COLOR_LEVELS, getStudentGroupName } from '@/lib/constants/indicators' - -export type ColorKey = 'red' | 'orange' | 'yellow' | 'green' | 'blue' - -const COLOR_KEY_TO_LEVEL: Record = { - red: 1, - orange: 2, - yellow: 3, - green: 4, - blue: 5, -} - -interface ColorCounts { - [key: string]: number | undefined - red?: number - orange?: number - yellow?: number - green?: number - blue?: number - none?: number -} - -interface EquityReportProps { - colorCounts: ColorCounts - groups: EquityGroupSummary[] - showGroupList?: boolean - filterColor?: ColorKey | null -} - -function ColorBar({ colorCounts }: { colorCounts: ColorCounts }) { - const red = colorCounts.red ?? 0 - const orange = colorCounts.orange ?? 0 - const yellow = colorCounts.yellow ?? 0 - const green = colorCounts.green ?? 0 - const blue = colorCounts.blue ?? 0 - const total = red + orange + yellow + green + blue - - if (total === 0) { - return ( -
- No student group data -
- ) - } - - const segments = [ - { key: 'red', count: red, color: COLOR_LEVELS[1].color }, - { key: 'orange', count: orange, color: COLOR_LEVELS[2].color }, - { key: 'yellow', count: yellow, color: COLOR_LEVELS[3].color }, - { key: 'green', count: green, color: COLOR_LEVELS[4].color }, - { key: 'blue', count: blue, color: COLOR_LEVELS[5].color }, - ].filter((s) => s.count > 0) - - return ( -
-
- {segments.map((segment) => ( -
- {segment.count} -
- ))} -
-
- {segments.map((segment) => ( - - - {segment.key.charAt(0).toUpperCase() + segment.key.slice(1)}: {segment.count} - - ))} -
-
- ) -} - -function GroupList({ groups }: { groups: EquityGroupSummary[] }) { - // Sort groups by color level (red first, then orange, etc.) - const sortedGroups = [...groups].sort((a, b) => { - const colorA = a.color ?? 6 - const colorB = b.color ?? 6 - return colorA - colorB - }) - - return ( -
- {sortedGroups.map((group) => { - const colorInfo = COLOR_LEVELS[(group.color ?? 0) as keyof typeof COLOR_LEVELS] - return ( -
-
- - {getStudentGroupName(group.studentgroup)} -
-
- {group.currdenom?.toLocaleString() ?? 'N/A'} students -
-
- ) - })} -
- ) -} - -export function EquityReport({ - colorCounts, - groups, - showGroupList = true, - filterColor, -}: EquityReportProps) { - // Filter groups by color if filterColor is provided - const filteredGroups = filterColor - ? groups.filter((g) => g.color === COLOR_KEY_TO_LEVEL[filterColor]) - : groups - - // Create filtered color counts if filterColor is provided - const filteredColorCounts = filterColor - ? { - red: filterColor === 'red' ? colorCounts.red : 0, - orange: filterColor === 'orange' ? colorCounts.orange : 0, - yellow: filterColor === 'yellow' ? colorCounts.yellow : 0, - green: filterColor === 'green' ? colorCounts.green : 0, - blue: filterColor === 'blue' ? colorCounts.blue : 0, - none: 0, - } - : colorCounts - - const colorLabel = filterColor ? filterColor.charAt(0).toUpperCase() + filterColor.slice(1) : null - - return ( -
-
-

- Student Group Performance Distribution - {colorLabel && ({colorLabel} only)} -

- -
- - {showGroupList && filteredGroups.length > 0 && ( -
-

- Student Groups ({filteredGroups.length}) -

- -
- )} -
- ) -} - -export function EquityReportSkeleton() { - return ( -
-
-
-
-
-
-
-
- {Array.from({ length: 5 }).map((_, i) => ( -
- ))} -
-
-
- ) -} diff --git a/frontend/src/components/Dashboard/detail/IndicatorDetailModal.tsx b/frontend/src/components/Dashboard/detail/IndicatorDetailModal.tsx deleted file mode 100644 index 40a76a9..0000000 --- a/frontend/src/components/Dashboard/detail/IndicatorDetailModal.tsx +++ /dev/null @@ -1,204 +0,0 @@ -import { Suspense, useState } from 'react' -import { FiArrowDown, FiArrowUp, FiChevronDown, FiChevronRight, FiMinus } from 'react-icons/fi' - -import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible' -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog' -import { Gauge } from '@/components/ui/gauge' -import type { IndicatorSummary } from '@/lib/client' -import { type IndicatorCode, INDICATORS, getIndicatorLabel } from '@/lib/constants/indicators' -import { useEquityReport } from '@/lib/hooks/useDashboardData' - -import { EquityReport, EquityReportSkeleton } from './EquityReport' - -export type ColorKey = 'red' | 'orange' | 'yellow' | 'green' | 'blue' - -interface CollapsibleSectionProps { - title: string - defaultOpen?: boolean - children: React.ReactNode -} - -function CollapsibleSection({ title, defaultOpen = true, children }: CollapsibleSectionProps) { - const [isOpen, setIsOpen] = useState(defaultOpen) - - return ( - - - {isOpen ? : } - {title} - - {children} - - ) -} - -interface IndicatorDetailModalProps { - isOpen: boolean - onClose: () => void - cds: string - indicator: IndicatorSummary | null - reportingyear: string - selectedColor?: ColorKey | null -} - -function formatStatus(value: number | null, indicator: string): string { - if (value === null) return 'N/A' - - if (['CHRONIC', 'SUSP', 'GRAD', 'ELPI', 'CCI'].includes(indicator)) { - return `${value.toFixed(1)}%` - } - - return value.toFixed(1) -} - -function ChangeDisplay({ change, indicator }: { change: number | null; indicator: string }) { - if (change === null) { - return ( -
- - No change data available -
- ) - } - - const config = INDICATORS[indicator as IndicatorCode] - const isInverted = config?.invertedScale ?? false - const isPositive = isInverted ? change < 0 : change > 0 - - return ( -
- {change > 0 ? ( - - ) : change < 0 ? ( - - ) : ( - - )} - - {change > 0 ? '+' : ''} - {change.toFixed(1)} from prior year - -
- ) -} - -function EquityReportContent({ - cds, - indicator, - reportingyear, - filterColor, -}: { - cds: string - indicator: string - reportingyear: string - filterColor?: ColorKey | null -}) { - const { data, isLoading, error } = useEquityReport(cds, indicator, reportingyear) - - if (isLoading) { - return - } - - if (error || !data) { - return
Unable to load equity report data.
- } - - return ( - - ) -} - -export function IndicatorDetailModal({ - isOpen, - onClose, - cds, - indicator, - reportingyear, - selectedColor, -}: IndicatorDetailModalProps) { - if (!indicator) { - return null - } - - const config = INDICATORS[indicator.indicator as IndicatorCode] - const performanceLevel = (indicator.statuslevel ?? 0) as 0 | 1 | 2 | 3 | 4 | 5 - - return ( - !open && onClose()}> - - - {getIndicatorLabel(indicator.indicator)} - {config?.description} - - -
- -
-
- -
- -
-
-

Current Status

-

- {formatStatus(indicator.currstatus ?? null, indicator.indicator)} -

-
- -
-

- Change from Prior Year -

- -
- - {indicator.currdenom && ( -
-

Students

-

{indicator.currdenom.toLocaleString()}

-
- )} - - {indicator.priorstatus !== null && ( -
-

Prior Year Status

-

- {formatStatus(indicator.priorstatus ?? null, indicator.indicator)} -

-
- )} -
-
-
- - -
- }> - - -
-
-
-
-
- ) -} diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx index a8c4bb5..a582aa8 100644 --- a/frontend/src/components/Header.tsx +++ b/frontend/src/components/Header.tsx @@ -1,23 +1,24 @@ -import { Link } from '@tanstack/react-router' import { - ChefHat, - ClipboardType, - Home, - ImageIcon, - Languages, - Menu, - MessagesSquare, - Network, - SquareFunction, - StickyNote, - Store, - Table, - Webhook, - X, -} from 'lucide-react' + AiNetworkIcon, + ChefHatIcon, + ClipboardIcon, + Comment01Icon, + FunctionIcon, + Home01Icon, + Image01Icon, + Menu01Icon, + Note01Icon, + Store01Icon, + TableIcon, + TranslateIcon, + WebhookIcon, + Cancel01Icon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' +import { Link } from '@tanstack/react-router' import { useState } from 'react' -import ParaglideLocaleSwitcher from './LocaleSwitcher.tsx' +import ParaglideLocaleSwitcher from './LocaleSwitcher' export default function Header() { const [isOpen, setIsOpen] = useState(false) @@ -32,7 +33,7 @@ export default function Header() { aria-label='Open menu' type='button' > - +

@@ -54,7 +55,7 @@ export default function Header() { aria-label='Close menu' type='button' > - +

@@ -68,7 +69,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + Home @@ -83,7 +84,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + TanStack Query @@ -96,7 +97,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + Store @@ -109,7 +110,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + TanStack Table @@ -122,7 +123,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + I18n example @@ -135,7 +136,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + MCP @@ -148,7 +149,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + Simple Form @@ -161,7 +162,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + Address Form @@ -174,7 +175,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + Chat @@ -187,7 +188,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + Generate Image @@ -200,7 +201,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + Structured Output @@ -213,7 +214,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + Start - Server Functions @@ -226,7 +227,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + Start - API Request @@ -241,7 +242,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + SPA Mode @@ -254,7 +255,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + Full SSR @@ -267,7 +268,7 @@ export default function Header() { 'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-2', }} > - + Data Only diff --git a/frontend/src/components/StatusTemplate.tsx b/frontend/src/components/StatusTemplate.tsx deleted file mode 100644 index ca45692..0000000 --- a/frontend/src/components/StatusTemplate.tsx +++ /dev/null @@ -1 +0,0 @@ -export { StatusCard, StatusTemplate } from '@/components/layout/status/StatusTemplate' diff --git a/frontend/src/components/Admin/DeleteUser.tsx b/frontend/src/components/admin/DeleteUser.tsx similarity index 91% rename from frontend/src/components/Admin/DeleteUser.tsx rename to frontend/src/components/admin/DeleteUser.tsx index 1b844a7..682525f 100644 --- a/frontend/src/components/Admin/DeleteUser.tsx +++ b/frontend/src/components/admin/DeleteUser.tsx @@ -1,5 +1,6 @@ +import { Delete02Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { useMutation, useQueryClient } from '@tanstack/react-query' -import { Trash2 } from 'lucide-react' import { useState } from 'react' import { Button } from '@/components/ui/button' @@ -16,7 +17,7 @@ import { DropdownMenuItem } from '@/components/ui/dropdown-menu' import { Spinner } from '@/components/ui/spinner' import { UsersService } from '@/lib/client' import { handleError } from '@/lib/client-utils' -import useCustomToast from '@/lib/hooks/useCustomToast' +import useCustomToast from '@/routes/-hooks/hooks/useCustomToast' interface DeleteUserProps { id: string @@ -53,7 +54,7 @@ const DeleteUser = ({ id, onSuccess }: DeleteUserProps) => { onSelect={(e) => e.preventDefault()} onClick={() => setIsOpen(true)} > - + Delete User diff --git a/frontend/src/components/Admin/EditUser.tsx b/frontend/src/components/admin/EditUser.tsx similarity index 88% rename from frontend/src/components/Admin/EditUser.tsx rename to frontend/src/components/admin/EditUser.tsx index a8e6537..93892c9 100644 --- a/frontend/src/components/Admin/EditUser.tsx +++ b/frontend/src/components/admin/EditUser.tsx @@ -1,9 +1,11 @@ +import { PencilEdit02Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { useForm } from '@tanstack/react-form' import { useMutation, useQueryClient } from '@tanstack/react-query' -import { Pencil } from 'lucide-react' import { useState } from 'react' import { z } from 'zod' +import { PasswordInput } from '@/components/password-input' import { Button } from '@/components/ui/button' import { Checkbox } from '@/components/ui/checkbox' import { @@ -18,28 +20,27 @@ import { import { DropdownMenuItem } from '@/components/ui/dropdown-menu' import { Field, FieldError, FieldLabel } from '@/components/ui/field' import { Input } from '@/components/ui/input' -import { PasswordInput } from '@/components/ui/password-input' import { Spinner } from '@/components/ui/spinner' import { type UserPublic, UsersService } from '@/lib/client' import { handleError } from '@/lib/client-utils' -import useCustomToast from '@/lib/hooks/useCustomToast' +import useCustomToast from '@/routes/-hooks/hooks/useCustomToast' const formSchema = z .object({ - email: z.string().email({ message: 'Invalid email address' }), - full_name: z.string().optional(), + email: z.string().email({ error: 'Invalid email address' }), + fullName: z.string().optional(), password: z .string() - .min(8, { message: 'Password must be at least 8 characters' }) + .min(8, { error: 'Password must be at least 8 characters' }) .optional() .or(z.literal('')), confirm_password: z.string().optional(), - is_superuser: z.boolean().optional(), - is_active: z.boolean().optional(), - force_password_reset: z.boolean().optional(), + isSuperuser: z.boolean().optional(), + isActive: z.boolean().optional(), + forcePasswordReset: z.boolean().optional(), }) .refine((data) => !data.password || data.password === data.confirm_password, { - message: "The passwords don't match", + error: "The passwords don't match", path: ['confirm_password'], }) @@ -58,12 +59,12 @@ const EditUser = ({ user, onSuccess }: EditUserProps) => { const form = useForm({ defaultValues: { email: user.email, - full_name: user.full_name ?? '', + fullName: user.fullName ?? '', password: '', confirm_password: '', - is_superuser: user.is_superuser, - is_active: user.is_active, - force_password_reset: user.force_password_reset, + isSuperuser: user.isSuperuser, + isActive: user.isActive, + forcePasswordReset: user.forcePasswordReset, } as FormData, validators: { onChange: formSchema, @@ -92,7 +93,7 @@ const EditUser = ({ user, onSuccess }: EditUserProps) => { return ( e.preventDefault()} onClick={() => setIsOpen(true)}> - + Edit User @@ -132,7 +133,7 @@ const EditUser = ({ user, onSuccess }: EditUserProps) => { )} - + {(field) => ( Full Name @@ -196,7 +197,7 @@ const EditUser = ({ user, onSuccess }: EditUserProps) => { )} - + {(field) => ( { )} - + {(field) => ( { )} - + {(field) => ( { return ( }> - + setOpen(false)} /> diff --git a/frontend/src/components/Admin/columns.tsx b/frontend/src/components/admin/columns.tsx similarity index 74% rename from frontend/src/components/Admin/columns.tsx rename to frontend/src/components/admin/columns.tsx index 9fe64c3..531004f 100644 --- a/frontend/src/components/Admin/columns.tsx +++ b/frontend/src/components/admin/columns.tsx @@ -12,10 +12,10 @@ export type UserTableData = UserPublic & { export const columns: ColumnDef[] = [ { - accessorKey: 'full_name', + accessorKey: 'fullName', header: 'Full Name', cell: ({ row }) => { - const fullName = row.original.full_name + const fullName = row.original.fullName return (
@@ -36,36 +36,36 @@ export const columns: ColumnDef[] = [ cell: ({ row }) => {row.original.email}, }, { - accessorKey: 'is_superuser', + accessorKey: 'isSuperuser', header: 'Role', cell: ({ row }) => ( - - {row.original.is_superuser ? 'Superuser' : 'User'} + + {row.original.isSuperuser ? 'Superuser' : 'User'} ), }, { - accessorKey: 'is_active', + accessorKey: 'isActive', header: 'Status', cell: ({ row }) => (
- - {row.original.is_active ? 'Active' : 'Inactive'} + + {row.original.isActive ? 'Active' : 'Inactive'}
), }, { - accessorKey: 'force_password_reset', + accessorKey: 'forcePasswordReset', header: 'Security', cell: ({ row }) => - row.original.force_password_reset ? ( + row.original.forcePasswordReset ? ( Reset Required ) : ( Normal diff --git a/frontend/src/components/layout/navbar/MobileButton.tsx b/frontend/src/components/button/MobileButton.tsx similarity index 82% rename from frontend/src/components/layout/navbar/MobileButton.tsx rename to frontend/src/components/button/MobileButton.tsx index 5a12a04..f36c381 100644 --- a/frontend/src/components/layout/navbar/MobileButton.tsx +++ b/frontend/src/components/button/MobileButton.tsx @@ -1,15 +1,16 @@ +import { Menu01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { Link } from '@tanstack/react-router' -import { FaBars } from 'react-icons/fa' -import { buttonVariants } from '@/components/ui/button.tsx' +import { buttonVariants } from '@/components/ui/button' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu.tsx' -import useAuth from '@/lib/hooks/useAuth.ts' +} from '@/components/ui/dropdown-menu' import { cn } from '@/lib/utils.ts' +import useAuth from '@/routes/-hooks/hooks/useAuth.ts' export default function MobileButton() { const { user: currentUser, logout } = useAuth() @@ -19,7 +20,7 @@ export default function MobileButton() { - + }> diff --git a/frontend/src/components/layout/navbar/SettingsButton.tsx b/frontend/src/components/button/SettingsButton.tsx similarity index 79% rename from frontend/src/components/layout/navbar/SettingsButton.tsx rename to frontend/src/components/button/SettingsButton.tsx index caaa54c..8e632cf 100644 --- a/frontend/src/components/layout/navbar/SettingsButton.tsx +++ b/frontend/src/components/button/SettingsButton.tsx @@ -1,15 +1,16 @@ +import { Settings02Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { Link } from '@tanstack/react-router' -import { FaGear } from 'react-icons/fa6' -import { buttonVariants } from '@/components/ui/button.tsx' +import { buttonVariants } from '@/components/ui/button' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu.tsx' -import useAuth from '@/lib/hooks/useAuth.ts' +} from '@/components/ui/dropdown-menu' import { cn } from '@/lib/utils.ts' +import useAuth from '@/routes/-hooks/hooks/useAuth.ts' export default function SettingsButton() { const { user: currentUser, logout } = useAuth() @@ -18,7 +19,7 @@ export default function SettingsButton() {
- + {currentUser ? ( diff --git a/frontend/src/components/layout/navbar/UserAvatar.tsx b/frontend/src/components/button/UserAvatar.tsx similarity index 88% rename from frontend/src/components/layout/navbar/UserAvatar.tsx rename to frontend/src/components/button/UserAvatar.tsx index ae040e2..fc1a016 100644 --- a/frontend/src/components/layout/navbar/UserAvatar.tsx +++ b/frontend/src/components/button/UserAvatar.tsx @@ -1,4 +1,4 @@ -import { Avatar, AvatarFallback, AvatarGroup, AvatarImage } from '@/components/ui/avatar.tsx' +import { Avatar, AvatarFallback, AvatarGroup, AvatarImage } from '@/components/ui/avatar' export default function UserAvatar() { return ( diff --git a/frontend/src/components/layout/app-sidebar.tsx b/frontend/src/components/common/AppSidebar.tsx similarity index 78% rename from frontend/src/components/layout/app-sidebar.tsx rename to frontend/src/components/common/AppSidebar.tsx index 177c900..7f64c93 100644 --- a/frontend/src/components/layout/app-sidebar.tsx +++ b/frontend/src/components/common/AppSidebar.tsx @@ -1,10 +1,17 @@ +import { + Briefcase01Icon, + Home01Icon, + Logout01Icon, + ScrollVerticalIcon, + Settings03Icon, + UserGroupIcon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { Link as RouterLink, useRouterState } from '@tanstack/react-router' -import type { LucideIcon } from 'lucide-react' -import { Briefcase, ChevronsUpDown, Home, LogOut, Settings, Users } from 'lucide-react' -import { SidebarAppearance } from '@/components/common/Appearance.tsx' -import { Logo } from '@/components/common/Logo.tsx' -import { Avatar, AvatarFallback } from '@/components/ui/avatar.tsx' +import { SidebarAppearance } from '@/components/common/Appearance' +import { Logo } from '@/components/common/Logo' +import { Avatar, AvatarFallback } from '@/components/ui/avatar' import { DropdownMenu, DropdownMenuContent, @@ -12,7 +19,7 @@ import { DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu.tsx' +} from '@/components/ui/dropdown-menu' import { Sidebar, SidebarContent, @@ -24,9 +31,9 @@ import { SidebarMenuButton, SidebarMenuItem, useSidebar, -} from '@/components/ui/sidebar.tsx' +} from '@/components/ui/sidebar' import { getInitials } from '@/lib/client-utils.ts' -import useAuth from '@/lib/hooks/useAuth.ts' +import useAuth from '@/routes/-hooks/hooks/useAuth.ts' interface UserInfoProps { fullName?: string @@ -34,7 +41,7 @@ interface UserInfoProps { } export type Item = { - icon: LucideIcon + icon: any title: string path: string } @@ -43,16 +50,16 @@ interface MainProps { items: Item[] } const baseItems: Item[] = [ - { icon: Home, title: 'Dashboard', path: '/user/' }, - { icon: Briefcase, title: 'Items', path: '/user/items' }, - { icon: Settings, title: 'Settings', path: '/user/settings' }, + { icon: Home01Icon, title: 'Dashboard', path: '/user/' }, + { icon: Briefcase01Icon, title: 'Items', path: '/user/items' }, + { icon: Settings03Icon, title: 'Settings', path: '/user/settings' }, ] export default function AppSidebar() { const { user: currentUser } = useAuth() - const items = currentUser?.is_superuser - ? [...baseItems, { icon: Users, title: 'Admin', path: '/user/admin' }] + const items = currentUser?.isSuperuser + ? [...baseItems, { icon: UserGroupIcon, title: 'Admin', path: '/user/admin' }] : baseItems return ( @@ -115,8 +122,11 @@ function User({ user }: { user: any }) { /> } > - - + + - + {/* Use 'render' prop for routing components in Base UI to avoid nesting issues */} } onClick={handleMenuClick}> - + User Settings - + Log Out @@ -179,7 +189,7 @@ function Main({ items }: MainProps) { // Base UI uses 'render' to merge functionality onto custom components render={} > - + {item.title} diff --git a/frontend/src/components/Common/Appearance.tsx b/frontend/src/components/common/Appearance.tsx similarity index 71% rename from frontend/src/components/Common/Appearance.tsx rename to frontend/src/components/common/Appearance.tsx index d1bd95c..fbc736d 100644 --- a/frontend/src/components/Common/Appearance.tsx +++ b/frontend/src/components/common/Appearance.tsx @@ -1,4 +1,5 @@ -import { Monitor, Moon, Sun } from 'lucide-react' +import { Monitor, MoonIcon, SunIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { type Theme, useTheme } from '@/components/theme-provider' import { Button } from '@/components/ui/button' @@ -10,12 +11,10 @@ import { } from '@/components/ui/dropdown-menu' import { SidebarMenuButton, SidebarMenuItem, useSidebar } from '@/components/ui/sidebar' -type LucideIcon = typeof Monitor - -const ICON_MAP: Record = { +const ICON_MAP: Record = { system: Monitor, - light: Sun, - dark: Moon, + light: SunIcon, + dark: MoonIcon, } export const SidebarAppearance = () => { @@ -39,15 +38,15 @@ export const SidebarAppearance = () => { className='w-(--radix-dropdown-menu-trigger-width) min-w-56' > setTheme('light')}> - + Light setTheme('dark')}> - + Dark setTheme('system')}> - + System @@ -65,21 +64,27 @@ export const Appearance = () => { } > - - + + Toggle theme setTheme('light')}> - + Light setTheme('dark')}> - + Dark setTheme('system')}> - + System diff --git a/frontend/src/components/Common/AuthLayout.tsx b/frontend/src/components/common/AuthLayout.tsx similarity index 100% rename from frontend/src/components/Common/AuthLayout.tsx rename to frontend/src/components/common/AuthLayout.tsx diff --git a/frontend/src/components/Common/DataTable.tsx b/frontend/src/components/common/DataTable.tsx similarity index 93% rename from frontend/src/components/Common/DataTable.tsx rename to frontend/src/components/common/DataTable.tsx index 886c233..886883f 100644 --- a/frontend/src/components/Common/DataTable.tsx +++ b/frontend/src/components/common/DataTable.tsx @@ -1,3 +1,5 @@ +import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { type ColumnDef, type FilterFn, @@ -6,7 +8,6 @@ import { getPaginationRowModel, useReactTable, } from '@tanstack/react-table' -import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react' import { Button } from '@/components/ui/button' import { @@ -136,7 +137,7 @@ export function DataTable({ columns, data }: DataTableProps Go to first page - +
diff --git a/frontend/src/components/Common/ErrorComponent.tsx b/frontend/src/components/common/ErrorComponent.tsx similarity index 100% rename from frontend/src/components/Common/ErrorComponent.tsx rename to frontend/src/components/common/ErrorComponent.tsx diff --git a/frontend/src/components/Common/Footer.tsx b/frontend/src/components/common/Footer.tsx similarity index 73% rename from frontend/src/components/Common/Footer.tsx rename to frontend/src/components/common/Footer.tsx index 436641f..5ef5660 100644 --- a/frontend/src/components/Common/Footer.tsx +++ b/frontend/src/components/common/Footer.tsx @@ -1,15 +1,15 @@ -import { FaGithub, FaLinkedinIn } from 'react-icons/fa' -import { FaXTwitter } from 'react-icons/fa6' +import { GithubIcon, Linkedin01Icon, NewTwitterIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' const socialLinks = [ { - icon: FaGithub, + icon: GithubIcon, href: 'https://github.com/fastapi/fastapi', label: 'GitHub', }, - { icon: FaXTwitter, href: 'https://x.com/fastapi', label: 'X' }, + { icon: NewTwitterIcon, href: 'https://x.com/fastapi', label: 'X' }, { - icon: FaLinkedinIn, + icon: Linkedin01Icon, href: 'https://linkedin.com/company/fastapi', label: 'LinkedIn', }, @@ -32,7 +32,7 @@ export function Footer() { aria-label={label} className='text-muted-foreground hover:text-foreground transition-colors' > - + ))} diff --git a/frontend/src/components/Common/Logo.tsx b/frontend/src/components/common/Logo.tsx similarity index 100% rename from frontend/src/components/Common/Logo.tsx rename to frontend/src/components/common/Logo.tsx diff --git a/frontend/src/components/layout/navbar/SearchBar.module.css b/frontend/src/components/common/navbar/SearchBar.module.css similarity index 100% rename from frontend/src/components/layout/navbar/SearchBar.module.css rename to frontend/src/components/common/navbar/SearchBar.module.css diff --git a/frontend/src/components/layout/navbar/SearchBar.tsx b/frontend/src/components/common/navbar/SearchBar.tsx similarity index 87% rename from frontend/src/components/layout/navbar/SearchBar.tsx rename to frontend/src/components/common/navbar/SearchBar.tsx index f5ce45d..21fcc16 100644 --- a/frontend/src/components/layout/navbar/SearchBar.tsx +++ b/frontend/src/components/common/navbar/SearchBar.tsx @@ -1,5 +1,14 @@ +import { + Building01Icon, + Clock01Icon, + MapsLocation01Icon, + School01Icon, + Search01Icon, + SparklesIcon, + Sorting05Icon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { useNavigate } from '@tanstack/react-router' -import { Building2, Clock, GraduationCap, MapPin, Search, Sparkles, TrendingUp } from 'lucide-react' import * as React from 'react' import { @@ -11,8 +20,8 @@ import { CommandItem, CommandList, CommandSeparator, -} from '@/components/ui/command.tsx' -import { Kbd, KbdGroup } from '@/components/ui/kbd.tsx' +} from '@/components/ui/command' +import { Kbd, KbdGroup } from '@/components/ui/kbd' import { cn } from '@/lib/utils.ts' import styles from './SearchBar.module.css' @@ -60,9 +69,9 @@ const SUGGESTED_SCHOOLS: SearchResult[] = [ ] const QUICK_FILTERS = [ - { id: 'top-performing', label: 'Top Performing Schools', icon: TrendingUp }, - { id: 'nearby', label: 'Schools Near Me', icon: MapPin }, - { id: 'charter', label: 'Charter Schools', icon: Sparkles }, + { id: 'top-performing', label: 'Top Performing Schools', icon: Sorting05Icon }, + { id: 'nearby', label: 'Schools Near Me', icon: MapsLocation01Icon }, + { id: 'charter', label: 'SparklesIcon', icon: SparklesIcon }, ] function getRecentSearches(): SearchResult[] { @@ -88,16 +97,19 @@ function clearRecentSearches() { function getTypeIcon(type: SearchResult['type']) { switch (type) { case 'school': - return GraduationCap + return School01Icon case 'district': - return Building2 + return Building01Icon case 'county': - return MapPin + return MapsLocation01Icon default: - return GraduationCap + return School01Icon } } +/** + * The search bar launches a modal. + */ export default function SearchBar({ className, placeholder = 'Search schools, districts...', @@ -151,7 +163,7 @@ export default function SearchBar({
{/* Trigger Button */}
diff --git a/frontend/src/components/layout/pending/PendingUsers.tsx b/frontend/src/components/common/pending/PendingUsers.tsx similarity index 91% rename from frontend/src/components/layout/pending/PendingUsers.tsx rename to frontend/src/components/common/pending/PendingUsers.tsx index faaa6c0..4183d9c 100644 --- a/frontend/src/components/layout/pending/PendingUsers.tsx +++ b/frontend/src/components/common/pending/PendingUsers.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from '@/components/ui/skeleton.tsx' +import { Skeleton } from '@/components/ui/skeleton' import { Table, TableBody, @@ -6,7 +6,7 @@ import { TableHead, TableHeader, TableRow, -} from '@/components/ui/table.tsx' +} from '@/components/ui/table' const PendingUsers = () => (
diff --git a/frontend/src/components/layout/status/DefaultCatchBoundary.tsx b/frontend/src/components/common/status/DefaultCatchBoundary.tsx similarity index 82% rename from frontend/src/components/layout/status/DefaultCatchBoundary.tsx rename to frontend/src/components/common/status/DefaultCatchBoundary.tsx index 0dceb81..184ca19 100644 --- a/frontend/src/components/layout/status/DefaultCatchBoundary.tsx +++ b/frontend/src/components/common/status/DefaultCatchBoundary.tsx @@ -1,10 +1,16 @@ +import { + Alert01Icon, + Home01Icon, + RefreshIcon, + ArrowTurnBackwardIcon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { Link, type ErrorComponentProps, useRouter } from '@tanstack/react-router' -import { AlertTriangle, Home, RefreshCcw, RotateCcw } from 'lucide-react' -import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert.tsx' -import { Button } from '@/components/ui/button.tsx' +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' +import { Button } from '@/components/ui/button' -import { StatusCard, StatusTemplate } from './StatusTemplate.tsx' +import { StatusCard, StatusTemplate } from './StatusTemplate' export interface DefaultCatchBoundaryProps extends Partial { /** Whether to show the full template with header/footer */ @@ -66,7 +72,8 @@ export function DefaultCatchBoundary({ error, reset, fullPage = true }: DefaultC
-
@@ -76,22 +83,22 @@ export function DefaultCatchBoundary({ error, reset, fullPage = true }: DefaultC footer={ <> } > - + Error Details {errorMessage} diff --git a/frontend/src/components/layout/status/DefaultError.tsx b/frontend/src/components/common/status/DefaultError.tsx similarity index 80% rename from frontend/src/components/layout/status/DefaultError.tsx rename to frontend/src/components/common/status/DefaultError.tsx index 98c95f1..fe2ec0b 100644 --- a/frontend/src/components/layout/status/DefaultError.tsx +++ b/frontend/src/components/common/status/DefaultError.tsx @@ -1,16 +1,17 @@ +import { AlertCircleIcon, Bug01Icon, Home01Icon, RefreshIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { Link, type ErrorComponentProps } from '@tanstack/react-router' -import { AlertOctagon, Bug, Home, RefreshCcw } from 'lucide-react' import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, -} from '@/components/ui/accordion.tsx' -import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert.tsx' -import { Button } from '@/components/ui/button.tsx' +} from '@/components/ui/accordion' +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' +import { Button } from '@/components/ui/button' -import { StatusCard, StatusTemplate } from './StatusTemplate.tsx' +import { StatusCard, StatusTemplate } from './StatusTemplate' export interface DefaultErrorProps extends Partial { /** Whether to show the full template with header/footer */ @@ -26,7 +27,7 @@ export function DefaultError({ error, reset, info, fullPage = true }: DefaultErr variant='error' icon={
- +
} title='Something Went Wrong' @@ -35,17 +36,17 @@ export function DefaultError({ error, reset, info, fullPage = true }: DefaultErr <> {reset ? ( ) : ( )} @@ -53,7 +54,7 @@ export function DefaultError({ error, reset, info, fullPage = true }: DefaultErr >
- + Error Details {errorMessage} diff --git a/frontend/src/components/layout/status/DefaultNotFound.tsx b/frontend/src/components/common/status/DefaultNotFound.tsx similarity index 76% rename from frontend/src/components/layout/status/DefaultNotFound.tsx rename to frontend/src/components/common/status/DefaultNotFound.tsx index d02faf7..36c6a32 100644 --- a/frontend/src/components/layout/status/DefaultNotFound.tsx +++ b/frontend/src/components/common/status/DefaultNotFound.tsx @@ -1,11 +1,12 @@ +import { FileQuestionMarkIcon, Home01Icon, Search01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { Link, type NotFoundRouteProps } from '@tanstack/react-router' -import { FileQuestion, Home, Search } from 'lucide-react' import type { ReactNode } from 'react' -import { Button } from '@/components/ui/button.tsx' -import { Input } from '@/components/ui/input.tsx' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' -import { StatusCard, StatusTemplate } from './StatusTemplate.tsx' +import { StatusCard, StatusTemplate } from './StatusTemplate' export interface DefaultNotFoundProps { /** Data passed from notFoundComponent */ @@ -20,7 +21,7 @@ export function DefaultNotFound({ data, fullPage = true }: DefaultNotFoundProps) variant='error' icon={
- +
} title='404 - Page Not Found' @@ -28,7 +29,7 @@ export function DefaultNotFound({ data, fullPage = true }: DefaultNotFoundProps) footer={ <>
{data != null ? ( diff --git a/frontend/src/components/layout/status/DefaultPending.tsx b/frontend/src/components/common/status/DefaultPending.tsx similarity index 83% rename from frontend/src/components/layout/status/DefaultPending.tsx rename to frontend/src/components/common/status/DefaultPending.tsx index 386996f..f4871c3 100644 --- a/frontend/src/components/layout/status/DefaultPending.tsx +++ b/frontend/src/components/common/status/DefaultPending.tsx @@ -1,11 +1,12 @@ -import { Loader2 } from 'lucide-react' +import { Loading01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card.tsx' -import { Progress } from '@/components/ui/progress.tsx' -import { Skeleton } from '@/components/ui/skeleton.tsx' -import { Spinner } from '@/components/ui/spinner.tsx' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { Progress } from '@/components/ui/progress' +import { Skeleton } from '@/components/ui/skeleton' +import { Spinner } from '@/components/ui/spinner' -import { StatusTemplate } from './StatusTemplate.tsx' +import { StatusTemplate } from './StatusTemplate' export interface DefaultPendingProps { /** Whether to show the full template with header/footer */ @@ -49,7 +50,10 @@ export function DefaultPending({
- +
{message} diff --git a/frontend/src/components/Common/NotFound.tsx b/frontend/src/components/common/status/NotFound.tsx similarity index 100% rename from frontend/src/components/Common/NotFound.tsx rename to frontend/src/components/common/status/NotFound.tsx diff --git a/frontend/src/components/layout/status/StatusTemplate.tsx b/frontend/src/components/common/status/StatusTemplate.tsx similarity index 95% rename from frontend/src/components/layout/status/StatusTemplate.tsx rename to frontend/src/components/common/status/StatusTemplate.tsx index bcfaa3f..f974560 100644 --- a/frontend/src/components/layout/status/StatusTemplate.tsx +++ b/frontend/src/components/common/status/StatusTemplate.tsx @@ -1,7 +1,7 @@ import { Link } from '@tanstack/react-router' import type { ReactNode } from 'react' -import { Button } from '@/components/ui/button.tsx' +import { Button } from '@/components/ui/button' import { Card, CardContent, @@ -9,8 +9,8 @@ import { CardFooter, CardHeader, CardTitle, -} from '@/components/ui/card.tsx' -import { Separator } from '@/components/ui/separator.tsx' +} from '@/components/ui/card' +import { Separator } from '@/components/ui/separator' import { cn } from '@/lib/utils.ts' export interface StatusTemplateProps { diff --git a/frontend/src/components/layout/status/StatusTemplateLayout.tsx b/frontend/src/components/common/status/StatusTemplateLayout.tsx similarity index 94% rename from frontend/src/components/layout/status/StatusTemplateLayout.tsx rename to frontend/src/components/common/status/StatusTemplateLayout.tsx index a8f57fa..ccaaf92 100644 --- a/frontend/src/components/layout/status/StatusTemplateLayout.tsx +++ b/frontend/src/components/common/status/StatusTemplateLayout.tsx @@ -1,7 +1,7 @@ import { Link, Outlet } from '@tanstack/react-router' -import { Button } from '@/components/ui/button.tsx' -import { Separator } from '@/components/ui/separator.tsx' +import { Button } from '@/components/ui/button' +import { Separator } from '@/components/ui/separator' export function StatusTemplateLayout() { return ( diff --git a/frontend/src/components/Dashboard/DemoDashboard.tsx b/frontend/src/components/dashboard/DemoDashboard.tsx similarity index 85% rename from frontend/src/components/Dashboard/DemoDashboard.tsx rename to frontend/src/components/dashboard/DemoDashboard.tsx index c3fa29c..49f2205 100644 --- a/frontend/src/components/Dashboard/DemoDashboard.tsx +++ b/frontend/src/components/dashboard/DemoDashboard.tsx @@ -1,13 +1,14 @@ import { - FiActivity, - FiArrowDown, - FiArrowUp, - FiDollarSign, - FiSettings, - FiShoppingCart, - FiTrendingUp, - FiUser, -} from 'react-icons/fi' + ActivityIcon, + AnalyticsUpIcon, + ArrowDown01Icon, + ArrowUp01Icon, + Dollar01Icon, + Settings02Icon, + ShoppingBasket01Icon, + UserIcon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' @@ -42,7 +43,7 @@ export default function DemoDashboard() {

Total Users

2,543

- + +12.5% from last month
@@ -53,7 +54,7 @@ export default function DemoDashboard() {

Active Users (30d)

1,987

- + +8.3% from last month
@@ -64,7 +65,7 @@ export default function DemoDashboard() {

New Users (7d)

142

- + -5.2% from last week
@@ -80,12 +81,12 @@ export default function DemoDashboard() {

Revenue

$45,231

- + +8.2%
- +
@@ -98,12 +99,12 @@ export default function DemoDashboard() {

Orders

1,234

- + -3.1%
- +
@@ -116,12 +117,12 @@ export default function DemoDashboard() {

Growth Rate

15.3%

- + +2.4%
- +
@@ -142,7 +143,7 @@ export default function DemoDashboard() {
- +

New user registered

@@ -155,7 +156,7 @@ export default function DemoDashboard() {
- +

Payment received

@@ -168,7 +169,7 @@ export default function DemoDashboard() {
- +

New order placed

@@ -193,15 +194,15 @@ export default function DemoDashboard() {
@@ -249,7 +250,7 @@ export default function DemoDashboard() {

Response Time

234ms

- + -12ms from last hour
diff --git a/frontend/src/components/Dashboard/card/DashboardCardD655.tsx b/frontend/src/components/dashboard/card/DashboardCardD655.tsx similarity index 68% rename from frontend/src/components/Dashboard/card/DashboardCardD655.tsx rename to frontend/src/components/dashboard/card/DashboardCardD655.tsx index 54a042f..0862732 100644 --- a/frontend/src/components/Dashboard/card/DashboardCardD655.tsx +++ b/frontend/src/components/dashboard/card/DashboardCardD655.tsx @@ -1,4 +1,5 @@ -import { FiArrowUp, FiDollarSign } from 'react-icons/fi' +import { ArrowUp01Icon, Dollar01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { Card, CardContent } from '@/components/ui/card' @@ -11,12 +12,12 @@ export default function DashboardCardD655() {

2024-2025 Cohort Total

$45,231

- + +8.2%
- +
diff --git a/frontend/src/components/Dashboard/card/DashboardCardDf61.tsx b/frontend/src/components/dashboard/card/DashboardCardDf61.tsx similarity index 100% rename from frontend/src/components/Dashboard/card/DashboardCardDf61.tsx rename to frontend/src/components/dashboard/card/DashboardCardDf61.tsx diff --git a/frontend/src/components/dashboard/detail/EquityReport.tsx b/frontend/src/components/dashboard/detail/EquityReport.tsx new file mode 100644 index 0000000..45c29b3 --- /dev/null +++ b/frontend/src/components/dashboard/detail/EquityReport.tsx @@ -0,0 +1,76 @@ +import type { EquityGroupSummary } from '@/lib/client' +import { getStudentGroupName } from '@/lib/constants/indicators' + +interface EquityReportProps { + groups: EquityGroupSummary[] +} + +function GroupList({ groups }: { groups: EquityGroupSummary[] }) { + // Sort groups by percent met descending + const sortedGroups = [...groups].sort((a, b) => { + const valA = a.overall_met_and_above_pct ? parseFloat(a.overall_met_and_above_pct) : 0 + const valB = b.overall_met_and_above_pct ? parseFloat(b.overall_met_and_above_pct) : 0 + return valB - valA + }) + + return ( +
+ {sortedGroups.map((group) => { + const percent = group.overall_met_and_above_pct + ? parseFloat(group.overall_met_and_above_pct) + : 0 + return ( +
+
+ {getStudentGroupName(group.studentgroup)} + {percent.toFixed(1)}% +
+
+
+
+
+ {group.students_tested?.toLocaleString() ?? '0'} students tested +
+
+ ) + })} +
+ ) +} + +export function EquityReport({ groups }: EquityReportProps) { + if (groups.length === 0) { + return ( +
+ No student group data available for this selection. +
+ ) + } + + return ( +
+
+

+ Standard Met or Exceeded by Student Group +

+ +
+
+ ) +} + +export function EquityReportSkeleton() { + return ( +
+ {Array.from({ length: 5 }).map((_, i) => ( +
+
+
+
+
+
+
+ ))} +
+ ) +} diff --git a/frontend/src/components/dashboard/detail/IndicatorDetailModal.tsx b/frontend/src/components/dashboard/detail/IndicatorDetailModal.tsx new file mode 100644 index 0000000..df5f0dd --- /dev/null +++ b/frontend/src/components/dashboard/detail/IndicatorDetailModal.tsx @@ -0,0 +1,104 @@ +import { Suspense } from 'react' + +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import type { IndicatorSummary } from '@/lib/client' +import { useEquityReport } from '@/routes/-hooks/hooks/useDashboardData' + +import { EquityReport, EquityReportSkeleton } from './EquityReport' + +interface IndicatorDetailModalProps { + isOpen: boolean + onClose: () => void + cds: string + indicator: IndicatorSummary | null + testYear: string +} + +function EquityReportContent({ + cds, + testId, + testYear, +}: { + cds: string + testId: string + testYear: string +}) { + const { data, isLoading, error } = useEquityReport(cds, testId, testYear) + + if (isLoading) { + return + } + + if (error || !data) { + return
Unable to load student group data.
+ } + + return +} + +export function IndicatorDetailModal({ + isOpen, + onClose, + cds, + indicator, + testYear, +}: IndicatorDetailModalProps) { + if (!indicator) { + return null + } + + return ( + !open && onClose()}> + + + Test Detail: {indicator.test_id} + + {indicator.test_type} | Grade {indicator.grade} + + + +
+
+
+

+ Standard Met or Exceeded +

+

{indicator.overall_met_and_above_pct}%

+
+
+

+ Mean Scale Score +

+

{indicator.overall_mean_scale_score}

+
+
+

+ Students Enrolled +

+

{indicator.students_enrolled}

+
+
+

+ Students Tested +

+

{indicator.students_tested}

+
+
+ +
+

Student Group Breakdown

+ }> + + +
+
+
+
+ ) +} diff --git a/frontend/src/components/ui/gauge.tsx b/frontend/src/components/dashboard/gauge.tsx similarity index 100% rename from frontend/src/components/ui/gauge.tsx rename to frontend/src/components/dashboard/gauge.tsx diff --git a/frontend/src/components/form/AddUser.tsx b/frontend/src/components/form/AddUser.tsx index e035930..2025f4b 100644 --- a/frontend/src/components/form/AddUser.tsx +++ b/frontend/src/components/form/AddUser.tsx @@ -1,11 +1,13 @@ +import { PlusSignIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { useForm } from '@tanstack/react-form' import { useMutation, useQueryClient } from '@tanstack/react-query' -import { Plus } from 'lucide-react' import { useState } from 'react' import { z } from 'zod' -import { Button } from '@/components/ui/button.tsx' -import { Checkbox } from '@/components/ui/checkbox.tsx' +import { PasswordInput } from '@/components/password-input' +import { Button } from '@/components/ui/button' +import { Checkbox } from '@/components/ui/checkbox' import { Dialog, DialogClose, @@ -15,29 +17,28 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from '@/components/ui/dialog.tsx' -import { Field, FieldError, FieldLabel } from '@/components/ui/field.tsx' -import { Input } from '@/components/ui/input.tsx' -import { PasswordInput } from '@/components/ui/password-input.tsx' -import { Spinner } from '@/components/ui/spinner.tsx' +} from '@/components/ui/dialog' +import { Field, FieldError, FieldLabel } from '@/components/ui/field' +import { Input } from '@/components/ui/input' +import { Spinner } from '@/components/ui/spinner' import { type UserCreate, UsersService } from '@/lib/client' import { handleError } from '@/lib/client-utils.ts' -import useCustomToast from '@/lib/hooks/useCustomToast.ts' +import useCustomToast from '@/routes/-hooks/hooks/useCustomToast.ts' const formSchema = z .object({ - email: z.string().email({ message: 'Invalid email address' }), - full_name: z.string().optional(), + email: z.string().email({ error: 'Invalid email address' }), + fullName: z.string().optional(), password: z .string() - .min(1, { message: 'Password is required' }) - .min(8, { message: 'Password must be at least 8 characters' }), - confirm_password: z.string().min(1, { message: 'Please confirm your password' }), - is_superuser: z.boolean(), - is_active: z.boolean(), + .min(1, { error: 'Password is required' }) + .min(8, { error: 'Password must be at least 8 characters' }), + confirm_password: z.string().min(1, { error: 'Please confirm your password' }), + isSuperuser: z.boolean(), + isActive: z.boolean(), }) .refine((data) => data.password === data.confirm_password, { - message: "The passwords don't match", + error: "The passwords don't match", path: ['confirm_password'], }) @@ -51,11 +52,11 @@ const AddUser = () => { const form = useForm({ defaultValues: { email: '', - full_name: '', + fullName: '', password: '', confirm_password: '', - is_superuser: false, - is_active: false, + isSuperuser: false, + isActive: false, } as FormData, validators: { onChange: formSchema, @@ -82,7 +83,7 @@ const AddUser = () => { return ( }> - + Add User @@ -124,7 +125,7 @@ const AddUser = () => { )} - + {(field) => ( Full Name @@ -192,7 +193,7 @@ const AddUser = () => { )} - + {(field) => ( { )} - + {(field) => ( data.new_password === data.confirm_password, { - message: "The passwords don't match", + .refine((data) => data.newPassword === data.confirm_password, { + error: "The passwords don't match", path: ['confirm_password'], }) @@ -35,8 +35,8 @@ const ChangePassword = () => { const form = useForm({ defaultValues: { - current_password: '', - new_password: '', + currentPassword: '', + newPassword: '', confirm_password: '', } as FormData, validators: { @@ -69,7 +69,7 @@ const ChangePassword = () => { }} className='flex flex-col gap-4' > - + {(field) => ( Current Password @@ -91,7 +91,7 @@ const ChangePassword = () => { )} - + {(field) => ( New Password diff --git a/frontend/src/components/form/ComboBox.tsx b/frontend/src/components/form/ComboBox.tsx index 504fa9c..61364d5 100644 --- a/frontend/src/components/form/ComboBox.tsx +++ b/frontend/src/components/form/ComboBox.tsx @@ -114,6 +114,7 @@ export function ComboBox({ {filteredOptions.map((option) => (
  • handleSelect(option)} onKeyDown={(e) => { diff --git a/frontend/src/components/form/DeleteConfirmation.tsx b/frontend/src/components/form/DeleteConfirmation.tsx index a28911a..6621169 100644 --- a/frontend/src/components/form/DeleteConfirmation.tsx +++ b/frontend/src/components/form/DeleteConfirmation.tsx @@ -1,6 +1,6 @@ import { useMutation, useQueryClient } from '@tanstack/react-query' -import { Button } from '@/components/ui/button.tsx' +import { Button } from '@/components/ui/button' import { Dialog, DialogClose, @@ -10,12 +10,12 @@ import { DialogHeader, DialogTitle, DialogTrigger, -} from '@/components/ui/dialog.tsx' -import { Spinner } from '@/components/ui/spinner.tsx' +} from '@/components/ui/dialog' +import { Spinner } from '@/components/ui/spinner' import { UsersService } from '@/lib/client' import { handleError } from '@/lib/client-utils.ts' -import useAuth from '@/lib/hooks/useAuth.ts' -import useCustomToast from '@/lib/hooks/useCustomToast.ts' +import useAuth from '@/routes/-hooks/hooks/useAuth.ts' +import useCustomToast from '@/routes/-hooks/hooks/useCustomToast.ts' const DeleteConfirmation = () => { const queryClient = useQueryClient() diff --git a/frontend/src/components/form/UserInformation.tsx b/frontend/src/components/form/UserInformation.tsx index 6495b6e..16fbe60 100644 --- a/frontend/src/components/form/UserInformation.tsx +++ b/frontend/src/components/form/UserInformation.tsx @@ -3,19 +3,19 @@ import { useMutation, useQueryClient } from '@tanstack/react-query' import { useState } from 'react' import { z } from 'zod' -import { Button } from '@/components/ui/button.tsx' -import { Field, FieldError, FieldLabel } from '@/components/ui/field.tsx' -import { Input } from '@/components/ui/input.tsx' -import { Spinner } from '@/components/ui/spinner.tsx' +import { Button } from '@/components/ui/button' +import { Field, FieldError, FieldLabel } from '@/components/ui/field' +import { Input } from '@/components/ui/input' +import { Spinner } from '@/components/ui/spinner' import { UsersService, type UserUpdateMe } from '@/lib/client' import { handleError } from '@/lib/client-utils.ts' -import useAuth from '@/lib/hooks/useAuth.ts' -import useCustomToast from '@/lib/hooks/useCustomToast.ts' import { cn } from '@/lib/utils.ts' +import useAuth from '@/routes/-hooks/hooks/useAuth.ts' +import useCustomToast from '@/routes/-hooks/hooks/useCustomToast.ts' const formSchema = z.object({ - full_name: z.string().max(30).optional(), - email: z.string().email({ message: 'Invalid email address' }), + fullName: z.string().max(30).optional(), + email: z.string().email({ error: 'Invalid email address' }), }) type FormData = z.infer @@ -28,7 +28,7 @@ const UserInformation = () => { const form = useForm({ defaultValues: { - full_name: currentUser?.full_name ?? '', + fullName: currentUser?.fullName ?? '', email: currentUser?.email ?? '', } as FormData, validators: { @@ -37,8 +37,8 @@ const UserInformation = () => { onSubmit: async ({ value }) => { const updateData: UserUpdateMe = {} - if (value.full_name !== currentUser?.full_name) { - updateData.full_name = value.full_name + if (value.fullName !== currentUser?.fullName) { + updateData.fullName = value.fullName } if (value.email !== currentUser?.email) { updateData.email = value.email @@ -80,7 +80,7 @@ const UserInformation = () => { }} className='flex flex-col gap-4' > - + {(field) => editMode ? ( diff --git a/frontend/src/components/form/demo-form.tsx b/frontend/src/components/form/demo-form.tsx index d3ec436..6634114 100644 --- a/frontend/src/components/form/demo-form.tsx +++ b/frontend/src/components/form/demo-form.tsx @@ -1,13 +1,13 @@ import { createFormHookContexts } from '@tanstack/react-form' import { useStore } from '@tanstack/react-form' -import { Button } from '@/components/ui/button.tsx' -import { Input } from '@/components/ui/input.tsx' -import { Label } from '@/components/ui/label.tsx' -import * as ShadcnSelect from '@/components/ui/select.tsx' -// import { Slider as ShadcnSlider } from '@/components/ui/slider.tsx' -// import { Switch as ShadcnSwitch } from '@/components/ui/switch.tsx' -import { Textarea as ShadcnTextarea } from '@/components/ui/textarea.tsx' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import * as ShadcnSelect from '@/components/ui/select' +// import { Slider as ShadcnSlider } from '@/components/ui/slider' +// import { Switch as ShadcnSwitch } from '@/components/ui/switch' +import { Textarea as ShadcnTextarea } from '@/components/ui/textarea' export function SubscribeButton({ label }: { label: string }) { const form = useFormContext() diff --git a/frontend/src/components/form/home-search-form.tsx b/frontend/src/components/form/home-search-form.tsx index 84bb3d3..0f87f57 100644 --- a/frontend/src/components/form/home-search-form.tsx +++ b/frontend/src/components/form/home-search-form.tsx @@ -2,8 +2,8 @@ import { useForm } from '@tanstack/react-form' import { useQuery } from '@tanstack/react-query' import { useState } from 'react' -import { ComboBox } from '@/components/form/ComboBox.tsx' -import { useDebounce } from '@/lib/hooks/useDebounce.ts' +import { ComboBox } from '@/components/form/ComboBox' +import { useDebounce } from '@/routes/-hooks/hooks/useDebounce.ts' interface SchoolSummary { id: string diff --git a/frontend/src/components/form/use-app-form.ts b/frontend/src/components/form/use-app-form.ts index 2f37015..19c3793 100644 --- a/frontend/src/components/form/use-app-form.ts +++ b/frontend/src/components/form/use-app-form.ts @@ -7,7 +7,7 @@ import { SubscribeButton, TextArea, TextField, -} from '@/components/form/demo-form.tsx' +} from '@/components/form/demo-form' export const { useAppForm } = createFormHook({ fieldComponents: { diff --git a/frontend/src/components/Items/AddItem.tsx b/frontend/src/components/items/AddItem.tsx similarity index 94% rename from frontend/src/components/Items/AddItem.tsx rename to frontend/src/components/items/AddItem.tsx index 6b569f2..1153bac 100644 --- a/frontend/src/components/Items/AddItem.tsx +++ b/frontend/src/components/items/AddItem.tsx @@ -1,6 +1,7 @@ +import { PlusSignIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { useForm } from '@tanstack/react-form' import { useMutation, useQueryClient } from '@tanstack/react-query' -import { Plus } from 'lucide-react' import { useState } from 'react' import { z } from 'zod' @@ -20,7 +21,7 @@ import { Input } from '@/components/ui/input' import { Spinner } from '@/components/ui/spinner' import { type ItemCreate, ItemsService } from '@/lib/client' import { handleError } from '@/lib/client-utils' -import useCustomToast from '@/lib/hooks/useCustomToast' +import useCustomToast from '@/routes/-hooks/hooks/useCustomToast' const formSchema = z.object({ title: z.string().min(1, { message: 'Title is required' }), @@ -63,7 +64,7 @@ const AddItem = () => { return ( }> - + Add Item diff --git a/frontend/src/components/Items/DeleteItem.tsx b/frontend/src/components/items/DeleteItem.tsx similarity index 91% rename from frontend/src/components/Items/DeleteItem.tsx rename to frontend/src/components/items/DeleteItem.tsx index b10afca..847edd7 100644 --- a/frontend/src/components/Items/DeleteItem.tsx +++ b/frontend/src/components/items/DeleteItem.tsx @@ -1,5 +1,6 @@ +import { Delete02Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { useMutation, useQueryClient } from '@tanstack/react-query' -import { Trash2 } from 'lucide-react' import { useState } from 'react' import { Button } from '@/components/ui/button' @@ -16,7 +17,7 @@ import { DropdownMenuItem } from '@/components/ui/dropdown-menu' import { Spinner } from '@/components/ui/spinner' import { ItemsService } from '@/lib/client' import { handleError } from '@/lib/client-utils' -import useCustomToast from '@/lib/hooks/useCustomToast' +import useCustomToast from '@/routes/-hooks/hooks/useCustomToast' interface DeleteItemProps { id: string @@ -53,7 +54,7 @@ const DeleteItem = ({ id, onSuccess }: DeleteItemProps) => { onSelect={(e) => e.preventDefault()} onClick={() => setIsOpen(true)} > - + Delete Item diff --git a/frontend/src/components/Items/EditItem.tsx b/frontend/src/components/items/EditItem.tsx similarity index 93% rename from frontend/src/components/Items/EditItem.tsx rename to frontend/src/components/items/EditItem.tsx index 6fb63bd..f1964be 100644 --- a/frontend/src/components/Items/EditItem.tsx +++ b/frontend/src/components/items/EditItem.tsx @@ -1,6 +1,7 @@ +import { PencilEdit02Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { useForm } from '@tanstack/react-form' import { useMutation, useQueryClient } from '@tanstack/react-query' -import { Pencil } from 'lucide-react' import { useState } from 'react' import { z } from 'zod' @@ -20,10 +21,10 @@ import { Input } from '@/components/ui/input' import { Spinner } from '@/components/ui/spinner' import { type ItemPublic, ItemsService } from '@/lib/client' import { handleError } from '@/lib/client-utils' -import useCustomToast from '@/lib/hooks/useCustomToast' +import useCustomToast from '@/routes/-hooks/hooks/useCustomToast' const formSchema = z.object({ - title: z.string().min(1, { message: 'Title is required' }), + title: z.string().min(1, { error: 'Title is required' }), description: z.string().optional(), }) @@ -69,7 +70,7 @@ const EditItem = ({ item, onSuccess }: EditItemProps) => { return ( e.preventDefault()} onClick={() => setIsOpen(true)}> - + Edit Item diff --git a/frontend/src/components/Items/ItemActionsMenu.tsx b/frontend/src/components/items/ItemActionsMenu.tsx similarity index 85% rename from frontend/src/components/Items/ItemActionsMenu.tsx rename to frontend/src/components/items/ItemActionsMenu.tsx index 1ba0553..b0038bf 100644 --- a/frontend/src/components/Items/ItemActionsMenu.tsx +++ b/frontend/src/components/items/ItemActionsMenu.tsx @@ -1,4 +1,5 @@ -import { EllipsisVertical } from 'lucide-react' +import { MoreVerticalIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { useState } from 'react' import DeleteItem from '@/components/items/DeleteItem' @@ -26,7 +27,7 @@ export const ItemActionsMenu = ({ item, canManage }: ItemActionsMenuProps) => { return ( }> - + setOpen(false)} /> diff --git a/frontend/src/components/Items/columns.tsx b/frontend/src/components/items/columns.tsx similarity index 85% rename from frontend/src/components/Items/columns.tsx rename to frontend/src/components/items/columns.tsx index e3efb92..cb05e92 100644 --- a/frontend/src/components/Items/columns.tsx +++ b/frontend/src/components/items/columns.tsx @@ -1,10 +1,11 @@ +import { Copy01Icon, Tick02Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import type { ColumnDef } from '@tanstack/react-table' -import { Check, Copy } from 'lucide-react' import { Button } from '@/components/ui/button' import type { ItemPublic } from '@/lib/client' -import { useCopyToClipboard } from '@/lib/hooks/useCopyToClipboard' import { cn } from '@/lib/utils' +import { useCopyToClipboard } from '@/routes/-hooks/hooks/useCopyToClipboard' import { ItemActionsMenu } from './ItemActionsMenu' @@ -21,7 +22,11 @@ function CopyId({ id }: { id: string }) { className='size-6 opacity-0 group-hover:opacity-100 transition-opacity' onClick={() => copy(id)} > - {isCopied ? : } + {isCopied ? ( + + ) : ( + + )} Copy ID
  • diff --git a/frontend/src/components/layout/navbar/DistrictSelector.tsx b/frontend/src/components/layout/navbar/DistrictSelector.tsx deleted file mode 100644 index 6927cad..0000000 --- a/frontend/src/components/layout/navbar/DistrictSelector.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { useEffect, useRef, useState } from 'react' -// import { useAuth } from "../components/hooks/use-auth"; - -export default function DistrictSelector() { - const [open, setOpen] = useState(false) - const dropdownRef = useRef(null) - // const auth = useAuth(); - - useEffect(() => { - function handleClickOutside(event: MouseEvent) { - if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { - setOpen(false) - } - } - - if (open) { - document.addEventListener('mousedown', handleClickOutside) - } else { - document.removeEventListener('mousedown', handleClickOutside) - } - return () => { - document.removeEventListener('mousedown', handleClickOutside) - } - }, [open]) - - // if (!auth.currentOrg) { - // return null; - // } - - return ( -
    - - Circle seperator icon - - - - {open && ( - - )} -
    - ) -} diff --git a/frontend/src/components/ui/loading-button.tsx b/frontend/src/components/loading-button.tsx similarity index 96% rename from frontend/src/components/ui/loading-button.tsx rename to frontend/src/components/loading-button.tsx index 74a32cf..834290f 100644 --- a/frontend/src/components/ui/loading-button.tsx +++ b/frontend/src/components/loading-button.tsx @@ -3,7 +3,7 @@ import { forwardRef } from 'react' import { Button, type buttonVariants } from '@/components/ui/button' import { Spinner } from '@/components/ui/spinner' -import { cn } from '@/lib/utils' +import { cn } from '@/lib/utils.ts' export interface LoadingButtonProps extends React.ButtonHTMLAttributes, VariantProps { diff --git a/frontend/src/components/ui/password-input.tsx b/frontend/src/components/password-input.tsx similarity index 75% rename from frontend/src/components/ui/password-input.tsx rename to frontend/src/components/password-input.tsx index 8f302a2..be59204 100644 --- a/frontend/src/components/ui/password-input.tsx +++ b/frontend/src/components/password-input.tsx @@ -1,9 +1,10 @@ -import { Eye, EyeOff } from 'lucide-react' +import { ViewIcon, ViewOffIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { forwardRef, useState } from 'react' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' -import { cn } from '@/lib/utils' +import { cn } from '@/lib/utils.ts' export interface PasswordInputProps extends React.InputHTMLAttributes {} @@ -28,9 +29,9 @@ const PasswordInput = forwardRef( aria-label={showPassword ? 'Hide password' : 'Show password'} > {showPassword ? ( - + ) : ( - + )}
    diff --git a/frontend/src/components/stories/Button.stories.ts b/frontend/src/components/stories/Button.stories.ts deleted file mode 100644 index 1a9f4d5..0000000 --- a/frontend/src/components/stories/Button.stories.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' -import { fn } from 'storybook/test' - -import { Button } from './Button' - -// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export -const meta = { - title: 'Example/Button', - component: Button, - parameters: { - // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout - layout: 'centered', - }, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs - tags: ['autodocs'], - // More on argTypes: https://storybook.js.org/docs/api/argtypes - argTypes: { - backgroundColor: { control: 'color' }, - }, - // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args - args: { onClick: fn() }, -} satisfies Meta - -export default meta -type Story = StoryObj - -// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args -export const Primary: Story = { - args: { - primary: true, - label: 'Button', - }, -} - -export const Secondary: Story = { - args: { - label: 'Button', - }, -} - -export const Large: Story = { - args: { - size: 'large', - label: 'Button', - }, -} - -export const Small: Story = { - args: { - size: 'small', - label: 'Button', - }, -} diff --git a/frontend/src/components/stories/Button.tsx b/frontend/src/components/stories/Button.tsx deleted file mode 100644 index c18db5d..0000000 --- a/frontend/src/components/stories/Button.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import './button.css' - -export interface ButtonProps { - /** Is this the principal call to action on the page? */ - primary?: boolean - /** What background color to use */ - backgroundColor?: string - /** How large should the button be? */ - size?: 'small' | 'medium' | 'large' - /** Button contents */ - label: string - /** Optional click handler */ - onClick?: () => void -} - -/** Primary UI component for user interaction */ -export const Button = ({ - primary = false, - size = 'medium', - backgroundColor, - label, - ...props -}: ButtonProps) => { - const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary' - return ( - - ) -} diff --git a/frontend/src/components/stories/Configure.mdx b/frontend/src/components/stories/Configure.mdx deleted file mode 100644 index 5f121c3..0000000 --- a/frontend/src/components/stories/Configure.mdx +++ /dev/null @@ -1,380 +0,0 @@ -import { Meta } from '@storybook/addon-docs/blocks' - -import Github from './assets/github.svg' -import Discord from './assets/discord.svg' -import Youtube from './assets/youtube.svg' -import Tutorials from './assets/tutorials.svg' -import Styling from './assets/styling.png' -import Context from './assets/context.png' -import Assets from './assets/assets.png' -import Docs from './assets/docs.png' -import Share from './assets/share.png' -import FigmaPlugin from './assets/figma-plugin.png' -import Testing from './assets/testing.png' -import Accessibility from './assets/accessibility.png' -import Theming from './assets/theming.png' -import AddonLibrary from './assets/addon-library.png' - -export const RightArrow = () => ( - - - -) - - - -
    -
    - # Configure your project - - Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. - Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how - you can ask for help from our community. -
    -
    -
    - A wall of logos representing different styling technologies -

    Add styling and CSS

    -

    Like with web applications, there are many ways to include CSS - within Storybook. Learn more about setting up styling within Storybook.

    - Learn more -
    -
    - An abstraction representing the composition of data for a component -

    Provide context and mocking

    -

    Often when a story doesn't render, it's because your component is - expecting a specific environment or context (like a theme provider) to be available.

    - Learn more -
    -
    - A representation of typography and image assets -
    -

    Load assets and resources

    -

    To link static files (like fonts) to your projects and stories, - use the - `staticDirs` configuration option to specify folders to load when - starting Storybook.

    - Learn more -
    -
    -
    - -
    -
    -
    - # Do more with Storybook - - Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This - list is just to get you started. You can customise Storybook in many ways to fit your needs. -
    - -
    -
    -
    - A screenshot showing the autodocs tag being set, pointing a docs page being generated -

    Autodocs

    -

    Auto-generate living, - interactive reference documentation from your components and stories.

    - Learn more -
    -
    - A browser window showing a Storybook being published to a chromatic.com URL -

    Publish to Chromatic

    -

    Publish your Storybook to review and collaborate with your - entire team.

    - Learn more -
    -
    - Windows showing the Storybook plugin in Figma -

    Figma Plugin

    -

    Embed your stories into Figma to cross-reference the design and - live - implementation in one place.

    - Learn more -
    -
    - Screenshot of tests passing and failing -

    Testing

    -

    Use stories to test a component in all its variations, no - matter how - complex.

    - Learn more -
    -
    - Screenshot of accessibility tests passing and failing -

    Accessibility

    -

    Automatically test your components for a11y issues as you - develop.

    - Learn more -
    -
    - Screenshot of Storybook in light and dark mode -

    Theming

    -

    Theme Storybook's UI to personalize it to your project.

    - Learn more -
    -
    -
    - -
    -
    -
    -

    Addons

    -

    Integrate your tools with Storybook to connect workflows.

    - Discover all addons -
    -
    - Integrate your tools with Storybook to connect workflows. -
    -
    - -
    -
    - Github logo - Join our contributors building the future of UI development. - - Star on GitHub -
    -
    - Discord logo -
    - Get support and chat with frontend developers. - - Join Discord server -
    -
    -
    - Youtube logo -
    - Watch tutorials, feature previews and interviews. - - Watch on YouTube -
    -
    -
    - A book -

    Follow guided walkthroughs on for key workflows.

    - - Discover tutorials -
    - -
    - - diff --git a/frontend/src/components/stories/Header.stories.ts b/frontend/src/components/stories/Header.stories.ts deleted file mode 100644 index 48b7fee..0000000 --- a/frontend/src/components/stories/Header.stories.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' -import { fn } from 'storybook/test' - -import { Header } from './Header' - -const meta = { - title: 'Example/Header', - component: Header, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs - tags: ['autodocs'], - parameters: { - // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout - layout: 'fullscreen', - }, - args: { - onLogin: fn(), - onLogout: fn(), - onCreateAccount: fn(), - }, -} satisfies Meta - -export default meta -type Story = StoryObj - -export const LoggedIn: Story = { - args: { - user: { - name: 'Jane Doe', - }, - }, -} - -export const LoggedOut: Story = {} diff --git a/frontend/src/components/stories/Header.tsx b/frontend/src/components/stories/Header.tsx deleted file mode 100644 index 241535e..0000000 --- a/frontend/src/components/stories/Header.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Button } from './Button' - -import './header.css' - -type User = { - name: string -} - -export interface HeaderProps { - user?: User - onLogin?: () => void - onLogout?: () => void - onCreateAccount?: () => void -} - -export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => ( -
    -
    -
    - - Canvas zoom - - - - - - -

    Acme

    -
    -
    - {user ? ( - <> - - Welcome, {user.name}! - -
    -
    -
    -) diff --git a/frontend/src/components/stories/ListOfSchools.mdx b/frontend/src/components/stories/ListOfSchools.mdx deleted file mode 100644 index b678783..0000000 --- a/frontend/src/components/stories/ListOfSchools.mdx +++ /dev/null @@ -1,380 +0,0 @@ -import { Meta } from '@storybook/addon-docs/blocks' - -import Github from './assets/github.svg' -import Discord from './assets/discord.svg' -import Youtube from './assets/youtube.svg' -import Tutorials from './assets/tutorials.svg' -import Styling from './assets/styling.png' -import Context from './assets/context.png' -import Assets from './assets/assets.png' -import Docs from './assets/docs.png' -import Share from './assets/share.png' -import FigmaPlugin from './assets/figma-plugin.png' -import Testing from './assets/testing.png' -import Accessibility from './assets/accessibility.png' -import Theming from './assets/theming.png' -import AddonLibrary from './assets/addon-library.png' - -export const RightArrow = () => ( - - - -) - - - -
    -
    - # List of Schools - - Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. - Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how - you can ask for help from our community. -
    -
    -
    - A wall of logos representing different styling technologies -

    Add styling and CSS

    -

    Like with web applications, there are many ways to include CSS - within Storybook. Learn more about setting up styling within Storybook.

    - Learn more -
    -
    - An abstraction representing the composition of data for a component -

    Provide context and mocking

    -

    Often when a story doesn't render, it's because your component is - expecting a specific environment or context (like a theme provider) to be available.

    - Learn more -
    -
    - A representation of typography and image assets -
    -

    Load assets and resources

    -

    To link static files (like fonts) to your projects and stories, - use the - `staticDirs` configuration option to specify folders to load when - starting Storybook.

    - Learn more -
    -
    -
    - -
    -
    -
    - # Do more with Storybook - - Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This - list is just to get you started. You can customise Storybook in many ways to fit your needs. -
    - -
    -
    -
    - A screenshot showing the autodocs tag being set, pointing a docs page being generated -

    Autodocs

    -

    Auto-generate living, - interactive reference documentation from your components and stories.

    - Learn more -
    -
    - A browser window showing a Storybook being published to a chromatic.com URL -

    Publish to Chromatic

    -

    Publish your Storybook to review and collaborate with your - entire team.

    - Learn more -
    -
    - Windows showing the Storybook plugin in Figma -

    Figma Plugin

    -

    Embed your stories into Figma to cross-reference the design and - live - implementation in one place.

    - Learn more -
    -
    - Screenshot of tests passing and failing -

    Testing

    -

    Use stories to test a component in all its variations, no - matter how - complex.

    - Learn more -
    -
    - Screenshot of accessibility tests passing and failing -

    Accessibility

    -

    Automatically test your components for a11y issues as you - develop.

    - Learn more -
    -
    - Screenshot of Storybook in light and dark mode -

    Theming

    -

    Theme Storybook's UI to personalize it to your project.

    - Learn more -
    -
    -
    - -
    -
    -
    -

    Addons

    -

    Integrate your tools with Storybook to connect workflows.

    - Discover all addons -
    -
    - Integrate your tools with Storybook to connect workflows. -
    -
    - -
    -
    - Github logo - Join our contributors building the future of UI development. - - Star on GitHub -
    -
    - Discord logo -
    - Get support and chat with frontend developers. - - Join Discord server -
    -
    -
    - Youtube logo -
    - Watch tutorials, feature previews and interviews. - - Watch on YouTube -
    -
    -
    - A book -

    Follow guided walkthroughs on for key workflows.

    - - Discover tutorials -
    - -
    - - diff --git a/frontend/src/components/stories/Page.stories.ts b/frontend/src/components/stories/Page.stories.ts deleted file mode 100644 index f31cae2..0000000 --- a/frontend/src/components/stories/Page.stories.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react-vite' -import { expect, userEvent, within } from 'storybook/test' - -import { Page } from './Page' - -const meta = { - title: 'Example/Page', - component: Page, - parameters: { - // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout - layout: 'fullscreen', - }, -} satisfies Meta - -export default meta -type Story = StoryObj - -export const LoggedOut: Story = {} - -// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing -export const LoggedIn: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement) - const loginButton = canvas.getByRole('button', { name: /Log in/i }) - await expect(loginButton).toBeInTheDocument() - await userEvent.click(loginButton) - await expect(loginButton).not.toBeInTheDocument() - - const logoutButton = canvas.getByRole('button', { name: /Log out/i }) - await expect(logoutButton).toBeInTheDocument() - }, -} diff --git a/frontend/src/components/stories/Page.tsx b/frontend/src/components/stories/Page.tsx deleted file mode 100644 index 397c4cf..0000000 --- a/frontend/src/components/stories/Page.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { useState } from 'react' - -import './page.css' -import { Header } from './Header' - -type User = { - name: string -} - -export const Page: React.FC = () => { - const [user, setUser] = useState() - - return ( -
    -
    setUser({ name: 'Jane Doe' })} - onLogout={() => setUser(undefined)} - onCreateAccount={() => setUser({ name: 'Jane Doe' })} - /> - -
    -

    Pages in Storybook

    -

    - We recommend building UIs with a{' '} - - component-driven - {' '} - process starting with atomic components and ending with pages. -

    -

    - Render pages with mock data. This makes it easy to build and review page states without - needing to navigate to them in your app. Here are some handy patterns for managing page - data in Storybook: -

    -
      -
    • - Use a higher-level connected component. Storybook helps you compose such data from the - "args" of child component stories -
    • -
    • - Assemble data in the page component from your services. You can mock these services out - using Storybook. -
    • -
    -

    - Get a guided tutorial on component-driven development at{' '} - - Storybook tutorials - - . Read more in the{' '} - - docs - - . -

    -
    - Tip Adjust the width of the canvas with the{' '} - - Canvas zoom - - - - - Viewports addon in the toolbar -
    -
    -
    - ) -} diff --git a/frontend/src/components/stories/README.md b/frontend/src/components/stories/README.md deleted file mode 100644 index 1f4c95e..0000000 --- a/frontend/src/components/stories/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Frontend Stories Documentation - -Use this folder for Storybook stories and supporting component docs. - -## Quick links - -1. Chakra UI cards details: [CHAKRA_UI_CARDS.md](./CHAKRA_UI_CARDS.md) -2. Developer Guide components page: -3. Developer Guide Storybook page: - -## Source references - -- Card component implementation: `frontend/src/components/ui/card.tsx` -- Storybook stories directory: `frontend/src/components/stories` diff --git a/frontend/src/components/stories/button.css b/frontend/src/components/stories/button.css deleted file mode 100644 index 6146299..0000000 --- a/frontend/src/components/stories/button.css +++ /dev/null @@ -1,35 +0,0 @@ -.storybook-button { - display: inline-block; - cursor: pointer; - border: 0; - border-radius: 3em; - font-weight: 700; - line-height: 1; - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -.storybook-button--primary { - background-color: #555ab9; - color: white; -} - -.storybook-button--secondary { - box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; - background-color: transparent; - color: #333; -} - -.storybook-button--small { - padding: 10px 16px; - font-size: 12px; -} - -.storybook-button--medium { - padding: 11px 20px; - font-size: 14px; -} - -.storybook-button--large { - padding: 12px 24px; - font-size: 16px; -} diff --git a/frontend/src/components/stories/header.css b/frontend/src/components/stories/header.css deleted file mode 100644 index d511c66..0000000 --- a/frontend/src/components/stories/header.css +++ /dev/null @@ -1,32 +0,0 @@ -.storybook-header { - display: flex; - justify-content: space-between; - align-items: center; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); - padding: 15px 20px; - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -.storybook-header svg { - display: inline-block; - vertical-align: top; -} - -.storybook-header h1 { - display: inline-block; - vertical-align: top; - margin: 6px 0 6px 10px; - font-weight: 700; - font-size: 20px; - line-height: 1; -} - -.storybook-header button + button { - margin-left: 10px; -} - -.storybook-header .welcome { - margin-right: 10px; - color: #333; - font-size: 14px; -} diff --git a/frontend/src/components/stories/page.css b/frontend/src/components/stories/page.css deleted file mode 100644 index 67f2bb2..0000000 --- a/frontend/src/components/stories/page.css +++ /dev/null @@ -1,68 +0,0 @@ -.storybook-page { - margin: 0 auto; - padding: 48px 20px; - max-width: 600px; - color: #333; - font-size: 14px; - line-height: 24px; - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -.storybook-page h2 { - display: inline-block; - vertical-align: top; - margin: 0 0 4px; - font-weight: 700; - font-size: 32px; - line-height: 1; -} - -.storybook-page p { - margin: 1em 0; -} - -.storybook-page a { - color: inherit; -} - -.storybook-page ul { - margin: 1em 0; - padding-left: 30px; -} - -.storybook-page li { - margin-bottom: 8px; -} - -.storybook-page .tip { - display: inline-block; - vertical-align: top; - margin-right: 10px; - border-radius: 1em; - background: #e7fdd8; - padding: 4px 12px; - color: #357a14; - font-weight: 700; - font-size: 11px; - line-height: 12px; -} - -.storybook-page .tip-wrapper { - margin-top: 40px; - margin-bottom: 40px; - font-size: 13px; - line-height: 20px; -} - -.storybook-page .tip-wrapper svg { - display: inline-block; - vertical-align: top; - margin-top: 3px; - margin-right: 4px; - width: 12px; - height: 12px; -} - -.storybook-page .tip-wrapper svg path { - fill: #1ea7fd; -} diff --git a/frontend/src/components/ui/alert-dialog.tsx b/frontend/src/components/ui/alert-dialog.tsx index 94e7b31..49df3c8 100644 --- a/frontend/src/components/ui/alert-dialog.tsx +++ b/frontend/src/components/ui/alert-dialog.tsx @@ -1,5 +1,3 @@ -'use client' - import { AlertDialog as AlertDialogPrimitive } from '@base-ui/react/alert-dialog' import * as React from 'react' @@ -45,7 +43,7 @@ function AlertDialogContent({ data-slot='alert-dialog-content' data-size={size} className={cn( - 'group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-6 rounded-4xl bg-background p-6 ring-1 ring-foreground/5 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-md data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95', + 'group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-6 rounded-4xl bg-popover p-6 text-popover-foreground ring-1 ring-foreground/5 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-md data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95', className, )} {...props} diff --git a/frontend/src/components/ui/avatar.tsx b/frontend/src/components/ui/avatar.tsx index f020556..418097e 100644 --- a/frontend/src/components/ui/avatar.tsx +++ b/frontend/src/components/ui/avatar.tsx @@ -1,5 +1,3 @@ -'use client' - import { Avatar as AvatarPrimitive } from '@base-ui/react/avatar' import * as React from 'react' diff --git a/frontend/src/components/ui/breadcrumb.tsx b/frontend/src/components/ui/breadcrumb.tsx index 0efd77a..c911142 100644 --- a/frontend/src/components/ui/breadcrumb.tsx +++ b/frontend/src/components/ui/breadcrumb.tsx @@ -53,6 +53,8 @@ function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) { return ( ) { return ( ) diff --git a/frontend/src/components/ui/carousel.tsx b/frontend/src/components/ui/carousel.tsx index dca79c7..5fc8848 100644 --- a/frontend/src/components/ui/carousel.tsx +++ b/frontend/src/components/ui/carousel.tsx @@ -1,5 +1,3 @@ -'use client' - import { ArrowLeft01Icon, ArrowRight01Icon } from '@hugeicons/core-free-icons' import { HugeiconsIcon } from '@hugeicons/react' import useEmblaCarousel, { type UseEmblaCarouselType } from 'embla-carousel-react' diff --git a/frontend/src/components/ui/chart.tsx b/frontend/src/components/ui/chart.tsx index 823421d..747d664 100644 --- a/frontend/src/components/ui/chart.tsx +++ b/frontend/src/components/ui/chart.tsx @@ -1,20 +1,25 @@ import * as React from 'react' import * as RechartsPrimitive from 'recharts' +import type { TooltipValueType } from 'recharts' import { cn } from '@/lib/utils' // Format: { THEME_NAME: CSS_SELECTOR } const THEMES = { light: '', dark: '.dark' } as const -export type ChartConfig = { - [k in string]: { +const INITIAL_DIMENSION = { width: 320, height: 200 } as const +type TooltipNameType = number | string + +export type ChartConfig = Record< + string, + { label?: React.ReactNode icon?: React.ComponentType } & ( | { color?: string; theme?: never } | { color?: never; theme: Record } ) -} +> type ChartContextProps = { config: ChartConfig @@ -37,13 +42,18 @@ function ChartContainer({ className, children, config, + initialDimension = INITIAL_DIMENSION, ...props }: React.ComponentProps<'div'> & { config: ChartConfig children: React.ComponentProps['children'] + initialDimension?: { + width: number + height: number + } }) { const uniqueId = React.useId() - const chartId = `chart-${id || uniqueId.replace(/:/g, '')}` + const chartId = `chart-${id ?? uniqueId.replace(/:/g, '')}` return ( @@ -57,14 +67,16 @@ function ChartContainer({ {...props} > - {children} + + {children} +
    ) } const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { - const colorConfig = Object.entries(config).filter(([, config]) => config.theme || config.color) + const colorConfig = Object.entries(config).filter(([, config]) => config.theme ?? config.color) if (!colorConfig.length) { return null @@ -79,7 +91,7 @@ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { ${prefix} [data-chart=${id}] { ${colorConfig .map(([key, itemConfig]) => { - const color = itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || itemConfig.color + const color = itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ?? itemConfig.color return color ? ` --color-${key}: ${color};` : null }) .join('\n')} @@ -94,31 +106,31 @@ ${colorConfig const ChartTooltip = RechartsPrimitive.Tooltip -function ChartTooltipContent( - props: RechartsPrimitive.TooltipProps & - React.ComponentProps<'div'> & { - hideLabel?: boolean - hideIndicator?: boolean - indicator?: 'line' | 'dot' | 'dashed' - nameKey?: string - labelKey?: string - }, -) { - const { - active, - payload, - className, - indicator = 'dot', - hideLabel = false, - hideIndicator = false, - label, - labelFormatter, - labelClassName, - formatter, - color, - nameKey, - labelKey, - } = props as any +function ChartTooltipContent({ + active, + payload, + className, + indicator = 'dot', + hideLabel = false, + hideIndicator = false, + label, + labelFormatter, + labelClassName, + formatter, + color, + nameKey, + labelKey, +}: React.ComponentProps & + React.ComponentProps<'div'> & { + hideLabel?: boolean + hideIndicator?: boolean + indicator?: 'line' | 'dot' | 'dashed' + nameKey?: string + labelKey?: string + } & Omit< + RechartsPrimitive.DefaultTooltipContentProps, + 'accessibilityLayer' + >) { const { config } = useChart() const tooltipLabel = React.useMemo(() => { @@ -127,12 +139,10 @@ function ChartTooltipContent( } const [item] = payload - const key = `${labelKey || item?.dataKey || item?.name || 'value'}` + const key = `${labelKey ?? item?.dataKey ?? item?.name ?? 'value'}` const itemConfig = getPayloadConfigFromPayload(config, item, key) const value = - !labelKey && typeof label === 'string' - ? config[label as keyof typeof config]?.label || label - : itemConfig?.label + !labelKey && typeof label === 'string' ? (config[label]?.label ?? label) : itemConfig?.label if (labelFormatter) { return ( @@ -163,15 +173,15 @@ function ChartTooltipContent( {!nestLabel ? tooltipLabel : null}
    {payload - .filter((item: any) => item.type !== 'none') - .map((item: any, index: number) => { - const key = `${nameKey || item.name || item.dataKey || 'value'}` + .filter((item) => item.type !== 'none') + .map((item, index) => { + const key = `${nameKey ?? item.name ?? item.dataKey ?? 'value'}` const itemConfig = getPayloadConfigFromPayload(config, item, key) - const indicatorColor = color || item.payload.fill || item.color + const indicatorColor = color ?? item.payload?.fill ?? item.color return (
    svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground', indicator === 'dot' && 'items-center', @@ -214,12 +224,14 @@ function ChartTooltipContent(
    {nestLabel ? tooltipLabel : null} - {itemConfig?.label || item.name} + {itemConfig?.label ?? item.name}
    - {item.value && ( + {item.value != null && ( - {item.value.toLocaleString()} + {typeof item.value === 'number' + ? item.value.toLocaleString() + : String(item.value)} )}
    @@ -235,14 +247,16 @@ function ChartTooltipContent( const ChartLegend = RechartsPrimitive.Legend -function ChartLegendContent( - props: React.ComponentProps<'div'> & - RechartsPrimitive.LegendProps & { - hideIcon?: boolean - nameKey?: string - }, -) { - const { className, hideIcon = false, payload, verticalAlign = 'bottom', nameKey } = props as any +function ChartLegendContent({ + className, + hideIcon = false, + payload, + verticalAlign = 'bottom', + nameKey, +}: React.ComponentProps<'div'> & { + hideIcon?: boolean + nameKey?: string +} & RechartsPrimitive.DefaultLegendContentProps) { const { config } = useChart() if (!payload?.length) { @@ -258,14 +272,14 @@ function ChartLegendContent( )} > {payload - ?.filter((item: any) => item.type !== 'none') - .map((item: any) => { - const key = `${nameKey || item.dataKey || 'value'}` + .filter((item) => item.type !== 'none') + .map((item, index) => { + const key = `${nameKey ?? item.dataKey ?? 'value'}` const itemConfig = getPayloadConfigFromPayload(config, item, key) return (
    svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground', )} @@ -310,7 +324,7 @@ function getPayloadConfigFromPayload(config: ChartConfig, payload: unknown, key: configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string } - return configLabelKey in config ? config[configLabelKey] : config[key as keyof typeof config] + return configLabelKey in config ? config[configLabelKey] : config[key] } export { diff --git a/frontend/src/components/ui/checkbox.tsx b/frontend/src/components/ui/checkbox.tsx index 296d2ae..f4850f9 100644 --- a/frontend/src/components/ui/checkbox.tsx +++ b/frontend/src/components/ui/checkbox.tsx @@ -1,5 +1,3 @@ -'use client' - import { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox' import { Tick02Icon } from '@hugeicons/core-free-icons' import { HugeiconsIcon } from '@hugeicons/react' diff --git a/frontend/src/components/ui/combobox.tsx b/frontend/src/components/ui/combobox.tsx index be03555..b03946b 100644 --- a/frontend/src/components/ui/combobox.tsx +++ b/frontend/src/components/ui/combobox.tsx @@ -18,11 +18,17 @@ function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) { return } -function ComboboxTrigger({ className, children, ...props }: ComboboxPrimitive.Trigger.Props) { +function ComboboxTrigger({ + className, + children, + nativeButton, + ...props +}: ComboboxPrimitive.Trigger.Props) { return ( {children} diff --git a/frontend/src/components/ui/command.tsx b/frontend/src/components/ui/command.tsx index 431ff66..98cf811 100644 --- a/frontend/src/components/ui/command.tsx +++ b/frontend/src/components/ui/command.tsx @@ -1,5 +1,3 @@ -'use client' - import { SearchIcon, Tick02Icon } from '@hugeicons/core-free-icons' import { HugeiconsIcon } from '@hugeicons/react' import { Command as CommandPrimitive } from 'cmdk' diff --git a/frontend/src/components/ui/context-menu.tsx b/frontend/src/components/ui/context-menu.tsx index 1045de1..bc0ed61 100644 --- a/frontend/src/components/ui/context-menu.tsx +++ b/frontend/src/components/ui/context-menu.tsx @@ -1,5 +1,3 @@ -'use client' - import { ContextMenu as ContextMenuPrimitive } from '@base-ui/react/context-menu' import { ArrowRight01Icon, Tick02Icon } from '@hugeicons/core-free-icons' import { HugeiconsIcon } from '@hugeicons/react' @@ -186,7 +184,7 @@ function ContextMenuRadioItem({ data-slot='context-menu-radio-item' data-inset={inset} className={cn( - "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-9.5 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + "relative flex cursor-default items-center gap-2 rounded-xl py-2 pr-8 pl-3 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-9.5 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className, )} {...props} diff --git a/frontend/src/components/ui/dialog.tsx b/frontend/src/components/ui/dialog.tsx index fc6dae4..aa800d3 100644 --- a/frontend/src/components/ui/dialog.tsx +++ b/frontend/src/components/ui/dialog.tsx @@ -10,16 +10,28 @@ function Dialog({ ...props }: DialogPrimitive.Root.Props) { return } -function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) { - return +function DialogTrigger({ nativeButton, ...props }: DialogPrimitive.Trigger.Props) { + return ( + + ) } function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) { return } -function DialogClose({ ...props }: DialogPrimitive.Close.Props) { - return +function DialogClose({ nativeButton, ...props }: DialogPrimitive.Close.Props) { + return ( + + ) } function DialogOverlay({ className, ...props }: DialogPrimitive.Backdrop.Props) { @@ -49,7 +61,7 @@ function DialogContent({ } -function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) { - return +function DropdownMenuTrigger({ nativeButton, ...props }: MenuPrimitive.Trigger.Props) { + return ( + + ) } function DropdownMenuContent({ @@ -40,7 +44,7 @@ function DropdownMenuContent({ ) { +function Label({ className, ...props }: React.ComponentProps<'label'>) { return ( /* eslint-disable-next-line jsx-a11y/label-has-associated-control */ + /> ) } diff --git a/frontend/src/components/ui/menubar.tsx b/frontend/src/components/ui/menubar.tsx index 1db35e8..13b72b3 100644 --- a/frontend/src/components/ui/menubar.tsx +++ b/frontend/src/components/ui/menubar.tsx @@ -1,5 +1,3 @@ -'use client' - import { Menu as MenuPrimitive } from '@base-ui/react/menu' import { Menubar as MenubarPrimitive } from '@base-ui/react/menubar' import { Tick02Icon } from '@hugeicons/core-free-icons' @@ -27,7 +25,7 @@ function Menubar({ className, ...props }: MenubarPrimitive.Props) { return ( ) @@ -50,7 +48,7 @@ function MenubarTrigger({ className, ...props }: React.ComponentProps, 'size'> & { + size?: 'sm' | 'default' +} + +function NativeSelect({ className, size = 'default', ...props }: NativeSelectProps) { + return ( +
    +
    ) } - -export default NotFoundPage diff --git a/frontend/src/routes/_status/500.tsx b/frontend/src/routes/_status/500.tsx index 4ffea21..7c26b70 100644 --- a/frontend/src/routes/_status/500.tsx +++ b/frontend/src/routes/_status/500.tsx @@ -1,7 +1,12 @@ +import { + Alert01Icon as AlertTriangle, + Home01Icon as Home, + RefreshIcon as RefreshCcw, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { AlertTriangle, Home, RefreshCcw } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' @@ -18,7 +23,7 @@ function InternalServerErrorPage() { variant='error' icon={
    - +
    } title='500 - Internal Server Error' @@ -26,18 +31,18 @@ function InternalServerErrorPage() { footer={ <> } > - + Error Details Our team has been notified and is investigating the issue. Please try again in a few @@ -47,5 +52,3 @@ function InternalServerErrorPage() { ) } - -export default InternalServerErrorPage diff --git a/frontend/src/routes/_status/503.tsx b/frontend/src/routes/_status/503.tsx index 84c8ecb..048cc85 100644 --- a/frontend/src/routes/_status/503.tsx +++ b/frontend/src/routes/_status/503.tsx @@ -1,7 +1,12 @@ +import { + Clock01Icon as Clock, + Home01Icon as Home, + CloudServerIcon as ServerOff, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Clock, Home, ServerOff } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Progress, ProgressLabel } from '@/components/ui/progress' @@ -19,7 +24,7 @@ function ServiceUnavailablePage() { variant='warning' icon={
    - +
    } title='503 - Service Unavailable' @@ -28,7 +33,7 @@ function ServiceUnavailablePage() { <> @@ -38,7 +43,7 @@ function ServiceUnavailablePage() {
    Status - + Recovering
    @@ -50,5 +55,3 @@ function ServiceUnavailablePage() { ) } - -export default ServiceUnavailablePage diff --git a/frontend/src/routes/_status/api-key-created.tsx b/frontend/src/routes/_status/api-key-created.tsx index 1fdad90..b2df098 100644 --- a/frontend/src/routes/_status/api-key-created.tsx +++ b/frontend/src/routes/_status/api-key-created.tsx @@ -1,7 +1,8 @@ +import { AlertCircleIcon, Copy01Icon, Home01Icon, Key01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { AlertTriangle, Copy, Home, Key } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -21,7 +22,7 @@ function ApiKeyCreatedPage() { variant='success' icon={
    - +
    } title='API Key Created' @@ -30,7 +31,7 @@ function ApiKeyCreatedPage() { <> @@ -38,7 +39,7 @@ function ApiKeyCreatedPage() { >
    - + Save This Key Now This is the only time you'll see this key. Copy it and store it securely. @@ -55,7 +56,7 @@ function ApiKeyCreatedPage() { className='absolute right-2 top-1/2 -translate-y-1/2' onClick={() => navigator.clipboard.writeText(apiKey)} > - +
    @@ -68,5 +69,3 @@ function ApiKeyCreatedPage() { ) } - -export default ApiKeyCreatedPage diff --git a/frontend/src/routes/_status/backup-complete.tsx b/frontend/src/routes/_status/backup-complete.tsx index c12ad4e..45e6ee5 100644 --- a/frontend/src/routes/_status/backup-complete.tsx +++ b/frontend/src/routes/_status/backup-complete.tsx @@ -1,7 +1,13 @@ +import { + Ticket02Icon as Check, + Database01Icon as Database, + Download01Icon as Download, + Home01Icon as Home, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Check, Database, Download, Home } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -19,7 +25,7 @@ function BackupCompletePage() { variant='success' icon={
    - +
    } title='Backup Complete' @@ -27,11 +33,11 @@ function BackupCompletePage() { footer={ <> @@ -40,7 +46,7 @@ function BackupCompletePage() {
    - + Verified
    @@ -69,5 +75,3 @@ function BackupCompletePage() { ) } - -export default BackupCompletePage diff --git a/frontend/src/routes/_status/bad-gateway.tsx b/frontend/src/routes/_status/bad-gateway.tsx index 74ea225..73fe53e 100644 --- a/frontend/src/routes/_status/bad-gateway.tsx +++ b/frontend/src/routes/_status/bad-gateway.tsx @@ -1,7 +1,12 @@ +import { + Home01Icon as Home, + StructureIcon as Network, + RefreshIcon as RefreshCcw, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Home, Network, RefreshCcw } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' @@ -18,7 +23,7 @@ function BadGatewayPage() { variant='error' icon={
    - +
    } title='502 - Bad Gateway' @@ -26,18 +31,18 @@ function BadGatewayPage() { footer={ <> } > - + Gateway Error Our servers are having trouble communicating. This is usually temporary. Please try again. @@ -46,5 +51,3 @@ function BadGatewayPage() { ) } - -export default BadGatewayPage diff --git a/frontend/src/routes/_status/bad-request.tsx b/frontend/src/routes/_status/bad-request.tsx index 05b5105..af2f4ea 100644 --- a/frontend/src/routes/_status/bad-request.tsx +++ b/frontend/src/routes/_status/bad-request.tsx @@ -1,7 +1,12 @@ +import { + Alert01Icon as AlertCircle, + FileQuestionMarkIcon as FileWarning, + Home01Icon as Home, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { AlertCircle, FileWarning, Home } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' @@ -18,7 +23,7 @@ function BadRequestPage() { variant='error' icon={
    - +
    } title='400 - Bad Request' @@ -26,7 +31,7 @@ function BadRequestPage() { footer={ <> @@ -70,5 +71,3 @@ function BandwidthExceededPage() { ) } - -export default BandwidthExceededPage diff --git a/frontend/src/routes/_status/cancelled.tsx b/frontend/src/routes/_status/cancelled.tsx index c145bd0..4a7485a 100644 --- a/frontend/src/routes/_status/cancelled.tsx +++ b/frontend/src/routes/_status/cancelled.tsx @@ -1,7 +1,12 @@ +import { + Cancel01Icon as Ban, + Home01Icon as Home, + RefreshIcon as RefreshCcw, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Ban, Home, RefreshCcw } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' @@ -18,7 +23,7 @@ function CancelledPage() { variant='default' icon={
    - +
    } title='Action Cancelled' @@ -26,18 +31,18 @@ function CancelledPage() { footer={ <> } > - + No Changes Made Your data remains unchanged. You can safely navigate away or try again. @@ -46,5 +51,3 @@ function CancelledPage() { ) } - -export default CancelledPage diff --git a/frontend/src/routes/_status/coming-soon.tsx b/frontend/src/routes/_status/coming-soon.tsx index 9c43e05..f656e63 100644 --- a/frontend/src/routes/_status/coming-soon.tsx +++ b/frontend/src/routes/_status/coming-soon.tsx @@ -1,7 +1,13 @@ +import { + Notification01Icon, + Home01Icon, + RocketIcon, + SparklesIcon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Bell, Home, Rocket, Sparkles } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Separator } from '@/components/ui/separator' @@ -19,21 +25,21 @@ function ComingSoonPage() { variant='info' icon={
    - +
    } title='Coming Soon' description="We're working on something exciting. Stay tuned!" footer={ } >
    - + New features launching soon
    @@ -44,7 +50,7 @@ function ComingSoonPage() {
    @@ -69,5 +75,3 @@ function ComingSoonPage() { ) } - -export default ComingSoonPage diff --git a/frontend/src/routes/_status/conflict.tsx b/frontend/src/routes/_status/conflict.tsx index 1be703e..ed48616 100644 --- a/frontend/src/routes/_status/conflict.tsx +++ b/frontend/src/routes/_status/conflict.tsx @@ -1,7 +1,8 @@ +import { GitMergeIcon, Home01Icon, RefreshIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { GitMerge, Home, RefreshCcw } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' @@ -18,7 +19,7 @@ function ConflictPage() { variant='warning' icon={
    - +
    } title='409 - Conflict' @@ -26,18 +27,18 @@ function ConflictPage() { footer={ <> } > - + Resource Conflict This usually happens when the resource was modified by another request. Please refresh and @@ -47,5 +48,3 @@ function ConflictPage() { ) } - -export default ConflictPage diff --git a/frontend/src/routes/_status/deleted.tsx b/frontend/src/routes/_status/deleted.tsx index ac60cc1..9d2d668 100644 --- a/frontend/src/routes/_status/deleted.tsx +++ b/frontend/src/routes/_status/deleted.tsx @@ -1,7 +1,8 @@ +import { Home01Icon, Delete02Icon, Undo02Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Home, Trash2, Undo2 } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -19,7 +20,7 @@ function DeletedPage() { variant='default' icon={
    - +
    } title='Account Deleted' @@ -30,7 +31,7 @@ function DeletedPage() { Create New Account @@ -38,7 +39,7 @@ function DeletedPage() { >
    - + 30-Day Recovery Period You can recover your account within 30 days by contacting support. @@ -59,5 +60,3 @@ function DeletedPage() { ) } - -export default DeletedPage diff --git a/frontend/src/routes/_status/device-verified.tsx b/frontend/src/routes/_status/device-verified.tsx index 501b9ff..caceb02 100644 --- a/frontend/src/routes/_status/device-verified.tsx +++ b/frontend/src/routes/_status/device-verified.tsx @@ -1,7 +1,8 @@ +import { Tick02Icon, LaptopIcon, Monitor, SmartPhone01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Check, Laptop, Monitor, Smartphone } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -19,7 +20,7 @@ function DeviceVerifiedPage() { variant='success' icon={
    - +
    } title='Device Verified' @@ -29,14 +30,14 @@ function DeviceVerifiedPage() {
    - + Trusted
    - +

    Chrome on Linux

    Added just now

    @@ -50,15 +51,15 @@ function DeviceVerifiedPage() {

    Your trusted devices:

    - + 2
    - + 1
    - + 1
    @@ -71,5 +72,3 @@ function DeviceVerifiedPage() { ) } - -export default DeviceVerifiedPage diff --git a/frontend/src/routes/_status/downgrade.tsx b/frontend/src/routes/_status/downgrade.tsx index b9f5c43..df339eb 100644 --- a/frontend/src/routes/_status/downgrade.tsx +++ b/frontend/src/routes/_status/downgrade.tsx @@ -1,7 +1,14 @@ +import { + Alert01Icon, + ArrowDown01Icon, + Tick02Icon, + Home01Icon, + Cancel01Icon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { AlertTriangle, ArrowDown, Check, Home, X } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -19,7 +26,7 @@ function DowngradePage() { variant='warning' icon={
    - +
    } title='Plan Downgraded' @@ -28,7 +35,7 @@ function DowngradePage() { <> @@ -36,7 +43,7 @@ function DowngradePage() { >
    - + Features Removed Some features are no longer available on your current plan. @@ -49,15 +56,15 @@ function DowngradePage() {

    What you've lost:

    • - + Unlimited API calls
    • - + Priority support
    • - + Team collaboration
    @@ -67,15 +74,15 @@ function DowngradePage() {

    What you still have:

    • - + 1,000 API calls/month
    • - + Basic analytics
    • - + Email support
    @@ -84,5 +91,3 @@ function DowngradePage() { ) } - -export default DowngradePage diff --git a/frontend/src/routes/_status/email-sent.tsx b/frontend/src/routes/_status/email-sent.tsx index 862f6d5..7e04d51 100644 --- a/frontend/src/routes/_status/email-sent.tsx +++ b/frontend/src/routes/_status/email-sent.tsx @@ -1,7 +1,8 @@ +import { Home01Icon, Mail01Icon, RefreshIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Home, Mail, RefreshCcw } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -18,7 +19,7 @@ function EmailSentPage() { variant='success' icon={
    - +
    } title='Email Sent' @@ -26,11 +27,11 @@ function EmailSentPage() { footer={ <> @@ -55,5 +56,3 @@ function EmailSentPage() { ) } - -export default EmailSentPage diff --git a/frontend/src/routes/_status/empty-state.tsx b/frontend/src/routes/_status/empty-state.tsx index 4a82876..e9407c9 100644 --- a/frontend/src/routes/_status/empty-state.tsx +++ b/frontend/src/routes/_status/empty-state.tsx @@ -1,7 +1,8 @@ +import { Folder01Icon, Home01Icon, PlusSignIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { FolderOpen, Home, Plus } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -18,7 +19,7 @@ function EmptyStatePage() { variant='default' icon={
    - +
    } title='No Items Yet' @@ -26,11 +27,11 @@ function EmptyStatePage() { footer={ <> @@ -45,5 +46,3 @@ function EmptyStatePage() { ) } - -export default EmptyStatePage diff --git a/frontend/src/routes/_status/error-demo.tsx b/frontend/src/routes/_status/error-demo.tsx index a2ceb78..377700a 100644 --- a/frontend/src/routes/_status/error-demo.tsx +++ b/frontend/src/routes/_status/error-demo.tsx @@ -1,5 +1,12 @@ +import { + AlertCircleIcon, + BugIcon, + FileQuestionMarkIcon, + SecurityBlockIcon, + Structure01Icon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { AlertOctagon, AlertTriangle, Bug, FileQuestion, Network, ShieldOff } from 'lucide-react' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' @@ -16,98 +23,98 @@ const errorPages = [ { code: '400', name: 'Bad Request', - icon: AlertTriangle, + icon: AlertCircleIcon, path: '/bad-request', color: 'text-yellow-500', }, { code: '401', name: 'Unauthorized', - icon: ShieldOff, + icon: SecurityBlockIcon, path: '/401', color: 'text-yellow-500', }, { code: '403', name: 'Forbidden', - icon: ShieldOff, + icon: SecurityBlockIcon, path: '/403', color: 'text-destructive', }, { code: '404', name: 'Not Found', - icon: FileQuestion, + icon: FileQuestionMarkIcon, path: '/404', color: 'text-destructive', }, { code: '408', name: 'Timeout', - icon: AlertTriangle, + icon: AlertCircleIcon, path: '/timeout', color: 'text-yellow-500', }, { code: '409', name: 'Conflict', - icon: AlertTriangle, + icon: AlertCircleIcon, path: '/conflict', color: 'text-yellow-500', }, { code: '410', name: 'Gone', - icon: FileQuestion, + icon: FileQuestionMarkIcon, path: '/gone', color: 'text-muted-foreground', }, { code: '415', name: 'Unsupported Media', - icon: AlertTriangle, + icon: AlertCircleIcon, path: '/unsupported-media', color: 'text-destructive', }, { code: '423', name: 'Locked', - icon: ShieldOff, + icon: SecurityBlockIcon, path: '/locked', color: 'text-destructive', }, { code: '429', name: 'Rate Limited', - icon: AlertTriangle, + icon: AlertCircleIcon, path: '/rate-limited', color: 'text-yellow-500', }, { code: '500', name: 'Server Error', - icon: AlertOctagon, + icon: AlertCircleIcon, path: '/500', color: 'text-destructive', }, { code: '502', name: 'Bad Gateway', - icon: Network, + icon: Structure01Icon, path: '/bad-gateway', color: 'text-destructive', }, { code: '503', name: 'Unavailable', - icon: Network, + icon: Structure01Icon, path: '/503', color: 'text-yellow-500', }, { code: '504', name: 'Gateway Timeout', - icon: Network, + icon: Structure01Icon, path: '/gateway-timeout', color: 'text-destructive', }, @@ -120,7 +127,7 @@ function ErrorDemoPage() {
    - +
    Error States @@ -145,7 +152,7 @@ function ErrorDemoPage() { to={error.path} className='flex items-center gap-3 p-3 rounded-lg border hover:bg-muted/50 transition-colors' > - +
    {error.code}
    {error.name}
    @@ -263,5 +270,3 @@ export const Route = createFileRoute('/my-route')({
    ) } - -export default ErrorDemoPage diff --git a/frontend/src/routes/_status/error.tsx b/frontend/src/routes/_status/error.tsx index 78d5b13..9c77806 100644 --- a/frontend/src/routes/_status/error.tsx +++ b/frontend/src/routes/_status/error.tsx @@ -1,7 +1,8 @@ +import { AlertCircleIcon, Bug01Icon, Home01Icon, RefreshIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { AlertOctagon, Bug, Home, RefreshCcw } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Accordion, AccordionContent, @@ -24,7 +25,7 @@ function GenericErrorPage() { variant='error' icon={
    - +
    } title='Something Went Wrong' @@ -32,11 +33,11 @@ function GenericErrorPage() { footer={ <> @@ -44,7 +45,7 @@ function GenericErrorPage() { >
    - + Error Code: E_UNKNOWN This error has been logged and our team will investigate. @@ -72,5 +73,3 @@ function GenericErrorPage() { ) } - -export default GenericErrorPage diff --git a/frontend/src/routes/_status/export-ready.tsx b/frontend/src/routes/_status/export-ready.tsx index 5a6e2d9..62de563 100644 --- a/frontend/src/routes/_status/export-ready.tsx +++ b/frontend/src/routes/_status/export-ready.tsx @@ -1,7 +1,8 @@ +import { Download01Icon, FileDownloadIcon, Home01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Download, FileDown, Home } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -19,7 +20,7 @@ function ExportReadyPage() { variant='success' icon={
    - +
    } title='Export Ready' @@ -27,11 +28,11 @@ function ExportReadyPage() { footer={ <> @@ -66,5 +67,3 @@ function ExportReadyPage() { ) } - -export default ExportReadyPage diff --git a/frontend/src/routes/_status/gateway-timeout.tsx b/frontend/src/routes/_status/gateway-timeout.tsx index f48335a..822e8f8 100644 --- a/frontend/src/routes/_status/gateway-timeout.tsx +++ b/frontend/src/routes/_status/gateway-timeout.tsx @@ -1,7 +1,8 @@ +import { Clock01Icon, Home01Icon, RefreshIcon, CloudServerIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Clock, Home, RefreshCcw, ServerCrash } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' @@ -18,7 +19,7 @@ function GatewayTimeoutPage() { variant='error' icon={
    - +
    } title='504 - Gateway Timeout' @@ -26,18 +27,18 @@ function GatewayTimeoutPage() { footer={ <> } > - + Server Timeout The server is taking longer than expected to respond. This could be due to high traffic or @@ -47,5 +48,3 @@ function GatewayTimeoutPage() { ) } - -export default GatewayTimeoutPage diff --git a/frontend/src/routes/_status/gone.tsx b/frontend/src/routes/_status/gone.tsx index 5dd9a78..ae75dcd 100644 --- a/frontend/src/routes/_status/gone.tsx +++ b/frontend/src/routes/_status/gone.tsx @@ -1,7 +1,8 @@ +import { AlertCircleIcon, Home01Icon, Search01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Ghost, Home, Search } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Separator } from '@/components/ui/separator' @@ -19,14 +20,14 @@ function GonePage() { variant='error' icon={
    - +
    } title='410 - Gone' description='This resource has been permanently removed.' footer={ } @@ -45,7 +46,7 @@ function GonePage() {
    @@ -53,5 +54,3 @@ function GonePage() { ) } - -export default GonePage diff --git a/frontend/src/routes/_status/import-complete.tsx b/frontend/src/routes/_status/import-complete.tsx index 9d0843c..371bbb4 100644 --- a/frontend/src/routes/_status/import-complete.tsx +++ b/frontend/src/routes/_status/import-complete.tsx @@ -1,7 +1,8 @@ +import { ArrowRight01Icon, Home01Icon, Tick01Icon, Upload02Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { ArrowRight, Check, FileUp, Home } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Progress, ProgressLabel, ProgressValue } from '@/components/ui/progress' @@ -20,7 +21,7 @@ function ImportCompletePage() { variant='success' icon={
    - +
    } title='Import Complete' @@ -29,10 +30,10 @@ function ImportCompletePage() { <> @@ -41,7 +42,7 @@ function ImportCompletePage() {
    - + Success
    @@ -71,5 +72,3 @@ function ImportCompletePage() { ) } - -export default ImportCompletePage diff --git a/frontend/src/routes/_status/info-states.tsx b/frontend/src/routes/_status/info-states.tsx index e77cb36..2b01ce3 100644 --- a/frontend/src/routes/_status/info-states.tsx +++ b/frontend/src/routes/_status/info-states.tsx @@ -1,17 +1,18 @@ -import { createFileRoute, Link } from '@tanstack/react-router' import { - Bell, - Clock, - Construction, - FolderOpen, - HardHat, - Info, - ListOrdered, - Mail, - Rocket, - Search, - Users, -} from 'lucide-react' + Clock01Icon, + ConstructionIcon, + FolderOpenIcon, + Information, + Mail01Icon, + Menu01Icon, + Notification01Icon, + RocketIcon, + Search01Icon, + SecurityIcon, + UserGroupIcon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' +import { createFileRoute, Link } from '@tanstack/react-router' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' @@ -24,28 +25,33 @@ export const Route = createFileRoute('/_status/info-states')({ }) const infoPages = [ - { name: 'Coming Soon', icon: Rocket, path: '/coming-soon', color: 'text-blue-500' }, - { name: 'Maintenance', icon: Construction, path: '/maintenance', color: 'text-blue-500' }, + { name: 'Coming Soon', icon: RocketIcon, path: '/coming-soon', color: 'text-blue-500' }, + { name: 'Maintenance', icon: ConstructionIcon, path: '/maintenance', color: 'text-blue-500' }, { name: 'Under Construction', - icon: HardHat, + icon: SecurityIcon, path: '/under-construction', color: 'text-blue-500', }, - { name: 'Verify Email', icon: Mail, path: '/verify-email', color: 'text-blue-500' }, - { name: 'Login Required', icon: Users, path: '/login-required', color: 'text-blue-500' }, - { name: '2FA Required', icon: Clock, path: '/2fa-required', color: 'text-blue-500' }, - { name: 'Team Invitation', icon: Users, path: '/invitation', color: 'text-blue-500' }, - { name: 'Processing', icon: Clock, path: '/processing', color: 'text-blue-500' }, - { name: 'Queued', icon: ListOrdered, path: '/queued', color: 'text-blue-500' }, + { name: 'Verify Email', icon: Mail01Icon, path: '/verify-email', color: 'text-blue-500' }, + { name: 'Login Required', icon: UserGroupIcon, path: '/login-required', color: 'text-blue-500' }, + { name: '2FA Required', icon: Clock01Icon, path: '/2fa-required', color: 'text-blue-500' }, + { name: 'Team Invitation', icon: UserGroupIcon, path: '/invitation', color: 'text-blue-500' }, + { name: 'Processing', icon: Clock01Icon, path: '/processing', color: 'text-blue-500' }, + { name: 'Queued', icon: Menu01Icon, path: '/queued', color: 'text-blue-500' }, { name: 'Empty State', - icon: FolderOpen, + icon: FolderOpenIcon, path: '/empty-state', color: 'text-muted-foreground', }, - { name: 'No Results', icon: Search, path: '/no-results', color: 'text-muted-foreground' }, - { name: 'Cancelled', icon: Info, path: '/cancelled', color: 'text-muted-foreground' }, + { name: 'No Results', icon: Search01Icon, path: '/no-results', color: 'text-muted-foreground' }, + { + name: 'Cancelled', + icon: Information, + path: '/cancelled', + color: 'text-muted-foreground', + }, ] function InfoStatesPage() { @@ -55,7 +61,7 @@ function InfoStatesPage() {
    - +
    Informational States @@ -81,7 +87,7 @@ function InfoStatesPage() { className='flex items-center gap-3 p-3 rounded-lg border hover:bg-muted/50 transition-colors' >
    - +
    {page.name}
    @@ -156,5 +162,3 @@ function InfoStatesPage() {
    ) } - -export default InfoStatesPage diff --git a/frontend/src/routes/_status/invitation.tsx b/frontend/src/routes/_status/invitation.tsx index 1897793..dcb8801 100644 --- a/frontend/src/routes/_status/invitation.tsx +++ b/frontend/src/routes/_status/invitation.tsx @@ -1,7 +1,14 @@ +import { + Cancel01Icon, + Home01Icon, + Mail01Icon, + Tick01Icon, + UserGroupIcon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Check, Home, Mail, Users, X } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' @@ -20,7 +27,7 @@ function InvitationPage() { variant='info' icon={
    - +
    } title="You're Invited!" @@ -28,11 +35,11 @@ function InvitationPage() { footer={ <> @@ -44,7 +51,7 @@ function InvitationPage() {
    Acme Corp - + Team
    @@ -63,7 +70,7 @@ function InvitationPage() {
    @@ -71,5 +78,3 @@ function InvitationPage() { ) } - -export default InvitationPage diff --git a/frontend/src/routes/_status/loading.tsx b/frontend/src/routes/_status/loading.tsx index a07c27c..d5f1656 100644 --- a/frontend/src/routes/_status/loading.tsx +++ b/frontend/src/routes/_status/loading.tsx @@ -1,5 +1,6 @@ +import { Loading01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute } from '@tanstack/react-router' -import { Loader2 } from 'lucide-react' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' @@ -23,7 +24,7 @@ function LoadingDemoPage() {
    - +
    Loading States @@ -62,7 +63,7 @@ function LoadingDemoPage() {
    - +
    Loading @@ -144,5 +145,3 @@ export const Route = createFileRoute('/my-route')({
    ) } - -export default LoadingDemoPage diff --git a/frontend/src/routes/_status/locked.tsx b/frontend/src/routes/_status/locked.tsx index a7b70c9..ad86187 100644 --- a/frontend/src/routes/_status/locked.tsx +++ b/frontend/src/routes/_status/locked.tsx @@ -1,7 +1,8 @@ +import { Home01Icon, LockIcon, Mail01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Home, Lock, Mail } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' @@ -18,7 +19,7 @@ function LockedPage() { variant='error' icon={
    - +
    } title='423 - Account Locked' @@ -26,18 +27,18 @@ function LockedPage() { footer={ <> } > - + Account Security This may be due to multiple failed login attempts or suspicious activity. Please contact @@ -47,5 +48,3 @@ function LockedPage() { ) } - -export default LockedPage diff --git a/frontend/src/routes/_status/login-required.tsx b/frontend/src/routes/_status/login-required.tsx index 5605054..d171584 100644 --- a/frontend/src/routes/_status/login-required.tsx +++ b/frontend/src/routes/_status/login-required.tsx @@ -1,7 +1,8 @@ +import { Home01Icon, Login01Icon, UserCircleIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Home, LogIn, UserCircle } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -18,7 +19,7 @@ function LoginRequiredPage() { variant='info' icon={
    - +
    } title='Login Required' @@ -26,11 +27,11 @@ function LoginRequiredPage() { footer={ <> @@ -51,5 +52,3 @@ function LoginRequiredPage() { ) } - -export default LoginRequiredPage diff --git a/frontend/src/routes/_status/maintenance.tsx b/frontend/src/routes/_status/maintenance.tsx index fe92159..7e8bf7f 100644 --- a/frontend/src/routes/_status/maintenance.tsx +++ b/frontend/src/routes/_status/maintenance.tsx @@ -1,7 +1,8 @@ +import { Clock01Icon, ConstructionIcon, Home01Icon, WrenchIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Clock, Construction, Home, Wrench } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Progress, ProgressLabel, ProgressValue } from '@/components/ui/progress' @@ -20,7 +21,7 @@ function MaintenancePage() { variant='info' icon={
    - +
    } title='Scheduled Maintenance' @@ -28,7 +29,7 @@ function MaintenancePage() { footer={ <> } @@ -35,7 +36,7 @@ function NoResultsPage() {
    @@ -54,5 +55,3 @@ function NoResultsPage() { ) } - -export default NoResultsPage diff --git a/frontend/src/routes/_status/offline.tsx b/frontend/src/routes/_status/offline.tsx index e9dbefa..bc862e3 100644 --- a/frontend/src/routes/_status/offline.tsx +++ b/frontend/src/routes/_status/offline.tsx @@ -1,7 +1,8 @@ +import { RefreshIcon, WifiOffIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute } from '@tanstack/react-router' -import { RefreshCcw, WifiOff } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' @@ -18,21 +19,21 @@ function OfflinePage() { variant='warning' icon={
    - +
    } title="You're Offline" description="It looks like you've lost your internet connection." footer={ } >
    - + No Internet Connection Please check your network settings and try again. @@ -50,5 +51,3 @@ function OfflinePage() { ) } - -export default OfflinePage diff --git a/frontend/src/routes/_status/password-changed.tsx b/frontend/src/routes/_status/password-changed.tsx index 76daea8..cc1c0fd 100644 --- a/frontend/src/routes/_status/password-changed.tsx +++ b/frontend/src/routes/_status/password-changed.tsx @@ -1,7 +1,8 @@ +import { Home01Icon, Key01Icon, Login01Icon, Tick01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Check, Home, KeyRound, LogIn } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' @@ -19,7 +20,7 @@ function PasswordChangedPage() { variant='success' icon={
    - +
    } title='Password Changed' @@ -27,11 +28,11 @@ function PasswordChangedPage() { footer={ <> @@ -40,13 +41,13 @@ function PasswordChangedPage() {
    - + Secured
    - + Security Notice You've been logged out of all devices for security. Please sign in with your new @@ -57,5 +58,3 @@ function PasswordChangedPage() { ) } - -export default PasswordChangedPage diff --git a/frontend/src/routes/_status/payment-required.tsx b/frontend/src/routes/_status/payment-required.tsx index 077d76b..c5d9aa4 100644 --- a/frontend/src/routes/_status/payment-required.tsx +++ b/frontend/src/routes/_status/payment-required.tsx @@ -1,7 +1,8 @@ +import { CreditCardIcon, Home01Icon, SparklesIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { CreditCard, Home, Sparkles } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' @@ -20,7 +21,7 @@ function PaymentRequiredPage() { variant='warning' icon={
    - +
    } title='402 - Payment Required' @@ -28,11 +29,11 @@ function PaymentRequiredPage() { footer={ <> @@ -69,5 +70,3 @@ function PaymentRequiredPage() { ) } - -export default PaymentRequiredPage diff --git a/frontend/src/routes/_status/processing.tsx b/frontend/src/routes/_status/processing.tsx index 41aa95f..77833c4 100644 --- a/frontend/src/routes/_status/processing.tsx +++ b/frontend/src/routes/_status/processing.tsx @@ -1,7 +1,8 @@ +import { Clock01Icon, Home01Icon, Settings01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Clock, Cog, Home } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Progress, ProgressLabel, ProgressValue } from '@/components/ui/progress' @@ -22,14 +23,18 @@ function ProcessingPage() { variant='info' icon={
    - +
    } title='Processing...' description='Your request is being processed. Please wait.' footer={ } @@ -38,7 +43,7 @@ function ProcessingPage() {
    - + In Progress
    @@ -70,5 +75,3 @@ function ProcessingPage() { ) } - -export default ProcessingPage diff --git a/frontend/src/routes/_status/queued.tsx b/frontend/src/routes/_status/queued.tsx index bd428aa..4b91c48 100644 --- a/frontend/src/routes/_status/queued.tsx +++ b/frontend/src/routes/_status/queued.tsx @@ -1,7 +1,13 @@ +import { + Clock01Icon, + Home01Icon, + WorkflowSquare01Icon as ListOrdered, + UserGroupIcon as Users, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Clock, Home, ListOrdered, Users } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Progress, ProgressLabel, ProgressValue } from '@/components/ui/progress' @@ -20,14 +26,14 @@ function QueuedPage() { variant='info' icon={
    - +
    } title='Request Queued' description='Your request has been added to the processing queue.' footer={ } @@ -35,7 +41,7 @@ function QueuedPage() {
    - + Waiting
    @@ -53,7 +59,7 @@ function QueuedPage() {
    - + 47 requests processed in the last hour
    @@ -64,5 +70,3 @@ function QueuedPage() { ) } - -export default QueuedPage diff --git a/frontend/src/routes/_status/rate-limited.tsx b/frontend/src/routes/_status/rate-limited.tsx index 480a07b..9e7ee6a 100644 --- a/frontend/src/routes/_status/rate-limited.tsx +++ b/frontend/src/routes/_status/rate-limited.tsx @@ -1,7 +1,13 @@ +import { + Clock01Icon, + DashboardCircleIcon as Gauge, + Home01Icon, + TimerIcon as Timer, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Clock, Gauge, Home, Timer } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Progress, ProgressLabel, ProgressValue } from '@/components/ui/progress' @@ -20,7 +26,7 @@ function RateLimitedPage() { variant='warning' icon={
    - +
    } title='429 - Too Many Requests' @@ -28,11 +34,11 @@ function RateLimitedPage() { footer={ <> @@ -41,7 +47,7 @@ function RateLimitedPage() {
    - + Cooldown Active
    @@ -80,5 +86,3 @@ function RateLimitedPage() { ) } - -export default RateLimitedPage diff --git a/frontend/src/routes/_status/session-expired.tsx b/frontend/src/routes/_status/session-expired.tsx index 4a03551..a0f1e5c 100644 --- a/frontend/src/routes/_status/session-expired.tsx +++ b/frontend/src/routes/_status/session-expired.tsx @@ -1,7 +1,8 @@ +import { Clock01Icon, Home01Icon, Login01Icon, TimerIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Clock, Home, LogIn, TimerOff } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' @@ -18,7 +19,7 @@ function SessionExpiredPage() { variant='warning' icon={
    - +
    } title='Session Expired' @@ -26,18 +27,18 @@ function SessionExpiredPage() { footer={ <> } > - + Security Notice For your security, sessions automatically expire after 30 minutes of inactivity. @@ -46,5 +47,3 @@ function SessionExpiredPage() { ) } - -export default SessionExpiredPage diff --git a/frontend/src/routes/_status/status.tsx b/frontend/src/routes/_status/status.tsx index 27800d7..be33102 100644 --- a/frontend/src/routes/_status/status.tsx +++ b/frontend/src/routes/_status/status.tsx @@ -1,18 +1,19 @@ -import { createFileRoute, Link } from '@tanstack/react-router' import { - Activity, - AlertTriangle, - Bell, - CheckCircle2, - Clock, - Database, - Globe, - Loader2, - PartyPopper, - Server, - Shield, - Zap, -} from 'lucide-react' + ActivityIcon, + Alert01Icon, + Notification01Icon, + Tick02Icon, + Clock01Icon, + Database01Icon, + InternetIcon, + Loading01Icon, + SparklesIcon, + CloudServerIcon as Server, + Shield01Icon, + ZapIcon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' +import { createFileRoute, Link } from '@tanstack/react-router' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' @@ -39,42 +40,42 @@ const services: ServiceStatus[] = [ { name: 'API Gateway', status: 'operational', - icon: , + icon: , uptime: 99.99, responseTime: 45, }, { name: 'Database', status: 'operational', - icon: , + icon: , uptime: 99.95, responseTime: 12, }, { name: 'Authentication', status: 'operational', - icon: , + icon: , uptime: 99.98, responseTime: 89, }, { name: 'Web Servers', status: 'operational', - icon: , + icon: , uptime: 99.97, responseTime: 23, }, { name: 'CDN', status: 'degraded', - icon: , + icon: , uptime: 99.5, responseTime: 156, }, { name: 'Background Jobs', status: 'operational', - icon: , + icon: , uptime: 99.9, responseTime: 34, }, @@ -118,15 +119,15 @@ function SystemStatusPage() {
    {allOperational ? (
    - +
    ) : hasOutage ? (
    - +
    ) : (
    - +
    )}
    @@ -146,7 +147,7 @@ function SystemStatusPage() {
    - + Last updated: {new Date().toLocaleTimeString()}
    @@ -166,7 +167,7 @@ function SystemStatusPage() { className='flex flex-col items-center gap-2 p-4 rounded-lg border hover:bg-muted/50 transition-colors' >
    - +
    Error States HTTP errors & failures @@ -176,7 +177,7 @@ function SystemStatusPage() { className='flex flex-col items-center gap-2 p-4 rounded-lg border hover:bg-muted/50 transition-colors' >
    - +
    Success States Confirmations @@ -186,7 +187,7 @@ function SystemStatusPage() { className='flex flex-col items-center gap-2 p-4 rounded-lg border hover:bg-muted/50 transition-colors' >
    - +
    Info States Notifications @@ -196,7 +197,7 @@ function SystemStatusPage() { className='flex flex-col items-center gap-2 p-4 rounded-lg border hover:bg-muted/50 transition-colors' >
    - +
    Loading States Pending & progress @@ -312,5 +313,3 @@ function SystemStatusPage() {
    ) } - -export default SystemStatusPage diff --git a/frontend/src/routes/_status/subscription-cancelled.tsx b/frontend/src/routes/_status/subscription-cancelled.tsx index c86d3bf..6d792a8 100644 --- a/frontend/src/routes/_status/subscription-cancelled.tsx +++ b/frontend/src/routes/_status/subscription-cancelled.tsx @@ -1,7 +1,8 @@ +import { CreditCardIcon, Home01Icon, SparklesIcon, Cancel01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { CreditCard, Home, Sparkles, XCircle } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -19,7 +20,7 @@ function SubscriptionCancelledPage() { variant='default' icon={
    - +
    } title='Subscription Cancelled' @@ -27,11 +28,11 @@ function SubscriptionCancelledPage() { footer={ <> @@ -39,7 +40,7 @@ function SubscriptionCancelledPage() { >
    - + Access Until End of Billing Period You'll continue to have access to Pro features until Feb 28, 2026. @@ -55,5 +56,3 @@ function SubscriptionCancelledPage() { ) } - -export default SubscriptionCancelledPage diff --git a/frontend/src/routes/_status/success-states.tsx b/frontend/src/routes/_status/success-states.tsx index 84b0e50..d9ffe85 100644 --- a/frontend/src/routes/_status/success-states.tsx +++ b/frontend/src/routes/_status/success-states.tsx @@ -1,19 +1,19 @@ -import { createFileRoute, Link } from '@tanstack/react-router' import { - Check, - CheckCircle2, - Crown, - Database, - FileDown, - FileUp, - Key, - KeyRound, - Mail, - PartyPopper, - Shield, - Sparkles, - Webhook, -} from 'lucide-react' + CheckmarkCircle01Icon, + CrownIcon, + Database01Icon, + FileDownloadIcon, + FileUploadIcon, + Key01Icon, + Mail01Icon, + Shield01Icon, + SparklesIcon, + Tick01Icon, + ChampionIcon as TrophyIcon, + WebhookIcon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' +import { createFileRoute, Link } from '@tanstack/react-router' import { Badge } from '@/components/ui/badge' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' @@ -26,45 +26,50 @@ export const Route = createFileRoute('/_status/success-states')({ }) const successPages = [ - { name: 'General Success', icon: CheckCircle2, path: '/success', color: 'text-green-500' }, - { name: 'Welcome', icon: Sparkles, path: '/welcome', color: 'text-green-500' }, + { + name: 'General Success', + icon: CheckmarkCircle01Icon, + path: '/success', + color: 'text-green-500', + }, + { name: 'Welcome', icon: SparklesIcon, path: '/welcome', color: 'text-green-500' }, { name: 'Upgrade Success', - icon: Crown, + icon: CrownIcon, path: '/upgrade-success', color: 'text-green-500', }, { name: 'Password Changed', - icon: KeyRound, + icon: Key01Icon, path: '/password-changed', color: 'text-green-500', }, - { name: 'Email Sent', icon: Mail, path: '/email-sent', color: 'text-green-500' }, - { name: '2FA Enabled', icon: Shield, path: '/2fa-enabled', color: 'text-green-500' }, + { name: 'Email Sent', icon: Mail01Icon, path: '/email-sent', color: 'text-green-500' }, + { name: '2FA Enabled', icon: Shield01Icon, path: '/2fa-enabled', color: 'text-green-500' }, { name: 'Device Verified', - icon: Check, + icon: Tick01Icon, path: '/device-verified', color: 'text-green-500', }, - { name: 'Export Ready', icon: FileDown, path: '/export-ready', color: 'text-green-500' }, + { name: 'Export Ready', icon: FileDownloadIcon, path: '/export-ready', color: 'text-green-500' }, { name: 'Import Complete', - icon: FileUp, + icon: FileUploadIcon, path: '/import-complete', color: 'text-green-500', }, { name: 'Backup Complete', - icon: Database, + icon: Database01Icon, path: '/backup-complete', color: 'text-green-500', }, - { name: 'API Key Created', icon: Key, path: '/api-key-created', color: 'text-green-500' }, + { name: 'API Key Created', icon: Key01Icon, path: '/api-key-created', color: 'text-green-500' }, { name: 'Webhook Configured', - icon: Webhook, + icon: WebhookIcon, path: '/webhook-configured', color: 'text-green-500', }, @@ -77,7 +82,7 @@ function SuccessStatesPage() {
    - +
    Success States @@ -103,7 +108,7 @@ function SuccessStatesPage() { className='flex items-center gap-3 p-3 rounded-lg border hover:bg-muted/50 transition-colors' >
    - +
    {page.name}
    @@ -154,14 +159,14 @@ const handleUpgrade = async () => {
    - +
    variant="success"
    Green border accent
    - +
    variant="info"
    Blue border accent
    @@ -173,5 +178,3 @@ const handleUpgrade = async () => {
    ) } - -export default SuccessStatesPage diff --git a/frontend/src/routes/_status/success.tsx b/frontend/src/routes/_status/success.tsx index 6ab4e67..0f95335 100644 --- a/frontend/src/routes/_status/success.tsx +++ b/frontend/src/routes/_status/success.tsx @@ -1,7 +1,8 @@ +import { Tick02Icon, Home01Icon, SparklesIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { CheckCircle2, Home, PartyPopper } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -19,7 +20,7 @@ function SuccessPage() { variant='success' icon={
    - +
    } title='Success!' @@ -27,7 +28,7 @@ function SuccessPage() { footer={ <> } > - + Connection Timed Out This could be due to slow network conditions or server load. Please try again. @@ -46,5 +47,3 @@ function TimeoutPage() { ) } - -export default TimeoutPage diff --git a/frontend/src/routes/_status/under-construction.tsx b/frontend/src/routes/_status/under-construction.tsx index f19ee49..555b3c7 100644 --- a/frontend/src/routes/_status/under-construction.tsx +++ b/frontend/src/routes/_status/under-construction.tsx @@ -1,7 +1,8 @@ +import { ConstructionIcon, Home01Icon, Wrench01Icon as Wrench } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { HardHat, Home, Wrench } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Progress, ProgressLabel, ProgressValue } from '@/components/ui/progress' @@ -20,14 +21,14 @@ function UnderConstructionPage() { variant='info' icon={
    - +
    } title='Under Construction' description="We're building something amazing here!" footer={ } @@ -35,7 +36,7 @@ function UnderConstructionPage() {
    - + Work in Progress
    @@ -60,5 +61,3 @@ function UnderConstructionPage() { ) } - -export default UnderConstructionPage diff --git a/frontend/src/routes/_status/unsupported-media.tsx b/frontend/src/routes/_status/unsupported-media.tsx index ccf9a42..ce84e45 100644 --- a/frontend/src/routes/_status/unsupported-media.tsx +++ b/frontend/src/routes/_status/unsupported-media.tsx @@ -1,7 +1,8 @@ +import { FileRemoveIcon, Home01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { FileX, Home } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -19,7 +20,7 @@ function UnsupportedMediaPage() { variant='error' icon={
    - +
    } title='415 - Unsupported Media Type' @@ -27,7 +28,7 @@ function UnsupportedMediaPage() { footer={ <> } >
    - + - + Pro Member - +
    @@ -47,23 +54,23 @@ function UpgradeSuccessPage() {

    New features unlocked:

    • - + Unlimited API calls
    • - + Priority support
    • - + Advanced analytics
    • - + Team collaboration
    • - + Custom integrations
    @@ -78,5 +85,3 @@ function UpgradeSuccessPage() { ) } - -export default UpgradeSuccessPage diff --git a/frontend/src/routes/_status/verify-email.tsx b/frontend/src/routes/_status/verify-email.tsx index aa6cf00..af4bbd6 100644 --- a/frontend/src/routes/_status/verify-email.tsx +++ b/frontend/src/routes/_status/verify-email.tsx @@ -1,7 +1,8 @@ +import { Home01Icon, Mail01Icon, RefreshIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Home, Mail, RefreshCcw } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -19,7 +20,7 @@ function VerifyEmailPage() { variant='info' icon={
    - +
    } title='Verify Your Email' @@ -27,11 +28,11 @@ function VerifyEmailPage() { footer={ <> @@ -39,7 +40,7 @@ function VerifyEmailPage() { >
    - + Check Your Inbox We've sent a verification email to your registered email address. @@ -60,5 +61,3 @@ function VerifyEmailPage() { ) } - -export default VerifyEmailPage diff --git a/frontend/src/routes/_status/webhook-configured.tsx b/frontend/src/routes/_status/webhook-configured.tsx index 94f2f06..22ce1f9 100644 --- a/frontend/src/routes/_status/webhook-configured.tsx +++ b/frontend/src/routes/_status/webhook-configured.tsx @@ -1,7 +1,8 @@ +import { Home01Icon, Tick01Icon, WebhookIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { Check, Home, Webhook } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -19,7 +20,7 @@ function WebhookConfiguredPage() { variant='success' icon={
    - +
    } title='Webhook Configured' @@ -28,7 +29,7 @@ function WebhookConfiguredPage() { <> @@ -37,7 +38,7 @@ function WebhookConfiguredPage() {
    - + Active
    @@ -68,5 +69,3 @@ function WebhookConfiguredPage() { ) } - -export default WebhookConfiguredPage diff --git a/frontend/src/routes/_status/welcome.tsx b/frontend/src/routes/_status/welcome.tsx index 828f12a..5ee42a2 100644 --- a/frontend/src/routes/_status/welcome.tsx +++ b/frontend/src/routes/_status/welcome.tsx @@ -1,7 +1,14 @@ +import { + ArrowRight01Icon as ArrowRight, + Book01Icon as BookOpen, + RocketIcon as Rocket, + Settings01Icon as Settings, + SparklesIcon as Sparkles, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { ArrowRight, BookOpen, Rocket, Settings, Sparkles } from 'lucide-react' -import { StatusCard } from '@/components/StatusTemplate' +import { StatusCard } from '@/components/common/status/StatusTemplate' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' @@ -20,7 +27,7 @@ function WelcomePage() { variant='success' icon={
    - +
    } title='Welcome to FastAPI Cloud!' @@ -28,14 +35,14 @@ function WelcomePage() { footer={ } >
    - + Account Active
    @@ -48,7 +55,7 @@ function WelcomePage() { - + Explore the Dashboard @@ -64,7 +71,7 @@ function WelcomePage() { - + Configure Settings @@ -80,7 +87,7 @@ function WelcomePage() { - + Read the Docs @@ -97,5 +104,3 @@ function WelcomePage() { ) } - -export default WelcomePage diff --git a/frontend/src/routes/dashboard/index.module.css b/frontend/src/routes/dashboard/index.module.css index 085bd93..3db09e4 100644 --- a/frontend/src/routes/dashboard/index.module.css +++ b/frontend/src/routes/dashboard/index.module.css @@ -18,22 +18,53 @@ padding: 0 1rem; } -.yearSelector { +.backButton { + gap: 0.25rem; + border-color: var(--border-subtle); + background-color: var(--surface-elevated); + color: var(--text-primary); + + &:hover { + background-color: var(--interactive-hover); + } +} + +/* Filter controls group (subject + year) */ +.filterGroup { + display: flex; + align-items: center; + gap: 1rem; + padding: 0.375rem 0.75rem; + border-radius: 0.75rem; + border: 1px solid var(--border-subtle); + background-color: var(--surface-elevated); +} + +.filterItem { display: flex; align-items: center; gap: 0.5rem; } -.yearLabel { - font-size: 0.875rem; +.filterLabel { + font-size: 0.8125rem; + font-weight: 500; color: var(--text-secondary); + white-space: nowrap; } -.backButton { - gap: 0.25rem; - border-color: var(--border-subtle); - background-color: var(--surface-elevated); +.filterDivider { + width: 1px; + height: 1.5rem; + background-color: var(--border-subtle); +} + +.filterSelectTrigger { + width: 8.5rem; + border-color: transparent; + background-color: transparent; color: var(--text-primary); + font-weight: 500; &:hover { background-color: var(--interactive-hover); @@ -41,10 +72,15 @@ } .yearSelectTrigger { - width: 7.5rem; - border-color: var(--border-subtle); - background-color: var(--surface-elevated); + width: 6rem; + border-color: transparent; + background-color: transparent; color: var(--text-primary); + font-weight: 500; + + &:hover { + background-color: var(--interactive-hover); + } } .content { @@ -71,6 +107,52 @@ } } +/* Stats row */ +.statsRow { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1rem; +} + +.statCard { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.125rem; + padding: 1rem 0.75rem; + border-radius: 0.75rem; + border: 1px solid var(--border-subtle); + background-color: var(--surface-elevated); + transition: + box-shadow 0.2s ease, + transform 0.15s ease; + + &:hover { + box-shadow: 0 2px 8px rgb(0 0 0 / 0.06); + transform: translateY(-1px); + } +} + +.statCardAccent { + border-color: hsl(var(--primary) / 0.3); + background: linear-gradient(135deg, hsl(var(--primary) / 0.04), hsl(var(--primary) / 0.08)); +} + +.statValue { + font-size: 1.5rem; + font-weight: 700; + color: var(--text-heading); + line-height: 1.2; +} + +.statLabel { + font-size: 0.75rem; + font-weight: 500; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.03em; +} + .gridSection { & h2 { margin-bottom: 1rem; @@ -95,3 +177,20 @@ opacity: 0.5; } } + +@media (max-width: 640px) { + .topBar { + flex-direction: column; + gap: 0.75rem; + align-items: stretch; + } + + .filterGroup { + width: 100%; + justify-content: center; + } + + .statsRow { + grid-template-columns: repeat(2, 1fr); + } +} diff --git a/frontend/src/routes/dashboard/index.tsx b/frontend/src/routes/dashboard/index.tsx index 80df589..86fd500 100644 --- a/frontend/src/routes/dashboard/index.tsx +++ b/frontend/src/routes/dashboard/index.tsx @@ -1,13 +1,45 @@ +import { + ArrowLeft01Icon, + BookOpen01Icon, + Calculator01Icon, + TestTube01Icon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, useRouter } from '@tanstack/react-router' -import { ChevronLeft } from 'lucide-react' -import { Suspense, useCallback, useState } from 'react' +import { Suspense, useCallback, useMemo, useState } from 'react' +import { + Area, + AreaChart, + Bar, + BarChart, + CartesianGrid, + Cell, + Line, + LineChart, + PolarAngleAxis, + PolarGrid, + PolarRadiusAxis, + Radar, + RadarChart, + RadialBar, + RadialBarChart, + XAxis, + YAxis, + Pie, + PieChart, +} from 'recharts' import { z } from 'zod' -import type { ColorKey } from '@/components/dashboard/card/IndicatorCard' -import { IndicatorDetailModal } from '@/components/dashboard/detail/IndicatorDetailModal' -import { IndicatorGrid, IndicatorGridSkeleton } from '@/components/dashboard/IndicatorGrid' -import NavbarD52 from '@/components/layout/navbar/NavbarD52' +import NavbarD52 from '@/components/common/navbar/navbar-D52' import { Button } from '@/components/ui/button' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { + ChartContainer, + ChartLegend, + ChartLegendContent, + ChartTooltip, + ChartTooltipContent, +} from '@/components/ui/chart' import { Select, SelectContent, @@ -15,67 +47,229 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select' -import { STATEWIDE_CDS, type IndicatorCode } from '@/lib/constants/indicators' -import ScrollReset from '@/lib/hooks/ScrollReset' -import { useDashboardSummarySuspense } from '@/lib/hooks/useDashboardData' -import { useLastViewedSchool } from '@/lib/hooks/useLastViewedSchool' +import { STATEWIDE_CDS } from '@/lib/constants/indicators' +import ScrollReset from '@/routes/-hooks/hooks/ScrollReset' +import { + useDashboardSummary, + useDashboardSummarySuspense, + useEquityReport, +} from '@/routes/-hooks/hooks/useDashboardData' +import { useLastViewedSchool } from '@/routes/-hooks/hooks/useLastViewedSchool' import styles from './index.module.css' const AVAILABLE_YEARS = ['2025', '2024'] as const type ReportingYear = (typeof AVAILABLE_YEARS)[number] +const SUBJECTS = [ + { id: '1', label: 'English Language Arts', shortLabel: 'ELA', icon: BookOpen01Icon }, + { id: '2', label: 'Mathematics', shortLabel: 'Math', icon: Calculator01Icon }, + { id: '3', label: 'Science (CAST)', shortLabel: 'Science', icon: TestTube01Icon }, +] as const + +type SubjectId = (typeof SUBJECTS)[number]['id'] + +type EquityGroup = { + studentGroup: string + overallMetAndAbovePct?: string | null + studentsTested?: string | null +} + +type SummaryIndicator = { + testId: string + grade: string + studentsEnrolled: string + studentsTested: string + overallMeanScaleScore?: string | null + overallMetAndAbovePct?: string | null + levels?: Record | null +} + +const EMPTY_EQUITY_GROUPS: EquityGroup[] = [] + +const PIE_COLORS = [ + 'var(--color-chart-1)', + 'var(--color-chart-2)', + 'var(--color-chart-3)', + 'var(--color-chart-4)', + 'var(--color-chart-5)', + '#0891b2', + '#65a30d', + '#db2777', +] + +const levelColorMap = { + level4: '#0f766e', + level3: '#2563eb', + level2: '#d97706', + level1: '#dc2626', +} as const + const searchSchema = z.object({ q: z.coerce.string().optional(), year: z.coerce .string() .optional() - .transform((val) => { - if (val === '2024' || val === '2025') return val - return undefined - }), + .transform((value) => + value === '2024' || value === '2025' ? (value as ReportingYear) : undefined, + ), + subject: z.coerce + .string() + .optional() + .transform((value) => + value === '1' || value === '2' || value === '3' ? (value as SubjectId) : undefined, + ), }) +const snapshotChartConfig = { + proficiency: { label: 'Met Standard', color: 'var(--color-chart-2)' }, + participation: { label: 'Participation', color: 'var(--color-chart-4)' }, +} as const + +const performanceChartConfig = { + level4: { label: 'Exceeded', color: levelColorMap.level4 }, + level3: { label: 'Met', color: levelColorMap.level3 }, + level2: { label: 'Nearly Met', color: levelColorMap.level2 }, + level1: { label: 'Not Met', color: levelColorMap.level1 }, +} as const + +const trendChartConfig = { + pct: { label: 'Met/Exceeded', color: 'var(--color-chart-2)' }, +} as const + +const testedChartConfig = { + tested: { label: 'Tested', color: 'var(--color-chart-3)' }, + enrolled: { label: 'Enrolled', color: 'var(--color-chart-5)' }, +} as const + +const scaleChartConfig = { + scale: { label: 'Mean Scale Score', color: 'var(--color-chart-1)' }, +} as const + +const radarChartConfig = { + level4: { label: 'Exceeded', color: levelColorMap.level4 }, + level3: { label: 'Met', color: levelColorMap.level3 }, + level2: { label: 'Nearly Met', color: levelColorMap.level2 }, + level1: { label: 'Not Met', color: levelColorMap.level1 }, +} as const + export const Route = createFileRoute('/dashboard/')({ component: DashboardPage, validateSearch: searchSchema, }) +function parseCount(value: string | null | undefined) { + const parsed = Number.parseInt(value ?? '', 10) + return Number.isFinite(parsed) ? parsed : 0 +} + +function parsePercentage(value: string | null | undefined) { + if (value == null) { + return null + } + + const parsed = Number.parseFloat(value) + return Number.isFinite(parsed) ? parsed : null +} + +function formatCompactNumber(value: number) { + return value.toLocaleString() +} + +function formatGradeLabel(grade: string) { + return grade === '13' ? 'All Grades' : `Grade ${grade}` +} + +function calculateAvgPct(data: { indicators?: SummaryIndicator[] } | undefined, subjectId: string) { + const subjectIndicators = (data?.indicators ?? []).filter( + (indicator) => indicator.testId === subjectId, + ) + let weightedPctSum = 0 + let weightedPctCount = 0 + + for (const indicator of subjectIndicators) { + const tested = parseCount(indicator.studentsTested) + const pct = parsePercentage(indicator.overallMetAndAbovePct) + if (pct !== null && tested > 0) { + weightedPctSum += pct * tested + weightedPctCount += tested + } + } + + return weightedPctCount > 0 + ? Number.parseFloat((weightedPctSum / weightedPctCount).toFixed(1)) + : null +} + +function getChangeLabel(current: number | null, previous: number | null) { + if (current === null || previous === null) { + return 'Single-year view' + } + + const delta = current - previous + if (Math.abs(delta) < 0.1) { + return 'Flat vs prior year' + } + + return `${delta > 0 ? '+' : ''}${delta.toFixed(1)} pts vs prior year` +} + +function EmptyChartState({ + title, + description, + height = 'h-[320px]', +}: { + title: string + description: string + height?: string +}) { + return ( +
    +
    +

    {title}

    +

    {description}

    +
    +
    + ) +} + function DashboardPage() { - const { q, year: urlYear } = Route.useSearch() + const { q, year: urlYear, subject: urlSubject } = Route.useSearch() const navigate = Route.useNavigate() const router = useRouter() const { cds: lastViewedCds } = useLastViewedSchool() const effectiveCds = q || lastViewedCds || STATEWIDE_CDS const effectiveYear: ReportingYear = urlYear || '2025' + const effectiveSubjectId: SubjectId = urlSubject || '1' - const [selectedIndicator, setSelectedIndicator] = useState(null) - const [selectedColor, setSelectedColor] = useState(null) - - const handleIndicatorClick = useCallback((code: IndicatorCode) => { - setSelectedIndicator(code) - setSelectedColor(null) - }, []) - - const handleColorClick = useCallback((code: IndicatorCode, color: ColorKey) => { - setSelectedIndicator(code) - setSelectedColor(color) - }, []) - - const handleCloseModal = useCallback(() => { - setSelectedIndicator(null) - setSelectedColor(null) - }, []) + const activeSubject = useMemo( + () => SUBJECTS.find((subject) => subject.id === effectiveSubjectId) ?? SUBJECTS[0], + [effectiveSubjectId], + ) const handleYearChange = useCallback( - (year: ReportingYear) => { - if (year === effectiveYear) return - navigate({ search: (prev) => ({ ...prev, year }) }) + (nextYear: ReportingYear) => { + if (nextYear === effectiveYear) { + return + } + navigate({ search: (previous) => ({ ...previous, year: nextYear }) }) }, [effectiveYear, navigate], ) + const handleSubjectChange = useCallback( + (nextSubject: SubjectId) => { + if (nextSubject === effectiveSubjectId) { + return + } + navigate({ search: (previous) => ({ ...previous, subject: nextSubject }) }) + }, + [effectiveSubjectId, navigate], + ) + return (
    @@ -88,26 +282,49 @@ function DashboardPage() { onClick={() => router.history.back()} className={styles.backButton} > - + Go back -
    - Reporting Year: - +
    +
    + Subject: + +
    +
    +
    + Year: + +
    @@ -115,11 +332,7 @@ function DashboardPage() {
    @@ -130,72 +343,728 @@ function DashboardPage() { function DashboardContent({ cds, year, - selectedIndicator, - selectedColor, - onIndicatorClick, - onColorClick, - onCloseModal, + subjectId, }: { cds: string year: ReportingYear - selectedIndicator: IndicatorCode | null - selectedColor: ColorKey | null - onIndicatorClick: (code: IndicatorCode) => void - onColorClick: (code: IndicatorCode, color: ColorKey) => void - onCloseModal: () => void + subjectId: SubjectId }) { - const { data } = useDashboardSummarySuspense(cds, year) - const indicators = Array.isArray(data.indicators) ? data.indicators : [] - const reportingYear = data.reportingyear || year + const { data: summaryData } = useDashboardSummarySuspense(cds, year) + const prevYear = year === '2025' ? '2024' : null + const { data: prevSummaryData } = useDashboardSummary(cds, prevYear || '2024', 'ALL') + const reportingYear = summaryData.testYear || year + const entityName = cds === STATEWIDE_CDS ? 'California Statewide' : 'Assessment Dashboard' + const activeSubject = useMemo( + () => SUBJECTS.find((subject) => subject.id === subjectId) ?? SUBJECTS[0], + [subjectId], + ) + const { data: equityData, isLoading: isEquityLoading } = useEquityReport( + cds, + subjectId, + reportingYear, + ) + const equityGroups = Array.isArray(equityData?.groups) ? equityData.groups : EMPTY_EQUITY_GROUPS + const [selectedGroup, setSelectedGroup] = useState(null) - const entityName = - data.schoolname || - data.districtname || - (cds === STATEWIDE_CDS ? 'California Statewide' : 'Unknown') + const subjectIndicators = useMemo( + () => (summaryData.indicators ?? []).filter((indicator) => indicator.testId === subjectId), + [summaryData.indicators, subjectId], + ) - const indicatorData = selectedIndicator - ? indicators.find((ind) => ind.indicator === selectedIndicator) - : null + const summaryStats = useMemo(() => { + const totalEnrolled = subjectIndicators.reduce( + (sum, indicator) => sum + parseCount(indicator.studentsEnrolled), + 0, + ) + const totalTested = subjectIndicators.reduce( + (sum, indicator) => sum + parseCount(indicator.studentsTested), + 0, + ) + let weightedPctSum = 0 + let weightedPctCount = 0 + let weightedScaleSum = 0 + let weightedScaleCount = 0 + + for (const indicator of subjectIndicators) { + const tested = parseCount(indicator.studentsTested) + const pct = parsePercentage(indicator.overallMetAndAbovePct) + const scale = parsePercentage(indicator.overallMeanScaleScore) + if (pct !== null && tested > 0) { + weightedPctSum += pct * tested + weightedPctCount += tested + } + if (scale !== null && tested > 0) { + weightedScaleSum += scale * tested + weightedScaleCount += tested + } + } + + return { + gradeCount: subjectIndicators.length, + totalEnrolled, + totalTested, + avgPct: weightedPctCount > 0 ? weightedPctSum / weightedPctCount : null, + avgScale: weightedScaleCount > 0 ? weightedScaleSum / weightedScaleCount : null, + participationPct: + totalEnrolled > 0 + ? Number.parseFloat(((totalTested / totalEnrolled) * 100).toFixed(1)) + : null, + } + }, [subjectIndicators]) + + const gradePerformanceData = useMemo( + () => + [...subjectIndicators] + .sort((left, right) => parseCount(left.grade) - parseCount(right.grade)) + .map((indicator) => { + const tested = parseCount(indicator.studentsTested) + const enrolled = parseCount(indicator.studentsEnrolled) + const meanScale = parsePercentage(indicator.overallMeanScaleScore) + return { + grade: formatGradeLabel(indicator.grade), + tested, + enrolled, + meanScale, + metPct: parsePercentage(indicator.overallMetAndAbovePct), + level4: indicator.levels?.['Standard Exceeded (Level 4)'] ?? 0, + level3: indicator.levels?.['Standard Met (Level 3)'] ?? 0, + level2: indicator.levels?.['Standard Nearly Met (Level 2)'] ?? 0, + level1: indicator.levels?.['Standard Not Met (Level 1)'] ?? 0, + } + }), + [subjectIndicators], + ) + + const trendData = useMemo( + () => + [ + { year: '2024', pct: calculateAvgPct(prevSummaryData, subjectId) }, + { year: '2025', pct: calculateAvgPct(summaryData, subjectId) }, + ].filter((entry) => entry.pct !== null), + [prevSummaryData, subjectId, summaryData], + ) + + const levelRadarData = useMemo(() => { + const totals = { + level4: 0, + level3: 0, + level2: 0, + level1: 0, + } + let weightTotal = 0 + + for (const item of gradePerformanceData) { + const weight = item.tested > 0 ? item.tested : 1 + totals.level4 += item.level4 * weight + totals.level3 += item.level3 * weight + totals.level2 += item.level2 * weight + totals.level1 += item.level1 * weight + weightTotal += weight + } + + if (weightTotal === 0) { + return [] + } + + return [ + { metric: 'Exceeded', value: Number.parseFloat((totals.level4 / weightTotal).toFixed(1)) }, + { metric: 'Met', value: Number.parseFloat((totals.level3 / weightTotal).toFixed(1)) }, + { metric: 'Nearly Met', value: Number.parseFloat((totals.level2 / weightTotal).toFixed(1)) }, + { metric: 'Not Met', value: Number.parseFloat((totals.level1 / weightTotal).toFixed(1)) }, + ] + }, [gradePerformanceData]) + + const equityPieData = useMemo( + () => + equityGroups + .filter((group) => group.studentGroup?.toLowerCase() !== 'all students') + .map((group, index) => ({ + name: group.studentGroup || 'Unknown', + tested: parseCount(group.studentsTested), + metPct: parsePercentage(group.overallMetAndAbovePct), + fill: PIE_COLORS[index % PIE_COLORS.length], + })) + .filter((group) => group.tested > 0) + .sort((left, right) => right.tested - left.tested), + [equityGroups], + ) + + const groupComparisonData = useMemo( + () => + [...equityPieData] + .sort((left, right) => (right.metPct ?? -1) - (left.metPct ?? -1)) + .slice(0, 6) + .map((group) => ({ + group: group.name, + metPct: group.metPct ?? 0, + tested: group.tested, + })), + [equityPieData], + ) + + const activeGroup = + selectedGroup != null + ? (equityPieData.find((group) => group.name === selectedGroup) ?? null) + : null + + const snapshotData = [ + { + name: 'snapshot', + proficiency: summaryStats.avgPct ?? 0, + participation: summaryStats.participationPct ?? 0, + }, + ] + + const changeLabel = getChangeLabel( + trendData.at(-1)?.pct ?? null, + trendData.length > 1 ? (trendData[0]?.pct ?? null) : null, + ) return ( - <> -
    -
    -

    {entityName}

    - {data.countyname && cds !== STATEWIDE_CDS && ( -

    - {data.districtname && data.schoolname - ? `${data.districtname} | ${data.countyname}` - : data.countyname} -

    - )} -

    - {reportingYear} California School Dashboard - {data.charter_flag === 'Y' && ' | Charter School'} -

    -
    +
    +
    +

    {entityName}

    +

    + {reportingYear} {activeSubject.label} assessment view +

    +
    -
    - -
    +
    + + +
    + + + + + {activeSubject.label} + + + Assessment snapshot across tested grades. Metrics stay visible even when a slice has + sparse reporting. + +
    +
    +

    Year-over-year signal

    +

    {changeLabel}

    +
    +
    + + + + ( + <> + {String(name)} + {Number(value).toFixed(1)}% + + )} + /> + } + /> + + + } /> + + +
    + + 0 + ? `${formatCompactNumber(summaryStats.totalEnrolled)} enrolled` + : 'Enrollment not reported' + } + /> + + +
    +
    +
    + + + + Achievement Profile + + Weighted performance shape for {activeSubject.shortLabel} across level bands. + + + + {levelRadarData.length > 0 ? ( + + + } /> + + + + + + + ) : ( + + )} + + +
    + +
    + + + Performance Levels by Grade + + Stacked distribution for {activeSubject.label} in {reportingYear}. + + + + {gradePerformanceData.length > 0 ? ( + + + + + `${value}%`} tickLine={false} axisLine={false} /> + ( + <> + {String(name)} + + {Number(value).toFixed(1)}% + {item?.payload?.tested + ? ` • ${item.payload.tested.toLocaleString()} tested` + : ''} + + + )} + /> + } + /> + } /> + + + + + + + ) : ( + + )} + + + + + + Grade Volume + + Tested and enrolled counts by grade for the selected subject. + + + + {gradePerformanceData.length > 0 ? ( + + + + + + } /> + } /> + + + + + ) : ( + + )} + +
    - - +
    + + + Performance Trend + + Area and line view of met-or-exceeded percentage across available years. + + + + {trendData.length > 0 ? ( + + + + + + + + + + + `${value}%`} + tickLine={false} + axisLine={false} + /> + ( + {Number(value).toFixed(1)}% + )} + /> + } + /> + + + + + ) : ( + + )} + + + + + + Mean Scale by Grade + + Line view of average scale score across reporting grades in {reportingYear}. + + + + {gradePerformanceData.some((item) => item.meanScale !== null) ? ( + + item.meanScale !== null)}> + + + + ( + {Number(value).toFixed(1)} + )} + /> + } + /> + + + + ) : ( + + )} + + +
    + +
    + + + Demographic Composition + + Tested-student share by student group. Select a slice to inspect that group. + + + + {isEquityLoading ? ( + + ) : equityPieData.length > 0 ? ( +
    + [ + group.name, + { label: group.name, color: group.fill }, + ]), + )} + className='mx-auto aspect-square max-h-[340px]' + > + + ( + <> +
    + Tested + + {Number(value).toLocaleString()} + +
    + {item?.payload?.metPct !== null && + item?.payload?.metPct !== undefined ? ( +
    + Met + + {Number(item.payload.metPct).toFixed(1)}% + +
    + ) : null} + + )} + /> + } + /> + + entry?.name && + setSelectedGroup(entry.name === selectedGroup ? null : entry.name) + } + > + {equityPieData.map((entry) => ( + + ))} + +
    +
    +
    +
    + + sum + group.tested, 0), + )} + note='Across reported groups' + /> +
    + {activeGroup ? ( +
    +

    {activeGroup.name}

    +
    + + +
    +
    + ) : ( +
    + Select a pie slice to inspect a student group without leaving the dashboard. +
    + )} +
    +
    + ) : ( + + )} +
    +
    + + + + Group Comparison + + Highest reported met-or-exceeded percentages among available student groups. + + + + {isEquityLoading ? ( + + ) : groupComparisonData.length > 0 ? ( + + + + `${value}%`} + tickLine={false} + axisLine={false} + /> + + ( + <> + {item?.payload?.group} + + {Number(value).toFixed(1)}% •{' '} + {item?.payload?.tested?.toLocaleString()} tested + + + )} + /> + } + /> + + + + ) : ( + + )} + + +
    +
    + ) +} + +function MetricPanel({ label, value, note }: { label: string; value: string; note: string }) { + return ( +
    +

    + {label} +

    +

    {value}

    +

    {note}

    +
    ) } @@ -204,11 +1073,19 @@ function DashboardSkeleton() {
    -
    -
    +
    +
    +
    +
    +
    +
    +
    +
    +
    -
    - +
    +
    +
    ) diff --git a/frontend/src/routes/dashboard2/index.tsx b/frontend/src/routes/dashboard2/index.tsx index 2223181..1b9af53 100644 --- a/frontend/src/routes/dashboard2/index.tsx +++ b/frontend/src/routes/dashboard2/index.tsx @@ -1,17 +1,18 @@ +import { + ActivityIcon, + AnalyticsUpIcon, + ArrowDown01Icon, + ArrowUp01Icon, + Dollar01Icon, + Home01Icon, + Settings02Icon, + ShoppingBasket01Icon, + UserGroupIcon, + UserIcon, +} from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute } from '@tanstack/react-router' import { useState } from 'react' -import { - FiActivity, - FiArrowDown, - FiArrowUp, - FiDollarSign, - FiHome, - FiSettings, - FiShoppingCart, - FiTrendingUp, - FiUser, - FiUsers, -} from 'react-icons/fi' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' @@ -19,7 +20,11 @@ import { Card, CardContent, CardFooter, CardHeader } from '@/components/ui/card' import { Skeleton } from '@/components/ui/skeleton' import { Spinner } from '@/components/ui/spinner' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' -import { useCensusDataById, useTotalEnrollment } from '@/lib/hooks/useCensusData' +import { useCensusDataById, useTotalEnrollment } from '@/routes/-hooks/hooks/useCensusData' + +export const Route = createFileRoute('/dashboard2/')({ + component: Dashboard2Page, +}) // Component to display total enrollment with loading and error states function TotalEnrollmentDisplay() { @@ -113,7 +118,7 @@ function CensusDataSearchCard() { Total Enrollment
    - +

    {data.total_enr?.toLocaleString() || '0'} @@ -152,7 +157,7 @@ function CensusDataSearchCard() {

    Default View

    -

    - + No data selected
    @@ -163,7 +168,7 @@ function CensusDataSearchCard() {

    Last Searched

    {searchId ? '✓' : '-'}

    - + {searchId ? 'Data loaded' : 'No recent searches'} @@ -174,10 +179,6 @@ function CensusDataSearchCard() { ) } -export const Route = createFileRoute('/dashboard2/')({ - component: Dashboard2Page, -}) - function Dashboard2Page() { return (
    @@ -206,7 +207,7 @@ function Dashboard2Page() {

    Total Users

    - + +12.5% from last month
    @@ -217,7 +218,7 @@ function Dashboard2Page() {

    Active Users (30d)

    1,987

    - + +8.3% from last month
    @@ -228,7 +229,7 @@ function Dashboard2Page() {

    New Users (7d)

    142

    - + -5.2% from last week
    @@ -250,12 +251,12 @@ function Dashboard2Page() {

    Orders

    1,234

    - + -3.1%
    - +
    @@ -268,12 +269,12 @@ function Dashboard2Page() {

    Growth Rate

    15.3%

    - + +2.4%
    - +
    @@ -294,7 +295,7 @@ function Dashboard2Page() {
    - +

    New user registered

    @@ -307,7 +308,7 @@ function Dashboard2Page() {
    - +

    Payment received

    @@ -320,7 +321,7 @@ function Dashboard2Page() {
    - +

    New order placed

    @@ -345,15 +346,15 @@ function Dashboard2Page() {
    @@ -401,7 +402,7 @@ function Dashboard2Page() {

    Response Time

    234ms

    - + -12ms from last hour
    diff --git a/frontend/src/routes/deprecated/home.tsx b/frontend/src/routes/deprecated/home.tsx index ab9855a..3b9f659 100644 --- a/frontend/src/routes/deprecated/home.tsx +++ b/frontend/src/routes/deprecated/home.tsx @@ -1,7 +1,7 @@ import { createFileRoute, Link } from '@tanstack/react-router' -import CardGrid from '@/components/CardGrid.tsx' -import NavbarD52 from '@/components/layout/navbar/NavbarD52.tsx' +import CardGrid from '@/components/CardGrid' +import NavbarD52 from '@/components/common/navbar/navbar-D52' import { Button } from '@/components/ui/button' export const Route = createFileRoute('/deprecated/home')({ diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx index 1ba9954..57fbe81 100644 --- a/frontend/src/routes/index.tsx +++ b/frontend/src/routes/index.tsx @@ -1,7 +1,7 @@ import { createFileRoute, Link } from '@tanstack/react-router' -import NavbarD52 from '@/components/layout/navbar/NavbarD52.tsx' -import { Button } from '@/components/ui/button.tsx' +import NavbarD52 from '@/components/common/navbar/navbar-D52' +import { Button } from '@/components/ui/button' import styles from './index.module.css' diff --git a/frontend/src/routes/private/_private.tsx b/frontend/src/routes/private/_private.tsx index 29c3137..0c985c3 100644 --- a/frontend/src/routes/private/_private.tsx +++ b/frontend/src/routes/private/_private.tsx @@ -1,7 +1,7 @@ import { createFileRoute, Outlet, redirect } from '@tanstack/react-router' -import { Button } from '@/components/ui/button.tsx' -import useAuth from '@/lib/hooks/useAuth.ts' +import { Button } from '@/components/ui/button' +import useAuth from '@/routes/-hooks/hooks/useAuth.ts' export const Route = createFileRoute('/private/_private')({ beforeLoad: ({ context, location }) => { @@ -20,7 +20,7 @@ export const Route = createFileRoute('/private/_private')({ function PrivateLayout() { const auth = useAuth() - const userLabel = auth.user?.full_name || auth.user?.email || 'User' + const userLabel = auth.user?.fullName || auth.user?.email || 'User' return ( <>
    diff --git a/frontend/src/routes/report/index.tsx b/frontend/src/routes/report/index.tsx index 9001ecd..a870429 100644 --- a/frontend/src/routes/report/index.tsx +++ b/frontend/src/routes/report/index.tsx @@ -1,215 +1,11 @@ -import { createFileRoute, useRouter } from '@tanstack/react-router' -import { ChevronLeft } from 'lucide-react' -import { Suspense, useCallback, useState } from 'react' -import { z } from 'zod' +import { createFileRoute } from '@tanstack/react-router' -import type { ColorKey } from '@/components/dashboard/card/IndicatorCard' -import { IndicatorDetailModal } from '@/components/dashboard/detail/IndicatorDetailModal' -import { IndicatorGrid, IndicatorGridSkeleton } from '@/components/dashboard/IndicatorGrid' -import NavbarD52 from '@/components/layout/navbar/NavbarD52' -import { Button } from '@/components/ui/button' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select' -import { STATEWIDE_CDS, type IndicatorCode } from '@/lib/constants/indicators' -import ScrollReset from '@/lib/hooks/ScrollReset' -import { useDashboardSummarySuspense } from '@/lib/hooks/useDashboardData' -import { useLastViewedSchool } from '@/lib/hooks/useLastViewedSchool' - -import styles from './index.module.css' - -const AVAILABLE_YEARS = ['2025', '2024'] as const -type ReportingYear = (typeof AVAILABLE_YEARS)[number] - -const searchSchema = z.object({ - q: z.coerce.string().optional(), - year: z.coerce - .string() - .optional() - .transform((val) => { - if (val === '2024' || val === '2025') return val - return undefined - }), -}) +import { ComponentExample } from '@/components/component-example' export const Route = createFileRoute('/report/')({ - component: DashboardPage, - validateSearch: searchSchema, + component: ReportPage, }) -function DashboardPage() { - const { q, year: urlYear } = Route.useSearch() - const navigate = Route.useNavigate() - const router = useRouter() - const { cds: lastViewedCds } = useLastViewedSchool() - - const effectiveCds = q || lastViewedCds || STATEWIDE_CDS - const effectiveYear: ReportingYear = urlYear || '2025' - - const [selectedIndicator, setSelectedIndicator] = useState(null) - const [selectedColor, setSelectedColor] = useState(null) - - const handleIndicatorClick = useCallback((code: IndicatorCode) => { - setSelectedIndicator(code) - setSelectedColor(null) - }, []) - - const handleColorClick = useCallback((code: IndicatorCode, color: ColorKey) => { - setSelectedIndicator(code) - setSelectedColor(color) - }, []) - - const handleCloseModal = useCallback(() => { - setSelectedIndicator(null) - setSelectedColor(null) - }, []) - - const handleYearChange = useCallback( - (year: ReportingYear) => { - if (year === effectiveYear) return - navigate({ search: (prev) => ({ ...prev, year }) }) - }, - [effectiveYear, navigate], - ) - - return ( -
    - - -
    -
    - -
    - Reporting Year: - -
    -
    - - }> - - -
    -
    - ) -} - -function DashboardContent({ - cds, - year, - selectedIndicator, - selectedColor, - onIndicatorClick, - onColorClick, - onCloseModal, -}: { - cds: string - year: ReportingYear - selectedIndicator: IndicatorCode | null - selectedColor: ColorKey | null - onIndicatorClick: (code: IndicatorCode) => void - onColorClick: (code: IndicatorCode, color: ColorKey) => void - onCloseModal: () => void -}) { - const { data } = useDashboardSummarySuspense(cds, year) - const indicators = Array.isArray(data.indicators) ? data.indicators : [] - const reportingYear = data.reportingyear || year - - const entityName = - data.schoolname || - data.districtname || - (cds === STATEWIDE_CDS ? 'California Statewide' : 'Unknown') - - const indicatorData = selectedIndicator - ? indicators.find((ind) => ind.indicator === selectedIndicator) - : null - - return ( - <> -
    -
    -

    {entityName}

    - {data.countyname && cds !== STATEWIDE_CDS && ( -

    - {data.districtname && data.schoolname - ? `${data.districtname} | ${data.countyname}` - : data.countyname} -

    - )} -

    - {reportingYear} California School Dashboard - {data.charter_flag === 'Y' && ' | Charter School'} -

    -
    - -
    - -
    -
    - - - - ) -} - -function DashboardSkeleton() { - return ( -
    -
    -
    -
    -
    -
    -
    - -
    -
    - ) +function ReportPage() { + return } diff --git a/frontend/src/routes/user/_layout.tsx b/frontend/src/routes/user/_layout.tsx index 96eefe0..829c598 100644 --- a/frontend/src/routes/user/_layout.tsx +++ b/frontend/src/routes/user/_layout.tsx @@ -1,9 +1,9 @@ import { createFileRoute, Outlet, redirect } from '@tanstack/react-router' +import AppSidebar from '@/components/common/AppSidebar' import { Footer } from '@/components/common/Footer' -import AppSidebar from '@/components/layout/app-sidebar.tsx' import { SidebarInset, SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar' -import { isLoggedIn } from '@/lib/hooks/useAuth' +import { isLoggedIn } from '@/routes/-hooks/hooks/useAuth' export const Route = createFileRoute('/user/_layout')({ component: Layout, @@ -34,5 +34,3 @@ function Layout() { ) } - -export default Layout diff --git a/frontend/src/routes/user/admin.tsx b/frontend/src/routes/user/admin.tsx index e877e15..33fdd1c 100644 --- a/frontend/src/routes/user/admin.tsx +++ b/frontend/src/routes/user/admin.tsx @@ -4,10 +4,10 @@ import { Suspense } from 'react' import { columns, type UserTableData } from '@/components/admin/columns' import { DataTable } from '@/components/common/DataTable' -import AddUser from '@/components/form/AddUser.tsx' -import PendingUsers from '@/components/layout/pending/PendingUsers' +import PendingUsers from '@/components/common/pending/PendingUsers' +import AddUser from '@/components/form/AddUser' import { type UserPublic, UsersService } from '@/lib/client' -import useAuth from '@/lib/hooks/useAuth' +import useAuth from '@/routes/-hooks/hooks/useAuth' function getUsersQueryOptions() { return { @@ -26,7 +26,7 @@ export const Route = createFileRoute('/user/admin')({ component: Admin, beforeLoad: async () => { const response = await UsersService.usersReadUserMe({}) - if (!response.data?.is_superuser) { + if (!response.data?.isSuperuser) { throw redirect({ to: '/', }) diff --git a/frontend/src/routes/user/index.tsx b/frontend/src/routes/user/index.tsx index 78768eb..dfa9beb 100644 --- a/frontend/src/routes/user/index.tsx +++ b/frontend/src/routes/user/index.tsx @@ -1,10 +1,11 @@ +import { AlertCircleIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { Link, createFileRoute } from '@tanstack/react-router' -import { ShieldAlert } from 'lucide-react' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' -import useAuth from '@/lib/hooks/useAuth' +import useAuth from '@/routes/-hooks/hooks/useAuth' export const Route = createFileRoute('/user/')({ component: Dashboard, @@ -29,19 +30,19 @@ function Dashboard() {

    - Hi, {currentUser.full_name || currentUser.email} + Hi, {currentUser.fullName || currentUser.email}

    - {currentUser.is_superuser && Admin} + {currentUser.isSuperuser && Admin}

    Welcome back. Choose what you want to manage.

    - {currentUser.force_password_reset && ( + {currentUser.forcePasswordReset && ( - + Password reset required - Your account has force_password_reset enabled. Please update your + Your account has forcePasswordReset enabled. Please update your password in settings. @@ -51,7 +52,7 @@ function Dashboard() {

    Items

    - {currentUser.is_superuser + {currentUser.isSuperuser ? "View and edit all users' items." : 'Create and manage your items.'}

    @@ -70,7 +71,7 @@ function Dashboard() {
    - {currentUser.is_superuser && ( + {currentUser.isSuperuser && (

    Admin

    diff --git a/frontend/src/routes/user/items.tsx b/frontend/src/routes/user/items.tsx index 29a1e18..606c637 100644 --- a/frontend/src/routes/user/items.tsx +++ b/frontend/src/routes/user/items.tsx @@ -1,14 +1,15 @@ +import { Search01Icon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { useSuspenseQuery } from '@tanstack/react-query' import { createFileRoute } from '@tanstack/react-router' -import { Search } from 'lucide-react' import { Suspense, useMemo } from 'react' import { DataTable } from '@/components/common/DataTable' +import PendingItems from '@/components/common/pending/PendingItems' import AddItem from '@/components/items/AddItem' import { createItemColumns } from '@/components/items/columns' -import PendingItems from '@/components/layout/pending/PendingItems' import { ItemsService } from '@/lib/client' -import useAuth from '@/lib/hooks/useAuth' +import useAuth from '@/routes/-hooks/hooks/useAuth' function getItemsQueryOptions() { return { @@ -41,24 +42,22 @@ function ItemsTableContent() { () => createItemColumns({ currentUserId: currentUser?.id, - isSuperuser: currentUser?.is_superuser, + isSuperuser: currentUser?.isSuperuser, }), - [currentUser?.id, currentUser?.is_superuser], + [currentUser?.id, currentUser?.isSuperuser], ) if (items.data.length === 0) { return (

    - +

    - {currentUser?.is_superuser - ? "There aren't any items yet" - : "You don't have any items yet"} + {currentUser?.isSuperuser ? "There aren't any items yet" : "You don't have any items yet"}

    - {currentUser?.is_superuser + {currentUser?.isSuperuser ? 'Create one or wait for users to add their items' : 'Add a new item to get started'}

    diff --git a/frontend/src/routes/user/settings.tsx b/frontend/src/routes/user/settings.tsx index 5e6db8a..20e2ec4 100644 --- a/frontend/src/routes/user/settings.tsx +++ b/frontend/src/routes/user/settings.tsx @@ -1,14 +1,15 @@ +import { AlertCircleIcon } from '@hugeicons/core-free-icons' +import { HugeiconsIcon } from '@hugeicons/react' import { createFileRoute, Link } from '@tanstack/react-router' -import { TriangleAlert } from 'lucide-react' -import ChangePassword from '@/components/form/ChangePassword.tsx' -import DeleteConfirmation from '@/components/form/DeleteConfirmation.tsx' -import UserInformation from '@/components/form/UserInformation.tsx' +import ChangePassword from '@/components/form/ChangePassword' +import DeleteConfirmation from '@/components/form/DeleteConfirmation' +import UserInformation from '@/components/form/UserInformation' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' -import useAuth from '@/lib/hooks/useAuth.ts' +import useAuth from '@/routes/-hooks/hooks/useAuth.ts' const tabsConfig = [ { value: 'my-profile', title: 'My profile', component: UserInformation }, @@ -42,7 +43,7 @@ export const Route = createFileRoute('/user/settings')({ function UserSettings() { const { user: currentUser } = useAuth() const finalTabs = tabsConfig - const defaultTab = currentUser?.force_password_reset ? 'password' : 'my-profile' + const defaultTab = currentUser?.forcePasswordReset ? 'password' : 'my-profile' if (!currentUser) { return null @@ -53,25 +54,25 @@ function UserSettings() {

    User Settings

    - {currentUser.is_superuser && Admin} + {currentUser.isSuperuser && Admin}

    Manage your profile, security settings, and account controls.

    - {currentUser.force_password_reset && ( + {currentUser.forcePasswordReset && ( - + Forced Password Reset Required - Your account has force_password_reset enabled. Update your password now + Your account has forcePasswordReset enabled. Update your password now to continue using all features. )} - {currentUser.is_superuser && ( + {currentUser.isSuperuser && (

    Admin Controls

    diff --git a/frontend/src/components/stories/CENSUS_API_IMPLEMENTATION.md b/frontend/src/stories/CENSUS_API_IMPLEMENTATION.mdx similarity index 98% rename from frontend/src/components/stories/CENSUS_API_IMPLEMENTATION.md rename to frontend/src/stories/CENSUS_API_IMPLEMENTATION.mdx index 72e6901..f2e1760 100644 --- a/frontend/src/components/stories/CENSUS_API_IMPLEMENTATION.md +++ b/frontend/src/stories/CENSUS_API_IMPLEMENTATION.mdx @@ -1,3 +1,7 @@ +import { Meta } from '@storybook/addon-docs/blocks' + + + # Census Data API Implementation ## Overview diff --git a/frontend/src/components/stories/CHAKRA_UI_CARDS.md b/frontend/src/stories/CHAKRA_UI_CARDS.mdx similarity index 99% rename from frontend/src/components/stories/CHAKRA_UI_CARDS.md rename to frontend/src/stories/CHAKRA_UI_CARDS.mdx index f9eab3c..6642177 100644 --- a/frontend/src/components/stories/CHAKRA_UI_CARDS.md +++ b/frontend/src/stories/CHAKRA_UI_CARDS.mdx @@ -1,3 +1,7 @@ +import { Meta } from '@storybook/addon-docs/blocks' + + + # Chakra UI Cards Documentation This documentation covers the implementation and usage of the custom Card component built with Chakra UI v3, along with diff --git a/frontend/src/components/stories/GETTING_STARTED.md b/frontend/src/stories/GETTING_STARTED.mdx similarity index 88% rename from frontend/src/components/stories/GETTING_STARTED.md rename to frontend/src/stories/GETTING_STARTED.mdx index 4a7140f..f63fee6 100644 --- a/frontend/src/components/stories/GETTING_STARTED.md +++ b/frontend/src/stories/GETTING_STARTED.mdx @@ -1,3 +1,7 @@ +import { Meta } from '@storybook/addon-docs/blocks' + + + # Getting Started with Frontend Development ## Quick Start @@ -242,4 +246,19 @@ npm run test npm run generate-client ``` +# Frontend Stories Documentation + +Use the `src/stories` folder for Storybook stories and supporting component docs. + +## Quick links + +1. [Chakra UI cards details](/) +2. [Developer Guide components page](https://opensacorg.github.io/app-capanel-doc/developer-guide/components> +3. [Developer Guide Storybook page](https://opensacorg.github.io/app-capanel-doc/developer-guide/storybook> + +## Source references + +- Card component implementation: `frontend/src/components/ui/card.tsx` +- Storybook stories directory: `frontend/src/components/stories` + Happy coding! 🚀 diff --git a/backend/app/scripts/gcp/functions/__init__.py b/frontend/src/stories/README.md similarity index 100% rename from backend/app/scripts/gcp/functions/__init__.py rename to frontend/src/stories/README.md diff --git a/frontend/src/components/stories/assets/accessibility.png b/frontend/src/stories/assets/accessibility.png similarity index 100% rename from frontend/src/components/stories/assets/accessibility.png rename to frontend/src/stories/assets/accessibility.png diff --git a/frontend/src/components/stories/assets/accessibility.svg b/frontend/src/stories/assets/accessibility.svg similarity index 100% rename from frontend/src/components/stories/assets/accessibility.svg rename to frontend/src/stories/assets/accessibility.svg diff --git a/frontend/src/components/stories/assets/addon-library.png b/frontend/src/stories/assets/addon-library.png similarity index 100% rename from frontend/src/components/stories/assets/addon-library.png rename to frontend/src/stories/assets/addon-library.png diff --git a/frontend/src/components/stories/assets/assets.png b/frontend/src/stories/assets/assets.png similarity index 100% rename from frontend/src/components/stories/assets/assets.png rename to frontend/src/stories/assets/assets.png diff --git a/frontend/src/components/stories/assets/avif-test-image.avif b/frontend/src/stories/assets/avif-test-image.avif similarity index 100% rename from frontend/src/components/stories/assets/avif-test-image.avif rename to frontend/src/stories/assets/avif-test-image.avif diff --git a/frontend/src/components/stories/assets/context.png b/frontend/src/stories/assets/context.png similarity index 100% rename from frontend/src/components/stories/assets/context.png rename to frontend/src/stories/assets/context.png diff --git a/frontend/src/components/stories/assets/discord.svg b/frontend/src/stories/assets/discord.svg similarity index 100% rename from frontend/src/components/stories/assets/discord.svg rename to frontend/src/stories/assets/discord.svg diff --git a/frontend/src/components/stories/assets/docs.png b/frontend/src/stories/assets/docs.png similarity index 100% rename from frontend/src/components/stories/assets/docs.png rename to frontend/src/stories/assets/docs.png diff --git a/frontend/src/components/stories/assets/figma-plugin.png b/frontend/src/stories/assets/figma-plugin.png similarity index 100% rename from frontend/src/components/stories/assets/figma-plugin.png rename to frontend/src/stories/assets/figma-plugin.png diff --git a/frontend/src/components/stories/assets/github.svg b/frontend/src/stories/assets/github.svg similarity index 100% rename from frontend/src/components/stories/assets/github.svg rename to frontend/src/stories/assets/github.svg diff --git a/frontend/src/components/stories/assets/share.png b/frontend/src/stories/assets/share.png similarity index 100% rename from frontend/src/components/stories/assets/share.png rename to frontend/src/stories/assets/share.png diff --git a/frontend/src/components/stories/assets/styling.png b/frontend/src/stories/assets/styling.png similarity index 100% rename from frontend/src/components/stories/assets/styling.png rename to frontend/src/stories/assets/styling.png diff --git a/frontend/src/components/stories/assets/testing.png b/frontend/src/stories/assets/testing.png similarity index 100% rename from frontend/src/components/stories/assets/testing.png rename to frontend/src/stories/assets/testing.png diff --git a/frontend/src/components/stories/assets/theming.png b/frontend/src/stories/assets/theming.png similarity index 100% rename from frontend/src/components/stories/assets/theming.png rename to frontend/src/stories/assets/theming.png diff --git a/frontend/src/components/stories/assets/tutorials.svg b/frontend/src/stories/assets/tutorials.svg similarity index 100% rename from frontend/src/components/stories/assets/tutorials.svg rename to frontend/src/stories/assets/tutorials.svg diff --git a/frontend/src/components/stories/assets/youtube.svg b/frontend/src/stories/assets/youtube.svg similarity index 100% rename from frontend/src/components/stories/assets/youtube.svg rename to frontend/src/stories/assets/youtube.svg diff --git a/frontend/src/stories/button.stories.ts b/frontend/src/stories/button.stories.ts new file mode 100644 index 0000000..a8a85ae --- /dev/null +++ b/frontend/src/stories/button.stories.ts @@ -0,0 +1,90 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { fn } from 'storybook/test' + +import { Button } from '@/components/ui/button' + +const meta = { + title: 'UI/Button', + component: Button, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + variant: { + control: 'select', + options: ['default', 'outline', 'secondary', 'ghost', 'destructive', 'link'], + }, + size: { + control: 'select', + options: ['default', 'xs', 'sm', 'lg', 'icon', 'icon-xs', 'icon-sm', 'icon-lg'], + }, + }, + args: { onClick: fn() }, +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = { + args: { + variant: 'default', + children: 'Button', + }, +} + +export const Outline: Story = { + args: { + variant: 'outline', + children: 'Button', + }, +} + +export const Secondary: Story = { + args: { + variant: 'secondary', + children: 'Button', + }, +} + +export const Ghost: Story = { + args: { + variant: 'ghost', + children: 'Button', + }, +} + +export const Destructive: Story = { + args: { + variant: 'destructive', + children: 'Button', + }, +} + +export const Link: Story = { + args: { + variant: 'link', + children: 'Button', + }, +} + +export const Large: Story = { + args: { + size: 'lg', + children: 'Button', + }, +} + +export const Small: Story = { + args: { + size: 'sm', + children: 'Button', + }, +} + +export const ExtraSmall: Story = { + args: { + size: 'xs', + children: 'Button', + }, +} diff --git a/frontend/src/stories/navbar-d52.stories.tsx b/frontend/src/stories/navbar-d52.stories.tsx new file mode 100644 index 0000000..071880f --- /dev/null +++ b/frontend/src/stories/navbar-d52.stories.tsx @@ -0,0 +1,77 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { + createMemoryHistory, + createRootRoute, + createRouter, + RouterProvider, +} from '@tanstack/react-router' + +import NavbarD52 from '@/components/common/navbar/navbar-D52' + +// Create a mock QueryClient +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + }, +}) + +const meta = { + title: 'layout/Navigation bar', + component: NavbarD52, + parameters: { + layout: 'fullscreen', + }, + decorators: [ + (Story) => { + const rootRoute = createRootRoute({ + component: Story, + }) + const router = createRouter({ + routeTree: rootRoute, + history: createMemoryHistory(), + }) + return ( + + + + ) + }, + ], + tags: ['autodocs'], +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = { + args: { + shadow: false, + }, +} + +export const WithShadow: Story = { + args: { + shadow: true, + }, +} + +export const LoggedIn: Story = { + args: { + shadow: false, + }, + decorators: [ + (Story) => { + queryClient.setQueryData(['currentUser'], { + id: '1', + email: 'jane.doe@example.com', + fullName: 'Jane Doe', + isActive: true, + isSuperuser: false, + }) + return + }, + ], +} diff --git a/frontend/src/stories/project-configuration.stories.tsx b/frontend/src/stories/project-configuration.stories.tsx new file mode 100644 index 0000000..6c352d3 --- /dev/null +++ b/frontend/src/stories/project-configuration.stories.tsx @@ -0,0 +1,206 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import oxfmtConfig from '#.oxfmtrc.jsonc?raw' +import oxlintConfig from '#.oxlintrc.jsonc?raw' +import componentsConfig from '#components.json?raw' +import openapiTsConfig from '#openapi-ts.config.ts?raw' +import playwrightConfig from '#playwright.config.ts?raw' +import tsConfig from '#tsconfig.json?raw' +import viteConfig from '#vite.config.ts?raw' +import vitestConfig from '#vitest.config.ts?raw' + +const viteConfigComments = + viteConfig.match(/\/\*[\s\S]*?\*\/|\/\/.*/g)?.join('\n\n') ?? 'No comments found.' +const tsConfigComments = + tsConfig.match(/\/\*[\s\S]*?\*\/|\/\/.*/g)?.join('\n\n') ?? 'No comments found.' +const oxlintConfigComments = + oxlintConfig.match(/\/\*[\s\S]*?\*\/|\/\/.*/g)?.join('\n\n') ?? 'No comments found.' +const oxfmtConfigComments = + oxfmtConfig.match(/\/\*[\s\S]*?\*\/|\/\/.*/g)?.join('\n\n') ?? 'No comments found.' +const playwrightConfigComments = + playwrightConfig.match(/\/\*[\s\S]*?\*\/|\/\/.*/g)?.join('\n\n') ?? 'No comments found.' +const shadcnComponentsConfigComments = + componentsConfig.match(/\/\*[\s\S]*?\*\/|\/\/.*/g)?.join('\n\n') ?? 'No comments found.' +const openapiTsConfigComments = + openapiTsConfig.match(/\/\*[\s\S]*?\*\/|\/\/.*/g)?.join('\n\n') ?? 'No comments found.' +const vitestConfigComments = + vitestConfig.match(/\/\*[\s\S]*?\*\/|\/\/.*/g)?.join('\n\n') ?? 'No comments found.' + +const meta = { + title: 'Project configuration files', + parameters: { + layout: 'centered', + }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const ViteConfig: Story = { + name: 'vite.config.ts', + render: () => ( +
    +

    Vite Config Documentation

    +
    +				{viteConfigComments}
    +			
    +
    + ), +} + +export const TSConfig: Story = { + name: 'tsconfig.json', + render: () => ( +
    +

    TypeScript Config Documentation

    +
    +				{tsConfigComments}
    +			
    +
    + ), +} + +export const OXLintConfig: Story = { + name: 'oxlint.config.json', + render: () => ( +
    +

    TypeScript Config Documentation

    +
    +				{oxlintConfigComments}
    +			
    +
    + ), +} + +export const OXFmtConfig: Story = { + name: 'oxfmt.config.json', + render: () => ( +
    +

    TypeScript Config Documentation

    +
    +				{oxfmtConfigComments}
    +			
    +
    + ), +} + +export const PlaywrightConfig: Story = { + name: 'playwright.config.ts', + render: () => ( +
    +

    TypeScript Config Documentation

    +
    +				{playwrightConfigComments}
    +			
    +
    + ), +} + +export const VitestConfig: Story = { + name: 'vitest.config.ts', + render: () => ( +
    +

    TypeScript Config Documentation

    +
    +				{vitestConfigComments}
    +			
    +
    + ), +} + +export const ShadcnComponentsConfig: Story = { + name: 'components.json', + render: () => ( +
    +

    TypeScript Config Documentation

    +
    +				{shadcnComponentsConfigComments}
    +			
    +
    + ), +} + +export const OpenAPIConfig: Story = { + name: 'openapi-ts.config.json', + render: () => ( +
    +

    TypeScript Config Documentation

    +
    +				{openapiTsConfigComments}
    +			
    +
    + ), +} diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json new file mode 100644 index 0000000..71ac0a9 --- /dev/null +++ b/frontend/tsconfig.app.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "resolveJsonModule": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + + "paths": { + "@/*": ["./src/*"], + "#.storybook/*": ["./.storybook/*"] + }, + "forceConsistentCasingInFileNames": true + }, + "include": ["src", "vite.config.ts"], + "exclude": ["src/lib/client"] +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 5f0edab..88a659f 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,27 +1,4 @@ { - "compilerOptions": { - "target": "ESNext", - "jsx": "react-jsx", - "module": "ESNext", - "useDefineForClassFields": true, - "lib": ["ESNext", "DOM", "DOM.Iterable"], - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "skipLibCheck": true, - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "paths": { - "@/*": ["./src/*"] - }, - "forceConsistentCasingInFileNames": true, - "allowJs": true, - "allowSyntheticDefaultImports": true - }, - "include": ["src", "vite.config.ts"], - "exclude": ["src/lib/client"] + "files": [], + "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }] } diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json new file mode 100644 index 0000000..eef3e62 --- /dev/null +++ b/frontend/tsconfig.node.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ESNext", + "lib": ["ESNext"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + + "forceConsistentCasingInFileNames": true + }, + "include": ["vite.config.ts"] +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 924a9c1..c7ee505 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -5,7 +5,6 @@ import { devtools } from '@tanstack/devtools-vite' import { tanstackRouter } from '@tanstack/router-plugin/vite' import react from '@vitejs/plugin-react' import { defineConfig, loadEnv } from 'vite' -import viteTsConfigPaths from 'vite-tsconfig-paths' const trimTrailingSlash = (value: string): string => value.replace(/\/+$/, '') @@ -20,7 +19,8 @@ const normalizeApiBase = (value: string | undefined): string | undefined => { /** * base: './' is required for relative paths in single-container deployment - * Add a delay to allow the Nitro server to boot in the container. This prevents the "fetch failed" immediately upon starting + * Add a delay to allow the Nitro server to boot in the container. This prevents the "fetch failed" immediately upon starting. + * Keep relative assets for production container builds, but use root base in dev so Vite's React refresh runtime is loaded correctly on routed URLs. */ const config = defineConfig(({ command, mode }) => { const env = loadEnv(mode, process.cwd(), '') @@ -28,13 +28,12 @@ const config = defineConfig(({ command, mode }) => { env.VITE_DEV_PROXY_TARGET || normalizeApiBase(env.VITE_API_URL) || 'http://localhost:8000' return { - // Keep relative assets for production container builds, but use root base - // in dev so Vite's React refresh runtime is loaded correctly on routed URLs. base: command === 'serve' ? '/' : './', build: { outDir: 'dist', }, resolve: { + tsconfigPaths: true, alias: { '@': fileURLToPath(new URL('./src', import.meta.url)), }, @@ -65,12 +64,10 @@ const config = defineConfig(({ command, mode }) => { }, plugins: [ devtools(), - viteTsConfigPaths({ - projects: ['./tsconfig.json'], - }), tailwindcss(), tanstackRouter({ target: 'react', autoCodeSplitting: true }), react({ + // @ts-expect-error This is the official solution from the website. babel: { plugins: ['babel-plugin-react-compiler'], }, diff --git a/frontend/vitest.config.ts b/frontend/vitest.config.ts new file mode 100644 index 0000000..0f37516 --- /dev/null +++ b/frontend/vitest.config.ts @@ -0,0 +1,52 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +import { storybookTest } from '@storybook/addon-vitest/vitest-plugin' +import { playwright } from '@vitest/browser-playwright' +import { defineConfig } from 'vitest/config' + +const dirname = + typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url)) + +/** + * The plugin will run tests for the stories defined in your Storybook config. + * See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest + */ +export default defineConfig({ + build: { + rollupOptions: { + onwarn(warning: any, warn: any) { + if (warning.code === 'MODULE_LEVEL_DIRECTIVE' && warning.message.includes('"use client"')) { + return + } + warn(warning) + }, + }, + }, + test: { + projects: [ + { + extends: true, + plugins: [ + storybookTest({ + configDir: path.join(dirname, '.storybook'), + }), + ], + test: { + name: 'storybook', + browser: { + enabled: true, + headless: true, + provider: playwright({}), + instances: [ + { + browser: 'chromium', + }, + ], + }, + setupFiles: ['.storybook/vitest.setup.ts'], + }, + }, + ], + }, +})