diff --git a/.vscode/settings.json b/.vscode/settings.json index 265989a..ba435c7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1,26 @@ { "editor.codeActionsOnSave": { "source.organizeImports": "always", - "source.fixAll": "always" + "source.fixAll": "always", + "source.fixAll.eslint": "explicit" }, + "editor.suggest.preview": true, + "editor.inlayHints.enabled": "offUnlessPressed", + "javascript.inlayHints.parameterNames.enabled": "all", "editor.formatOnSaveMode": "modificationsIfAvailable", + "eslint.workingDirectories": ["./fuware-fe"], "editor.insertSpaces": true, "editor.tabSize": 2, - "python.analysis.autoImportCompletions": true + "python.analysis.autoImportCompletions": true, + "python.analysis.indexing": true, + "python.analysis.fixAll": ["source.unusedImports"], + "python.analysis.packageIndexDepths": [ + { + "name": "fuware", + "depth": 3, + "includeAllSymbols": false + } + ] + // "python.analysis.extraPaths": ["./fuware"], + // "python.autoComplete.extraPaths": ["./fuware"] } diff --git a/Taskfile.yml b/Taskfile.yml index ad2e949..c9116f5 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -12,10 +12,6 @@ dotenv: - .env - .dev.env tasks: - py:setupdb: - desc: runs it first for init db - cmds: - - poetry run python fuware/db/init_db.py py:dev: desc: runs the backend server cmds: diff --git a/alembic/versions/56750c50a8c3_create_user_and_session_modal.py b/alembic/versions/68d05d045e6e_create_user_table.py similarity index 61% rename from alembic/versions/56750c50a8c3_create_user_and_session_modal.py rename to alembic/versions/68d05d045e6e_create_user_table.py index 66f4e30..f72f08b 100644 --- a/alembic/versions/56750c50a8c3_create_user_and_session_modal.py +++ b/alembic/versions/68d05d045e6e_create_user_table.py @@ -1,8 +1,8 @@ -"""Create User and Session Modal +"""create user table -Revision ID: 56750c50a8c3 +Revision ID: 68d05d045e6e Revises: -Create Date: 2024-05-13 12:36:10.095215 +Create Date: 2024-05-24 04:12:25.599139 """ from typing import Sequence, Union @@ -12,7 +12,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision: str = '56750c50a8c3' +revision: str = '68d05d045e6e' down_revision: Union[str, None] = None branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None @@ -36,27 +36,11 @@ def upgrade() -> None: op.create_index(op.f('ix_users_name'), 'users', ['name'], unique=False) op.create_index(op.f('ix_users_password'), 'users', ['password'], unique=False) op.create_index(op.f('ix_users_username'), 'users', ['username'], unique=True) - op.create_table('session_login', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('session', sa.String(), nullable=False), - sa.Column('user_id', sa.UUID(), nullable=False), - sa.Column('created_at', sa.DateTime(), nullable=True), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.create_index(op.f('ix_session_login_created_at'), 'session_login', ['created_at'], unique=False) - op.create_index(op.f('ix_session_login_session'), 'session_login', ['session'], unique=True) - op.create_index(op.f('ix_session_login_user_id'), 'session_login', ['user_id'], unique=True) # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_session_login_user_id'), table_name='session_login') - op.drop_index(op.f('ix_session_login_session'), table_name='session_login') - op.drop_index(op.f('ix_session_login_created_at'), table_name='session_login') - op.drop_table('session_login') op.drop_index(op.f('ix_users_username'), table_name='users') op.drop_index(op.f('ix_users_password'), table_name='users') op.drop_index(op.f('ix_users_name'), table_name='users') diff --git a/fuware-fe/index copy.html b/fuware-fe/index copy.html deleted file mode 100644 index 0ca60a5..0000000 --- a/fuware-fe/index copy.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - League of legend Skins - - -
- - - diff --git a/fuware-fe/index.html b/fuware-fe/index.html index c5e49ef..d155b08 100644 --- a/fuware-fe/index.html +++ b/fuware-fe/index.html @@ -4,6 +4,10 @@ + Vite + Solid diff --git a/fuware-fe/jsconfig.json b/fuware-fe/jsconfig.json index 44e11aa..c2ef0e3 100644 --- a/fuware-fe/jsconfig.json +++ b/fuware-fe/jsconfig.json @@ -1,15 +1,16 @@ { "extends": "./jsconfig.paths.json", "compilerOptions": { - "module": "ESNext", - "jsx": "preserve", "target": "ESNext", + "module": "ESNext", "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", "resolveJsonModule": true, "isolatedModules": false, "allowJs": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, "skipLibCheck": true } } diff --git a/fuware-fe/package.json b/fuware-fe/package.json index 2a9a454..57314ed 100644 --- a/fuware-fe/package.json +++ b/fuware-fe/package.json @@ -12,7 +12,6 @@ "prettier": "prettier \"src/**/*.{js,jsx}\" --write" }, "dependencies": { - "@hope-ui/solid": "^0.6.7", "@solidjs/router": "^0.13.3", "@stitches/core": "^1.2.8", "@tabler/icons-solidjs": "^3.3.0", @@ -21,13 +20,18 @@ "solid-form-handler": "^1.2.3", "solid-js": "^1.8.15", "solid-styled-components": "^0.28.5", + "solid-toast": "^0.5.0", "yup": "^1.4.0" }, "devDependencies": { - "eslint": "^9.2.0", + "autoprefixer": "^10.4.19", + "daisyui": "^4.11.1", + "eslint": "^8.56.0", "eslint-plugin-solid": "^0.14.0", "lint-staged": "15.2.2", + "postcss": "^8.4.38", "prettier": "3.2.5", + "tailwindcss": "^3.4.3", "vite": "^5.2.0", "vite-plugin-mkcert": "^1.17.5", "vite-plugin-solid": "^2.10.2" diff --git a/fuware-fe/pnpm-lock.yaml b/fuware-fe/pnpm-lock.yaml index 0d5f102..cc4ad0d 100644 --- a/fuware-fe/pnpm-lock.yaml +++ b/fuware-fe/pnpm-lock.yaml @@ -8,9 +8,6 @@ importers: .: dependencies: - '@hope-ui/solid': - specifier: ^0.6.7 - version: 0.6.7(@stitches/core@1.2.8)(solid-js@1.8.17)(solid-transition-group@0.0.10(solid-js@1.8.17)) '@solidjs/router': specifier: ^0.13.3 version: 0.13.3(solid-js@1.8.17) @@ -19,7 +16,7 @@ importers: version: 1.2.8 '@tabler/icons-solidjs': specifier: ^3.3.0 - version: 3.3.0(solid-js@1.8.17) + version: 3.4.0(solid-js@1.8.17) axios: specifier: ^1.6.8 version: 1.6.8(debug@4.3.4) @@ -35,22 +32,37 @@ importers: solid-styled-components: specifier: ^0.28.5 version: 0.28.5(solid-js@1.8.17) + solid-toast: + specifier: ^0.5.0 + version: 0.5.0(solid-js@1.8.17) yup: specifier: ^1.4.0 version: 1.4.0 devDependencies: + autoprefixer: + specifier: ^10.4.19 + version: 10.4.19(postcss@8.4.38) + daisyui: + specifier: ^4.11.1 + version: 4.11.1(postcss@8.4.38) eslint: - specifier: ^9.2.0 - version: 9.2.0 + specifier: ^8.56.0 + version: 8.57.0 eslint-plugin-solid: specifier: ^0.14.0 - version: 0.14.0(eslint@9.2.0)(typescript@5.4.5) + version: 0.14.0(eslint@8.57.0)(typescript@5.4.5) lint-staged: specifier: 15.2.2 version: 15.2.2 + postcss: + specifier: ^8.4.38 + version: 8.4.38 prettier: specifier: 3.2.5 version: 3.2.5 + tailwindcss: + specifier: ^3.4.3 + version: 3.4.3 vite: specifier: ^5.2.0 version: 5.2.11 @@ -63,6 +75,10 @@ importers: packages: + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -316,29 +332,16 @@ packages: resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/eslintrc@3.0.2': - resolution: {integrity: sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/js@9.2.0': - resolution: {integrity: sha512-ESiIudvhoYni+MdsI8oD7skpprZ89qKocwRM2KEvhhBJ9nl5MRh7BXU5GTod7Mdygq+AUl+QzId6iWJKR/wABA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@8.57.0': + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@floating-ui/core@0.6.2': - resolution: {integrity: sha512-jktYRmZwmau63adUG3GKOAVCofBXkk55S/zQ94XOorAHhwqFIOFAy1rSp2N0Wp6/tGbe9V3u/ExlGZypyY17rg==} - - '@floating-ui/dom@0.4.4': - resolution: {integrity: sha512-0Ulu3B/dqQplUUSqnTx0foSrlYuMN+GTtlJWvNJwt6Fr7/PqmlR/Y08o6/+bxDWr6p3roBJRaQ51MDZsNmEhhw==} - - '@hope-ui/solid@0.6.7': - resolution: {integrity: sha512-7zGGy4QbGUC7QhwRnNH8HO0MZFg4jFISlC2cnAMBfFBy272uqQN3PYdTjiIbnpR/4JilUfxCWpFQY+4qslqcIw==} - peerDependencies: - '@stitches/core': ^1.2.8 - solid-js: ^1.4.0 - solid-transition-group: ^0.0.10 - - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + '@humanwhocodes/config-array@0.11.14': + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} '@humanwhocodes/module-importer@1.0.1': @@ -348,9 +351,9 @@ packages: '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - '@humanwhocodes/retry@0.2.4': - resolution: {integrity: sha512-Ttl/jHpxfS3st5sxwICYfk4pOH0WrLI1SpW283GgQL7sCWU7EHIOhX4b4fkIxr3tkfzwg8+FNojtzsIEE7Ecgg==} - engines: {node: '>=18.18'} + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} @@ -434,6 +437,10 @@ packages: '@octokit/types@13.5.0': resolution: {integrity: sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@rollup/rollup-android-arm-eabi@4.17.2': resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==} cpu: [arm] @@ -522,13 +529,13 @@ packages: '@stitches/core@1.2.8': resolution: {integrity: sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg==} - '@tabler/icons-solidjs@3.3.0': - resolution: {integrity: sha512-spOad61pFAE57YGOcPqFN5458TBF0ctZzEfwiVzvLByJbrmuocmgeUmctsmfmdXNQ5yTtyk5NBmelpxQuyFJrA==} + '@tabler/icons-solidjs@3.4.0': + resolution: {integrity: sha512-d8FUhH+/QtTdzQP3D0K0DnDSyH+D+ufMRtU9jhNnKM8+g5TfbVXUxAJKD0v5pWrllmZz0/uutUVcp/baWVHn+g==} peerDependencies: solid-js: ^1.4.7 - '@tabler/icons@3.3.0': - resolution: {integrity: sha512-PLVe9d7b59sKytbx00KgeGhQG3N176Ezv8YMmsnSz4s0ifDzMWlp/h2wEfQZ0ZNe8e377GY2OW6kovUe3Rnd0g==} + '@tabler/icons@3.4.0': + resolution: {integrity: sha512-6gYHXG0xAJgt2KPcTYDqhe3xYoJMTgz/ZfYup4EUHsxzYsz6rBlt8WgavHsGaWckaqH7ApR/epYslfXZjK27yw==} '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -545,22 +552,16 @@ packages: '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/semver@7.5.8': - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - - '@typescript-eslint/scope-manager@7.8.0': - resolution: {integrity: sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==} + '@typescript-eslint/scope-manager@7.9.0': + resolution: {integrity: sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/types@7.8.0': - resolution: {integrity: sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==} + '@typescript-eslint/types@7.9.0': + resolution: {integrity: sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/typescript-estree@7.8.0': - resolution: {integrity: sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==} + '@typescript-eslint/typescript-estree@7.9.0': + resolution: {integrity: sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -568,16 +569,19 @@ packages: typescript: optional: true - '@typescript-eslint/utils@7.8.0': - resolution: {integrity: sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==} + '@typescript-eslint/utils@7.9.0': + resolution: {integrity: sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/visitor-keys@7.8.0': - resolution: {integrity: sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==} + '@typescript-eslint/visitor-keys@7.9.0': + resolution: {integrity: sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ==} engines: {node: ^18.18.0 || >=20.0.0} + '@ungap/structured-clone@1.2.0': + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -615,6 +619,16 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -625,6 +639,13 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.4.19: + resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + axios@1.6.8: resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} @@ -644,6 +665,10 @@ packages: before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -663,8 +688,12 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001617: - resolution: {integrity: sha512-mLyjzNI9I+Pix8zwcrpxEbGlfqOkF9kM3ptzmKNw5tizSyYwMe+nGLTqMK9cO+0E+Bh6TsBxNAaHWEM8xwSsmA==} + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + caniuse-lite@1.0.30001620: + resolution: {integrity: sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==} chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} @@ -678,6 +707,10 @@ packages: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + cli-cursor@4.0.0: resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -710,6 +743,10 @@ packages: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -723,12 +760,25 @@ packages: crypto-js@4.2.0: resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} - csstype@3.0.11: - resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==} + css-selector-tokenizer@0.8.0: + resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + culori@3.3.0: + resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + daisyui@4.11.1: + resolution: {integrity: sha512-obT9CUbQdW6eoHwSeT5VwaRrWlwrM4OT5qlfdJ0oQlSIEYhwnEl2+L2fwu5PioLbitwuMdYC2X8I1cyy8Pf6LQ==} + engines: {node: '>=16.9.0'} + debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -748,16 +798,35 @@ packages: deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - electron-to-chromium@1.4.763: - resolution: {integrity: sha512-k4J8NrtJ9QrvHLRo8Q18OncqBCB7tIUyqxRcJnlonQ0ioHKYB988GcDFF3ZePmnb8eHEopDs/wPHR/iGAFgoUQ==} + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + electron-to-chromium@1.4.773: + resolution: {integrity: sha512-87eHF+h3PlCRwbxVEAw9KtK3v7lWfc/sUDr0W76955AdYTG4bV/k0zrl585Qnj/skRMH2qOSiE+kqMeOQ+LOpw==} emoji-regex@10.3.0: resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + esbuild@0.20.2: resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} engines: {node: '>=12'} @@ -781,26 +850,22 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - eslint-scope@8.0.1: - resolution: {integrity: sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.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.0.0: - resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint@9.2.0: - resolution: {integrity: sha512-0n/I88vZpCOzO+PQpt0lbsqmn9AsnsJAQseIqhZFI8ibQT0U1AkEKRxA3EVMos0BoHSXDQvCXY25TUjB5tr8Og==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true - espree@10.0.1: - resolution: {integrity: sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} @@ -838,12 +903,15 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fastparse@1.1.2: + resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==} + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} @@ -853,16 +921,13 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - focus-trap@6.7.3: - resolution: {integrity: sha512-8xCEKndV4KrseGhFKKKmczVA14yx1/hnmFICPOjcFjToxCJYj/NHH43tPc3YE/PLnLRNZoFug0EcWkGQde/miQ==} - follow-redirects@1.15.6: resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} engines: {node: '>=4.0'} @@ -872,15 +937,28 @@ packages: debug: optional: true + foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -901,13 +979,21 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob@10.3.15: + resolution: {integrity: sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==} + engines: {node: '>=16 || 14 >=14.18'} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} @@ -918,6 +1004,9 @@ packages: peerDependencies: csstype: ^3.0.10 + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -926,6 +1015,10 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + html-entities@2.3.3: resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} @@ -949,13 +1042,30 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + inline-style-parser@0.2.3: resolution: {integrity: sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-fullwidth-code-point@4.0.0: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} engines: {node: '>=12'} @@ -991,6 +1101,14 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + + jiti@1.21.0: + resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} + hasBin: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1030,10 +1148,17 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + lilconfig@3.0.0: resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==} engines: {node: '>=14'} + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lint-staged@15.2.2: resolution: {integrity: sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==} engines: {node: '>=18.12.0'} @@ -1054,6 +1179,10 @@ packages: resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==} engines: {node: '>=18'} + lru-cache@10.2.2: + resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} + engines: {node: 14 || >=16.14} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -1095,9 +1224,16 @@ packages: resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} engines: {node: '>=16 || 14 >=14.17'} + minipass@7.1.1: + resolution: {integrity: sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==} + engines: {node: '>=16 || 14 >=14.17'} + ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1109,10 +1245,26 @@ packages: node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + npm-run-path@5.3.0: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -1144,6 +1296,10 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1152,12 +1308,19 @@ packages: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} + 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-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -1168,6 +1331,51 @@ packages: engines: {node: '>=0.10'} hasBin: true + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.0.1: + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-nested@6.0.1: + resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.0.16: + resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss@8.4.38: resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} @@ -1194,10 +1402,21 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + restore-cursor@4.0.0: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1209,6 +1428,10 @@ packages: rfdc@1.3.1: resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + rollup@4.17.2: resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -1217,9 +1440,6 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - scroll-lock@2.1.5: - resolution: {integrity: sha512-GN8Lp0AzXbkrPFUUNkMUruiiv019UvarNKE/SnXi+AxZRjMnDc2R22VB9RcUtL4P/uub04cKibmpHKIKTyWwYQ==} - semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -1229,14 +1449,14 @@ packages: engines: {node: '>=10'} hasBin: true - seroval-plugins@1.0.5: - resolution: {integrity: sha512-8+pDC1vOedPXjKG7oz8o+iiHrtF2WswaMQJ7CKFpccvSYfrzmvKY9zOJWCg+881722wIHfwkdnRmiiDm9ym+zQ==} + seroval-plugins@1.0.7: + resolution: {integrity: sha512-GO7TkWvodGp6buMEX9p7tNyIkbwlyuAWbI6G9Ec5bhcm7mQdu3JOK1IXbEUwb3FVzSc363GraG/wLW23NSavIw==} engines: {node: '>=10'} peerDependencies: seroval: ^1.0 - seroval@1.0.5: - resolution: {integrity: sha512-TM+Z11tHHvQVQKeNlOUonOWnsNM+2IBwZ4vwoi4j3zKzIpc5IDw8WPwCfcc8F17wy6cBcJGbZbFOR0UCuTZHQA==} + seroval@1.0.7: + resolution: {integrity: sha512-n6ZMQX5q0Vn19Zq7CIKNIo7E75gPkGCFUEqDpa8jgwpYr/vScjqnQ6H09t1uIiZ0ZSK0ypEGvrYK2bhBGWsGdw==} engines: {node: '>=10'} shebang-command@2.0.0: @@ -1284,10 +1504,10 @@ packages: peerDependencies: solid-js: ^1.4.4 - solid-transition-group@0.0.10: - resolution: {integrity: sha512-b3O9z6BUP60CG1WnTdqFuvHms0reDNYwQF+eAEEaSaoDEmiOu9+Lu7zQgWGySJjaAdSAClhmFCmx/eAjQgfIoA==} + solid-toast@0.5.0: + resolution: {integrity: sha512-t770JakjyS2P9b8Qa1zMLOD51KYKWXbTAyJePVUoYex5c5FH5S/HtUBUbZAWFcqRCKmAE8KhyIiCvDZA8bOnxQ==} peerDependencies: - solid-js: ^1.0.0 + solid-js: ^1.5.4 source-map-js@1.2.0: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} @@ -1297,6 +1517,14 @@ packages: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} + string-width@4.2.3: + 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.1.0: resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==} engines: {node: '>=18'} @@ -1320,6 +1548,11 @@ packages: style-to-object@1.0.6: resolution: {integrity: sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==} + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -1328,12 +1561,25 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} - tabbable@5.3.3: - resolution: {integrity: sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tailwindcss@3.4.3: + resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==} + engines: {node: '>=14.0.0'} + hasBin: true text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tiny-case@1.0.3: resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==} @@ -1354,10 +1600,17 @@ packages: peerDependencies: typescript: '>=4.2.0' + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + type-fest@2.19.0: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} @@ -1370,8 +1623,8 @@ packages: universal-user-agent@6.0.1: resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} - update-browserslist-db@1.0.15: - resolution: {integrity: sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA==} + update-browserslist-db@1.0.16: + resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -1379,6 +1632,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + validate-html-nesting@1.2.2: resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==} @@ -1443,6 +1699,14 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + wrap-ansi@9.0.0: resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} engines: {node: '>=18'} @@ -1466,6 +1730,8 @@ packages: snapshots: + '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.5 @@ -1474,7 +1740,7 @@ snapshots: '@babel/code-frame@7.24.2': dependencies: '@babel/highlight': 7.24.5 - picocolors: 1.0.0 + picocolors: 1.0.1 '@babel/compat-data@7.24.4': {} @@ -1570,7 +1836,7 @@ snapshots: '@babel/helper-validator-identifier': 7.24.5 chalk: 2.4.2 js-tokens: 4.0.0 - picocolors: 1.0.0 + picocolors: 1.0.1 '@babel/parser@7.24.5': dependencies: @@ -1677,19 +1943,19 @@ snapshots: '@esbuild/win32-x64@0.20.2': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@9.2.0)': + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': dependencies: - eslint: 9.2.0 + eslint: 8.57.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.10.0': {} - '@eslint/eslintrc@3.0.2': + '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 debug: 4.3.4 - espree: 10.0.1 - globals: 14.0.0 + espree: 9.6.1 + globals: 13.24.0 ignore: 5.3.1 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -1698,26 +1964,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.2.0': {} + '@eslint/js@8.57.0': {} - '@floating-ui/core@0.6.2': {} - - '@floating-ui/dom@0.4.4': - dependencies: - '@floating-ui/core': 0.6.2 - - '@hope-ui/solid@0.6.7(@stitches/core@1.2.8)(solid-js@1.8.17)(solid-transition-group@0.0.10(solid-js@1.8.17))': - dependencies: - '@floating-ui/dom': 0.4.4 - '@stitches/core': 1.2.8 - csstype: 3.0.11 - focus-trap: 6.7.3 - lodash.merge: 4.6.2 - scroll-lock: 2.1.5 - solid-js: 1.8.17 - solid-transition-group: 0.0.10(solid-js@1.8.17) - - '@humanwhocodes/config-array@0.13.0': + '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 debug: 4.3.4 @@ -1729,7 +1978,14 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@humanwhocodes/retry@0.2.4': {} + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 '@jridgewell/gen-mapping@0.3.5': dependencies: @@ -1823,6 +2079,9 @@ snapshots: dependencies: '@octokit/openapi-types': 22.2.0 + '@pkgjs/parseargs@0.11.0': + optional: true + '@rollup/rollup-android-arm-eabi@4.17.2': optional: true @@ -1877,12 +2136,12 @@ snapshots: '@stitches/core@1.2.8': {} - '@tabler/icons-solidjs@3.3.0(solid-js@1.8.17)': + '@tabler/icons-solidjs@3.4.0(solid-js@1.8.17)': dependencies: - '@tabler/icons': 3.3.0 + '@tabler/icons': 3.4.0 solid-js: 1.8.17 - '@tabler/icons@3.3.0': {} + '@tabler/icons@3.4.0': {} '@types/babel__core@7.20.5': dependencies: @@ -1907,21 +2166,17 @@ snapshots: '@types/estree@1.0.5': {} - '@types/json-schema@7.0.15': {} - - '@types/semver@7.5.8': {} - - '@typescript-eslint/scope-manager@7.8.0': + '@typescript-eslint/scope-manager@7.9.0': dependencies: - '@typescript-eslint/types': 7.8.0 - '@typescript-eslint/visitor-keys': 7.8.0 + '@typescript-eslint/types': 7.9.0 + '@typescript-eslint/visitor-keys': 7.9.0 - '@typescript-eslint/types@7.8.0': {} + '@typescript-eslint/types@7.9.0': {} - '@typescript-eslint/typescript-estree@7.8.0(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@7.9.0(typescript@5.4.5)': dependencies: - '@typescript-eslint/types': 7.8.0 - '@typescript-eslint/visitor-keys': 7.8.0 + '@typescript-eslint/types': 7.9.0 + '@typescript-eslint/visitor-keys': 7.9.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -1933,25 +2188,24 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.8.0(eslint@9.2.0)(typescript@5.4.5)': + '@typescript-eslint/utils@7.9.0(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.2.0) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 7.8.0 - '@typescript-eslint/types': 7.8.0 - '@typescript-eslint/typescript-estree': 7.8.0(typescript@5.4.5) - eslint: 9.2.0 - semver: 7.6.2 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 7.9.0 + '@typescript-eslint/types': 7.9.0 + '@typescript-eslint/typescript-estree': 7.9.0(typescript@5.4.5) + eslint: 8.57.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/visitor-keys@7.8.0': + '@typescript-eslint/visitor-keys@7.9.0': dependencies: - '@typescript-eslint/types': 7.8.0 + '@typescript-eslint/types': 7.9.0 eslint-visitor-keys: 3.4.3 + '@ungap/structured-clone@1.2.0': {} + acorn-jsx@5.3.2(acorn@8.11.3): dependencies: acorn: 8.11.3 @@ -1981,12 +2235,31 @@ snapshots: ansi-styles@6.2.1: {} + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@5.0.2: {} + argparse@2.0.1: {} array-union@2.1.0: {} asynckit@0.4.0: {} + autoprefixer@10.4.19(postcss@8.4.38): + dependencies: + browserslist: 4.23.0 + caniuse-lite: 1.0.30001620 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.0.1 + postcss: 8.4.38 + postcss-value-parser: 4.2.0 + axios@1.6.8(debug@4.3.4): dependencies: follow-redirects: 1.15.6(debug@4.3.4) @@ -2013,6 +2286,8 @@ snapshots: before-after-hook@2.2.3: {} + binary-extensions@2.3.0: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -2028,14 +2303,16 @@ snapshots: browserslist@4.23.0: dependencies: - caniuse-lite: 1.0.30001617 - electron-to-chromium: 1.4.763 + caniuse-lite: 1.0.30001620 + electron-to-chromium: 1.4.773 node-releases: 2.0.14 - update-browserslist-db: 1.0.15(browserslist@4.23.0) + update-browserslist-db: 1.0.16(browserslist@4.23.0) callsites@3.1.0: {} - caniuse-lite@1.0.30001617: {} + camelcase-css@2.0.1: {} + + caniuse-lite@1.0.30001620: {} chalk@2.4.2: dependencies: @@ -2050,6 +2327,18 @@ snapshots: chalk@5.3.0: {} + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + cli-cursor@4.0.0: dependencies: restore-cursor: 4.0.0 @@ -2079,6 +2368,8 @@ snapshots: commander@11.1.0: {} + commander@4.1.1: {} + concat-map@0.0.1: {} convert-source-map@2.0.0: {} @@ -2091,10 +2382,26 @@ snapshots: crypto-js@4.2.0: {} - csstype@3.0.11: {} + css-selector-tokenizer@0.8.0: + dependencies: + cssesc: 3.0.0 + fastparse: 1.1.2 + + cssesc@3.0.0: {} csstype@3.1.3: {} + culori@3.3.0: {} + + daisyui@4.11.1(postcss@8.4.38): + dependencies: + css-selector-tokenizer: 0.8.0 + culori: 3.3.0 + picocolors: 1.0.1 + postcss-js: 4.0.1(postcss@8.4.38) + transitivePeerDependencies: + - postcss + debug@4.3.4: dependencies: ms: 2.1.2 @@ -2105,14 +2412,28 @@ snapshots: deprecation@2.3.1: {} + didyoumean@1.2.2: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 - electron-to-chromium@1.4.763: {} + dlv@1.1.3: {} + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.4.773: {} emoji-regex@10.3.0: {} + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + esbuild@0.20.2: optionalDependencies: '@esbuild/aix-ppc64': 0.20.2 @@ -2145,10 +2466,10 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-solid@0.14.0(eslint@9.2.0)(typescript@5.4.5): + eslint-plugin-solid@0.14.0(eslint@8.57.0)(typescript@5.4.5): dependencies: - '@typescript-eslint/utils': 7.8.0(eslint@9.2.0)(typescript@5.4.5) - eslint: 9.2.0 + '@typescript-eslint/utils': 7.9.0(eslint@8.57.0)(typescript@5.4.5) + eslint: 8.57.0 estraverse: 5.3.0 is-html: 2.0.0 kebab-case: 1.0.2 @@ -2158,43 +2479,45 @@ snapshots: - supports-color - typescript - eslint-scope@8.0.1: + eslint-scope@7.2.2: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 eslint-visitor-keys@3.4.3: {} - eslint-visitor-keys@4.0.0: {} - - eslint@9.2.0: + eslint@8.57.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.2.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.10.0 - '@eslint/eslintrc': 3.0.2 - '@eslint/js': 9.2.0 - '@humanwhocodes/config-array': 0.13.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.2.4 '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 debug: 4.3.4 + doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 8.0.1 - eslint-visitor-keys: 4.0.0 - espree: 10.0.1 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 + file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 ignore: 5.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 + js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 @@ -2206,11 +2529,11 @@ snapshots: transitivePeerDependencies: - supports-color - espree@10.0.1: + espree@9.6.1: dependencies: acorn: 8.11.3 acorn-jsx: 5.3.2(acorn@8.11.3) - eslint-visitor-keys: 4.0.0 + eslint-visitor-keys: 3.4.3 esquery@1.5.0: dependencies: @@ -2252,13 +2575,15 @@ snapshots: fast-levenshtein@2.0.6: {} + fastparse@1.1.2: {} + fastq@1.17.1: dependencies: reusify: 1.0.4 - file-entry-cache@8.0.0: + file-entry-cache@6.0.1: dependencies: - flat-cache: 4.0.1 + flat-cache: 3.2.0 fill-range@7.0.1: dependencies: @@ -2269,30 +2594,38 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - flat-cache@4.0.1: + flat-cache@3.2.0: dependencies: flatted: 3.3.1 keyv: 4.5.4 + rimraf: 3.0.2 flatted@3.3.1: {} - focus-trap@6.7.3: - dependencies: - tabbable: 5.3.3 - follow-redirects@1.15.6(debug@4.3.4): optionalDependencies: debug: 4.3.4 + foreground-child@3.1.1: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + form-data@4.0.0: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 + fraction.js@4.3.7: {} + + fs.realpath@1.0.0: {} + fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + gensync@1.0.0-beta.2: {} get-east-asian-width@1.2.0: {} @@ -2307,9 +2640,28 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.3.15: + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.4 + minipass: 7.1.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + globals@11.12.0: {} - globals@14.0.0: {} + globals@13.24.0: + dependencies: + type-fest: 0.20.2 globby@11.1.0: dependencies: @@ -2324,10 +2676,16 @@ snapshots: dependencies: csstype: 3.1.3 + graphemer@1.4.0: {} + has-flag@3.0.0: {} has-flag@4.0.0: {} + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + html-entities@2.3.3: {} html-tags@3.3.1: {} @@ -2343,10 +2701,27 @@ snapshots: imurmurhash@0.1.4: {} + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + inline-style-parser@0.2.3: {} + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-core-module@2.13.1: + dependencies: + hasown: 2.0.2 + is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@4.0.0: {} is-fullwidth-code-point@5.0.0: @@ -2371,6 +2746,14 @@ snapshots: isexe@2.0.0: {} + jackspeak@2.3.6: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jiti@1.21.0: {} + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -2400,8 +2783,12 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lilconfig@2.1.0: {} + lilconfig@3.0.0: {} + lines-and-columns@1.2.4: {} + lint-staged@15.2.2: dependencies: chalk: 5.3.0 @@ -2440,6 +2827,8 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 9.0.0 + lru-cache@10.2.2: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -2475,18 +2864,34 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minipass@7.1.1: {} + ms@2.1.2: {} + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nanoid@3.3.7: {} natural-compare@1.4.0: {} node-releases@2.0.14: {} + normalize-path@3.0.0: {} + + normalize-range@0.1.2: {} + npm-run-path@5.3.0: dependencies: path-key: 4.0.0 + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -2522,22 +2927,66 @@ snapshots: path-exists@4.0.0: {} + path-is-absolute@1.0.1: {} + path-key@3.1.1: {} path-key@4.0.0: {} + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.2.2 + minipass: 7.1.1 + path-type@4.0.0: {} - picocolors@1.0.0: {} + picocolors@1.0.1: {} picomatch@2.3.1: {} pidtree@0.6.0: {} + pify@2.3.0: {} + + pirates@4.0.6: {} + + postcss-import@15.1.0(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + + postcss-js@4.0.1(postcss@8.4.38): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.38 + + postcss-load-config@4.0.2(postcss@8.4.38): + dependencies: + lilconfig: 3.0.0 + yaml: 2.3.4 + optionalDependencies: + postcss: 8.4.38 + + postcss-nested@6.0.1(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + postcss-selector-parser: 6.0.16 + + postcss-selector-parser@6.0.16: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + postcss@8.4.38: dependencies: nanoid: 3.3.7 - picocolors: 1.0.0 + picocolors: 1.0.1 source-map-js: 1.2.0 prelude-ls@1.2.1: {} @@ -2552,8 +3001,22 @@ snapshots: queue-microtask@1.2.3: {} + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + resolve-from@4.0.0: {} + resolve@1.22.8: + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@4.0.0: dependencies: onetime: 5.1.2 @@ -2563,6 +3026,10 @@ snapshots: rfdc@1.3.1: {} + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + rollup@4.17.2: dependencies: '@types/estree': 1.0.5 @@ -2589,17 +3056,15 @@ snapshots: dependencies: queue-microtask: 1.2.3 - scroll-lock@2.1.5: {} - semver@6.3.1: {} semver@7.6.2: {} - seroval-plugins@1.0.5(seroval@1.0.5): + seroval-plugins@1.0.7(seroval@1.0.7): dependencies: - seroval: 1.0.5 + seroval: 1.0.7 - seroval@1.0.5: {} + seroval@1.0.7: {} shebang-command@2.0.0: dependencies: @@ -2630,8 +3095,8 @@ snapshots: solid-js@1.8.17: dependencies: csstype: 3.1.3 - seroval: 1.0.5 - seroval-plugins: 1.0.5(seroval@1.0.5) + seroval: 1.0.7 + seroval-plugins: 1.0.7(seroval@1.0.7) solid-refresh@0.6.3(solid-js@1.8.17): dependencies: @@ -2646,7 +3111,7 @@ snapshots: goober: 2.1.14(csstype@3.1.3) solid-js: 1.8.17 - solid-transition-group@0.0.10(solid-js@1.8.17): + solid-toast@0.5.0(solid-js@1.8.17): dependencies: solid-js: 1.8.17 @@ -2654,6 +3119,18 @@ snapshots: string-argv@0.3.2: {} + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + 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.1.0 + string-width@7.1.0: dependencies: emoji-regex: 10.3.0 @@ -2676,6 +3153,16 @@ snapshots: dependencies: inline-style-parser: 0.2.3 + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + commander: 4.1.1 + glob: 10.3.15 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -2684,10 +3171,45 @@ snapshots: dependencies: has-flag: 4.0.0 - tabbable@5.3.3: {} + supports-preserve-symlinks-flag@1.0.0: {} + + tailwindcss@3.4.3: + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.0 + lilconfig: 2.1.0 + micromatch: 4.0.5 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.1 + postcss: 8.4.38 + postcss-import: 15.1.0(postcss@8.4.38) + postcss-js: 4.0.1(postcss@8.4.38) + postcss-load-config: 4.0.2(postcss@8.4.38) + postcss-nested: 6.0.1(postcss@8.4.38) + postcss-selector-parser: 6.0.16 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node text-table@0.2.0: {} + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + tiny-case@1.0.3: {} to-fast-properties@2.0.0: {} @@ -2702,26 +3224,32 @@ snapshots: dependencies: typescript: 5.4.5 + ts-interface-checker@0.1.13: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 + type-fest@0.20.2: {} + type-fest@2.19.0: {} typescript@5.4.5: {} universal-user-agent@6.0.1: {} - update-browserslist-db@1.0.15(browserslist@4.23.0): + update-browserslist-db@1.0.16(browserslist@4.23.0): dependencies: browserslist: 4.23.0 escalade: 3.1.2 - picocolors: 1.0.0 + picocolors: 1.0.1 uri-js@4.4.1: dependencies: punycode: 2.3.1 + util-deprecate@1.0.2: {} + validate-html-nesting@1.2.2: {} vite-plugin-mkcert@1.17.5(vite@5.2.11): @@ -2729,7 +3257,7 @@ snapshots: '@octokit/rest': 20.1.1 axios: 1.6.8(debug@4.3.4) debug: 4.3.4 - picocolors: 1.0.0 + picocolors: 1.0.1 vite: 5.2.11 transitivePeerDependencies: - supports-color @@ -2765,6 +3293,18 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + wrap-ansi@9.0.0: dependencies: ansi-styles: 6.2.1 diff --git a/fuware-fe/postcss.config.js b/fuware-fe/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/fuware-fe/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/fuware-fe/public/images/bg-login.jpg b/fuware-fe/public/images/bg-login.jpg new file mode 100644 index 0000000..8fedf82 Binary files /dev/null and b/fuware-fe/public/images/bg-login.jpg differ diff --git a/fuware-fe/public/images/logo_fuware.png b/fuware-fe/public/images/logo-fuware.png similarity index 100% rename from fuware-fe/public/images/logo_fuware.png rename to fuware-fe/public/images/logo-fuware.png diff --git a/fuware-fe/src/App.jsx b/fuware-fe/src/App.jsx index 12bf011..7dc2628 100644 --- a/fuware-fe/src/App.jsx +++ b/fuware-fe/src/App.jsx @@ -1,14 +1,19 @@ -import { HopeProvider, NotificationsProvider } from '@hope-ui/solid' +import { Toaster } from 'solid-toast' import './App.css' import { SiteContextProvider } from './context/SiteContext' function App(props) { return ( - - - {props.children} - - + + = 0 + ? null + : { 'margin-top': '60px' } + } + /> + {props.children} + ) } diff --git a/fuware-fe/src/api/auth.js b/fuware-fe/src/api/auth.js index 7f0f9b2..f28cc87 100644 --- a/fuware-fe/src/api/auth.js +++ b/fuware-fe/src/api/auth.js @@ -1,5 +1,5 @@ import { protocol } from './index' -import { POST_LOGIN, POST_LOGOUT } from './url' +import { POST_LOGIN, POST_LOGOUT, POST_REFRESH } from './url' export const postLogin = (payload) => { return protocol.post(POST_LOGIN, payload) @@ -8,3 +8,7 @@ export const postLogin = (payload) => { export const getLogout = () => { return protocol.get(POST_LOGOUT, {}) } + +export const refreshToken = () => { + return protocol.get(POST_REFRESH, {}) +} diff --git a/fuware-fe/src/api/feature.js b/fuware-fe/src/api/feature.js deleted file mode 100644 index 42d4ca0..0000000 --- a/fuware-fe/src/api/feature.js +++ /dev/null @@ -1,6 +0,0 @@ -import { protocol } from './index' -import { GET_DATE } from './url' - -export const getWebData = (payload) => { - return protocol.get(`${GET_DATE}?url=${payload}`, {}) -} diff --git a/fuware-fe/src/api/index.js b/fuware-fe/src/api/index.js index 9fdf12f..ee226b4 100644 --- a/fuware-fe/src/api/index.js +++ b/fuware-fe/src/api/index.js @@ -1,20 +1,37 @@ +import { LOGIN_KEY } from '@utils/enum' import axios from 'axios' import { Helpers } from '../utils/helper' +import { refreshToken } from './auth' const protocol = axios.create({ baseURL: '/', }) const forceLogout = () => { - Helpers.clearCookie() + Helpers.clearStorage() window.location.href = '/login' } -protocol.interceptors.request.use(function (config) { +protocol.interceptors.request.use(async (config) => { config.headers.set( 'Content-Type', config.headers.get('Content-Type') ?? 'application/json', ) + + if ( + config.url.indexOf('/login') >= 0 || + config.url.indexOf('/refresh') >= 0 + ) { + return config + } + + const { accessToken, exp } = await JSON.parse( + Helpers.decrypt(localStorage.getItem(LOGIN_KEY)), + ) + if (accessToken && !Helpers.checkTokenExpired(exp)) { + config.headers.set('Authorization', `Bearer ${accessToken}`) + } + return config }) @@ -22,11 +39,36 @@ protocol.interceptors.response.use( (response) => { return response.data || {} }, - (error) => { + async (error) => { const { response: { status, data }, + config, } = error + if ( + config.url.indexOf('/login') >= 0 || + config.url.indexOf('/refresh') >= 0 + ) { + return Promise.reject(data) + } + + if (status === 401 && !config._retry) { + config._retry = true + try { + // call refresh token + const resp = await refreshToken() + if (resp.status === 200) { + const { data } = resp + localStorage.setItem(LOGIN_KEY, Helpers.encrypt(JSON.stringify(data))) + + config.headers['Authorization'] = `Bearer ${data.accessToken}` + return protocol(config) + } + } catch (error) { + forceLogout() + return Promise.reject(error) + } + } if (status === 403) { forceLogout() } diff --git a/fuware-fe/src/api/url.js b/fuware-fe/src/api/url.js index b8ebcfb..7845825 100644 --- a/fuware-fe/src/api/url.js +++ b/fuware-fe/src/api/url.js @@ -1,3 +1,4 @@ export const POST_LOGIN = '/api/auth/login' export const POST_LOGOUT = '/api/auth/logout' -export const GET_DATE = '/api/user/get-data/' +export const POST_REFRESH = '/api/auth/refresh' +export const GET_USER_PROFILE = '/api/user/me' diff --git a/fuware-fe/src/api/user.js b/fuware-fe/src/api/user.js new file mode 100644 index 0000000..02c97db --- /dev/null +++ b/fuware-fe/src/api/user.js @@ -0,0 +1,6 @@ +import { protocol } from './index' +import { GET_USER_PROFILE } from './url' + +export const getProfile = () => { + return protocol.get(GET_USER_PROFILE, {}) +} diff --git a/fuware-fe/src/assets/logo-fuware.svg b/fuware-fe/src/assets/logo-fuware.svg new file mode 100644 index 0000000..d7859b3 --- /dev/null +++ b/fuware-fe/src/assets/logo-fuware.svg @@ -0,0 +1,585 @@ + + + + + + + + diff --git a/fuware-fe/src/components/Header.jsx b/fuware-fe/src/components/Header.jsx index 9b11a6b..8f07525 100644 --- a/fuware-fe/src/components/Header.jsx +++ b/fuware-fe/src/components/Header.jsx @@ -1,34 +1,38 @@ -import { getLogout } from '@api/auth' -import solidLogo from '@assets/solid.svg' +import { getProfile } from '@api/user' +import fuwareLogo from '@assets/logo-fuware.svg' import { useSiteContext } from '@context/SiteContext' -import useLanguage from '@hooks/useLanguage' -import { - Avatar, - AvatarBadge, - Button, - Flex, - Spacer, - Text, - notificationService, -} from '@hope-ui/solid' -import { A, useNavigate } from '@solidjs/router' -import { Helpers } from '@utils/helper' -import { Show } from 'solid-js' +import useAuth from '@hooks/useAuth' +import useToast from '@hooks/useToast' +import { A } from '@solidjs/router' +import { IconLogout, IconMenuDeep } from '@tabler/icons-solidjs' +import { Show, onMount } from 'solid-js' import { css } from 'solid-styled-components' export default function Header() { - const { store, setAuth } = useSiteContext() - const navigate = useNavigate() - const language = useLanguage() + const { store, setAuth, setUser } = useSiteContext() + const { clickLogOut } = useAuth(setAuth) + const notify = useToast() + + onMount(async () => { + try { + const resp = await getProfile() + if (resp.status === 200) { + setUser(resp.data) + } + } catch (error) { + notify.error({ + title: 'Get profile fail!', + closable: false, + description: error?.data || 'Can not get user profile!', + }) + } + }) const logOut = async () => { try { - await getLogout() - Helpers.clearCookie() - setAuth({ auth: false, user: null }) - navigate('/login', { replace: false }) + await clickLogOut() } catch (error) { - notificationService.show({ + console.log({ status: 'danger', title: 'Logout fail!', closable: false, @@ -37,41 +41,48 @@ export default function Header() { } return ( -
- - - Solid logo - - - - - - - - +
+
+ + +
+ +
+
+
) } diff --git a/fuware-fe/src/components/Navbar.jsx b/fuware-fe/src/components/Navbar.jsx new file mode 100644 index 0000000..d783112 --- /dev/null +++ b/fuware-fe/src/components/Navbar.jsx @@ -0,0 +1,75 @@ +// import { styled } from 'solid-styled-components' + +import { useSiteContext } from '@context/SiteContext' +import useAuth from '@hooks/useAuth' +import useLanguage from '@hooks/useLanguage' +import { A } from '@solidjs/router' +import { IconDashboard, IconLogout, IconTriangle } from '@tabler/icons-solidjs' +import { For, Show } from 'solid-js' +import { Dynamic } from 'solid-js/web' + +const language = useLanguage('vi') + +const NAVBAR_ITEM = [ + { + path: '/dashboard', + icon: IconDashboard, + text: language?.ui.dashboard, + }, +] + +export default function Navbar() { + const { store, setAuth } = useSiteContext() + const { clickLogOut } = useAuth(setAuth) + + const logOut = async () => { + try { + await clickLogOut() + } catch (error) { + console.log({ + status: 'danger', + title: 'Logout fail!', + closable: false, + }) + } + } + + return ( +
+
+ ) +} diff --git a/fuware-fe/src/components/Navbar/Navbar.jsx b/fuware-fe/src/components/Navbar/Navbar.jsx deleted file mode 100644 index 652bc69..0000000 --- a/fuware-fe/src/components/Navbar/Navbar.jsx +++ /dev/null @@ -1,34 +0,0 @@ -// import { styled } from 'solid-styled-components' - -import useLanguage from '@hooks/useLanguage' -import { Flex, Icon, Text } from '@hope-ui/solid' -import { A } from '@solidjs/router' -import { IconDashboard } from '@tabler/icons-solidjs' -import { For } from 'solid-js' - -const language = useLanguage('vi') - -const NAVBAR_ITEM = [ - { - path: '/dashboard', - icon: IconDashboard, - text: language?.ui.dashboard, - }, -] - -export default function Navbar() { - return ( - - ) -} diff --git a/fuware-fe/src/components/Navbar/index.js b/fuware-fe/src/components/Navbar/index.js deleted file mode 100644 index e6400ae..0000000 --- a/fuware-fe/src/components/Navbar/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Navbar' diff --git a/fuware-fe/src/components/Notify.jsx b/fuware-fe/src/components/Notify.jsx new file mode 100644 index 0000000..c5fc280 --- /dev/null +++ b/fuware-fe/src/components/Notify.jsx @@ -0,0 +1,62 @@ +import { + IconCircleCheck, + IconFaceIdError, + IconInfoCircle, + IconX, +} from '@tabler/icons-solidjs' +import { Show } from 'solid-js' +import { Dynamic } from 'solid-js/web' + +const STATUS = Object.freeze( + new Proxy( + { + success: { + icon: IconCircleCheck, + color: 'text-green-500', + }, + error: { + icon: IconFaceIdError, + color: 'text-red-500', + }, + info: { + icon: IconInfoCircle, + color: 'text-blue-500', + }, + }, + { + get: (target, prop) => + target[prop] ?? { icon: IconInfoCircle, color: 'text-blue-500' }, + }, + ), +) + +export default function Notify(props) { + return ( +
+
+ +
+
+ +

+ {props.title} +

+
+

+ {props.description} +

+
+ +
+ +
+
+
+ ) +} diff --git a/fuware-fe/src/context/SiteContext.jsx b/fuware-fe/src/context/SiteContext.jsx index c580156..d06841d 100644 --- a/fuware-fe/src/context/SiteContext.jsx +++ b/fuware-fe/src/context/SiteContext.jsx @@ -1,4 +1,4 @@ -import { LOGIN_KEY, STORE_KEY } from '@utils/enum' +import { STORE_KEY } from '@utils/enum' import { Helpers } from '@utils/helper' import { createContext, onMount, useContext } from 'solid-js' import { createStore, produce } from 'solid-js/store' @@ -12,18 +12,17 @@ export function SiteContextProvider(props) { }) onMount(() => { - const checkCookie = Helpers.getCookie(LOGIN_KEY) - if (checkCookie) { - const storeData = Helpers.decrypt(localStorage.getItem(STORE_KEY)) - if (!storeData) return - setStore(storeData) - } else { - localStorage.removeItem(STORE_KEY) - } + const storeData = Helpers.decrypt(localStorage.getItem(STORE_KEY)) + if (!storeData) return + setStore(storeData) }) const setLocalStore = () => { - localStorage.setItem(STORE_KEY, Helpers.encrypt(store)) + if (store.auth) { + localStorage.setItem(STORE_KEY, Helpers.encrypt(store)) + } else { + localStorage.removeItem(STORE_KEY) + } } const setAuth = ({ auth, user }) => { @@ -36,8 +35,16 @@ export function SiteContextProvider(props) { setLocalStore() } + const setUser = (user) => { + setStore( + produce((s) => { + s.userInfo = user + }), + ) + } + return ( - + {props.children} ) diff --git a/fuware-fe/src/hooks/useAuth.js b/fuware-fe/src/hooks/useAuth.js new file mode 100644 index 0000000..e0897f8 --- /dev/null +++ b/fuware-fe/src/hooks/useAuth.js @@ -0,0 +1,41 @@ +import { getLogout, postLogin } from '@api/auth' +import { useNavigate } from '@solidjs/router' +import { LOGIN_KEY } from '@utils/enum' +import { Helpers } from '@utils/helper' + +export default function useAuth(setAuth) { + const navigate = useNavigate() + + const clickLogIn = async (username, password, cbFormReset) => { + const loginData = { + username: username, + password: password, + } + + const resp = await postLogin(loginData) + + if (resp.status === 200) { + const token = resp.data || {} + if (token) { + const { name, ...rest } = token + setAuth({ auth: true, user: { name } }) + localStorage.setItem(LOGIN_KEY, Helpers.encrypt(JSON.stringify(rest))) + } + + cbFormReset() + navigate('/', { replace: true }) + } + } + + const clickLogOut = async () => { + await getLogout() + Helpers.clearStorage() + setAuth({ auth: false, user: null }) + navigate('/login', { replace: false }) + } + + return { + clickLogOut, + clickLogIn, + } +} diff --git a/fuware-fe/src/hooks/useToast.jsx b/fuware-fe/src/hooks/useToast.jsx new file mode 100644 index 0000000..5c35c4b --- /dev/null +++ b/fuware-fe/src/hooks/useToast.jsx @@ -0,0 +1,31 @@ +import Notify from '@components/Notify' +import toast from 'solid-toast' + +export default function useToast() { + const notify = {} + + notify.show = ({ status, title, description, closable = false }) => { + return toast.custom((t) => ( + toast.dismiss(t.id) : null} + /> + )) + } + + notify.success = ({ title, description, closable = false }) => { + return notify.show({ status: 'success', title, description, closable }) + } + + notify.error = ({ title, description, closable = false }) => { + return notify.show({ status: 'error', title, description, closable }) + } + + notify.info = ({ title, description, closable = false }) => { + return notify.show({ status: 'info', title, description, closable }) + } + + return notify +} diff --git a/fuware-fe/src/index.css b/fuware-fe/src/index.css index 5d60db8..f3280de 100644 --- a/fuware-fe/src/index.css +++ b/fuware-fe/src/index.css @@ -1,3 +1,7 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + :root { font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.5; diff --git a/fuware-fe/src/pages/Layout.jsx b/fuware-fe/src/pages/Layout.jsx index 4f20010..cb67749 100644 --- a/fuware-fe/src/pages/Layout.jsx +++ b/fuware-fe/src/pages/Layout.jsx @@ -2,7 +2,7 @@ import Header from '@components/Header' import Navbar from '@components/Navbar' import { useSiteContext } from '@context/SiteContext' import { useNavigate } from '@solidjs/router' -import { onMount, Show } from 'solid-js' +import { onMount } from 'solid-js' export default function Layout(props) { const { store } = useSiteContext() @@ -15,16 +15,17 @@ export default function Layout(props) { }) return ( -
- -
- -
- +
+
+
+
+ +
+
{props.children}
+
- -
{props.children}
+
-
+ ) } diff --git a/fuware-fe/src/pages/Login.jsx b/fuware-fe/src/pages/Login.jsx index e22b321..b47aa3b 100644 --- a/fuware-fe/src/pages/Login.jsx +++ b/fuware-fe/src/pages/Login.jsx @@ -1,17 +1,5 @@ -import { postLogin } from '@api/auth' import { useSiteContext } from '@context/SiteContext' import useLanguage from '@hooks/useLanguage' -import { - Button, - Center, - FormControl, - FormErrorMessage, - FormLabel, - Heading, - Input, - Stack, - notificationService, -} from '@hope-ui/solid' import { useNavigate } from '@solidjs/router' import { Field, useFormHandler } from 'solid-form-handler' import { yupSchema } from 'solid-form-handler/yup' @@ -19,12 +7,18 @@ import { Show, onMount } from 'solid-js' import { styled } from 'solid-styled-components' import * as yup from 'yup' +import logo from '@assets/logo-fuware.svg' +import useAuth from '@hooks/useAuth' +import useToast from '@hooks/useToast' + const LoginPage = styled('div')` width: 100%; height: 100svh; display: flex; padding-left: 15px; padding-right: 15px; + background: #fff url('/images/bg-login.jpg') no-repeat fixed center; + background-size: cover; place-items: center; .login-wrap { @@ -32,11 +26,51 @@ const LoginPage = styled('div')` max-width: 500px; min-width: 320px; margin: 0 auto; + overflow: hidden; + position: relative; + + &:after { + content: ''; + display: block; + width: 500px; + height: 500px; + border-radius: 15px; + position: absolute; + z-index: 2; + top: -120px; + left: -285px; + background: #10b981; + transform: rotate(45deg); + } + + &:before { + content: ''; + display: block; + width: 500px; + height: 500px; + border-radius: 15px; + position: absolute; + z-index: 2; + top: -40px; + left: -130px; + background: #ff6600; + transform: rotate(20deg); + } + + .card-body { + position: relative; + z-index: 4; + } .logo { + position: relative; + z-index: 4; + display: block; width: 40%; max-width: 150px; min-width: 100px; + margin: 0 auto; + margin-top: 15px; } .login-box { @@ -57,6 +91,8 @@ const language = useLanguage() export default function Login() { const { store, setAuth } = useSiteContext() const navigate = useNavigate() + const { clickLogIn } = useAuth(setAuth) + const notify = useToast() const formHandler = useFormHandler(yupSchema(loginSchema)) const { formData } = formHandler @@ -70,90 +106,115 @@ export default function Login() { event.preventDefault() await formHandler.validateForm() try { - const loginData = { - username: formData()?.username, - password: formData()?.password, - } - - const resp = await postLogin(loginData) - - if (resp.status === 200) { - const user = resp?.data || {} - setAuth({ auth: true, user }) - formHandler.resetForm() - navigate('/', { replace: true }) - } + const { username, password } = formData() + await clickLogIn(username, password, formHandler.resetForm) + notify.success({ + title: 'Login success!', + description: 'Welcome back!', + closable: true, + }) } catch (error) { - notificationService.show({ - status: 'danger', + notify.error({ title: 'Login fail!', - description: error?.data || 'Your username or password input is wrong!', - closable: false, + description: error?.data + ? language.message[error.data] + : 'Your username or password input is wrong!', + closable: true, }) } } return ( - diff --git a/fuware-fe/src/utils/enum.js b/fuware-fe/src/utils/enum.js index 885263d..0c96433 100644 --- a/fuware-fe/src/utils/enum.js +++ b/fuware-fe/src/utils/enum.js @@ -1,5 +1,5 @@ -const PRODUCTION = import.meta.env.NODE_ENV === 'production' +// const PRODUCTION = import.meta.env.NODE_ENV === 'production' export const SECRET_KEY = 'bGV0IGRvIGl0IGZvciBlbmNyeXRo' export const STORE_KEY = 'dXNlciBsb2dpbiBpbmZv' -export const LOGIN_KEY = PRODUCTION ? import.meta.env.VITE_LOGIN_KEY : 'logcook' +export const LOGIN_KEY = '7fo24CMyIc' diff --git a/fuware-fe/src/utils/helper.js b/fuware-fe/src/utils/helper.js index 72293aa..570b48d 100644 --- a/fuware-fe/src/utils/helper.js +++ b/fuware-fe/src/utils/helper.js @@ -2,6 +2,13 @@ import { AES, enc } from 'crypto-js' import { LOGIN_KEY, SECRET_KEY, STORE_KEY } from './enum' export class Helpers { + static setCookie = (cname, cvalue, exdays) => { + const d = new Date() + d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000) + let expires = `expires=${d.toUTCString()}` + document.cookie = `${cname}=${cvalue};${expires};path=/` + } + static getCookie = (cname) => { let name = cname + '=' let ca = document.cookie.split(';') @@ -21,11 +28,16 @@ export class Helpers { document.cookie = `${cname}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;` } - static clearCookie = () => { - this.deleteCookie(LOGIN_KEY) + static clearStorage = () => { + localStorage.removeItem(LOGIN_KEY) localStorage.removeItem(STORE_KEY) } + static checkTokenExpired = (exp) => { + const currentTime = Math.floor(new Date().getTime() / 1000) + return exp < currentTime + } + static checkAuth = () => { return !!this.getCookie(LOGIN_KEY) && !!localStorage.getItem(STORE_KEY) } diff --git a/fuware-fe/tailwind.config.js b/fuware-fe/tailwind.config.js new file mode 100644 index 0000000..b624e18 --- /dev/null +++ b/fuware-fe/tailwind.config.js @@ -0,0 +1,10 @@ +import daisyui from 'daisyui' + +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./src/**/*.{js,jsx}'], + theme: { + extend: {}, + }, + plugins: [daisyui], +} diff --git a/fuware/core/__init__.py b/fuware/core/__init__.py index e69de29..4f329e5 100644 --- a/fuware/core/__init__.py +++ b/fuware/core/__init__.py @@ -0,0 +1 @@ +from .message_code import * diff --git a/fuware/core/dependencies/dependencies.py b/fuware/core/dependencies/dependencies.py index cf579b9..8202e1f 100644 --- a/fuware/core/dependencies/dependencies.py +++ b/fuware/core/dependencies/dependencies.py @@ -1,20 +1,76 @@ -from fastapi import Depends, HTTPException, Request -from sqlalchemy.orm import Session +from fastapi import Depends, HTTPException, Request, status +from fastapi.security import OAuth2PasswordBearer from fuware.core.config import get_app_settings -from fuware.db.db_setup import generate_session +from fuware.core import MessageCode +import jwt +from fuware.services.user.user_service import UserService + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/token") +oauth2_scheme_soft_fail = OAuth2PasswordBearer(tokenUrl="/api/auth/token", auto_error=False) +ALGORITHM = "HS256" settings = get_app_settings() -async def get_auth_user(request: Request, db: Session = Depends(generate_session)): +credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Could not validate credentials", + headers={"WWW-Authenticate": "Bearer"}, +) + +async def is_logged_in(token: str = Depends(oauth2_scheme_soft_fail)) -> bool: + try: + payload = jwt.decode(token, settings.SECRET, algorithms=[ALGORITHM]) + user_id: str = payload.get("sub") + exp: int = payload.get("exp") + + if exp is not None: + try: + user_service = UserService() + user = user_service.get_by_id(user_id) + if not user: + raise credentials_exception + if user.is_lock is True: + raise HTTPException(status_code=status.HTTP_423_LOCKED, detail=MessageCode.ACCOUNT_LOCK) + except Exception: + return credentials_exception + + return user + except Exception: + raise credentials_exception + +async def get_current_user(request: Request, token: str | None = Depends(oauth2_scheme_soft_fail)): """verify that user has a valid session""" - session_id = request.cookies.get(settings.COOKIE_KEY) - if not session_id: - raise HTTPException(status_code=401, detail="Unauthorized") - # decrypt_user = decryptString(session_id).split(',') - # db_user = get_user_by_username(db, decrypt_user[0]) - # if not db_user: - # raise HTTPException(status_code=403) - # if not verify_password(decrypt_user[1], db_user.password): - # raise HTTPException(status_code=401, detail="Your username or password input is wrong!") - return True + if token is None and settings.COOKIE_KEY in request.cookies: + # Try extract from cookie + token = request.cookies.get(settings.COOKIE_KEY, "") + else: + token = token or "" + + try: + payload = jwt.decode(token, settings.SECRET, algorithms=[ALGORITHM]) + user_id: str = payload.get("sub") + exp: int = payload.get("exp") + + if user_id is None or exp is None: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="credentials have expired", + ) + + user_service = UserService() + user = user_service.get_by_id(user_id) + + if not user: + raise credentials_exception + if user.is_lock is True: + raise HTTPException(status_code=status.HTTP_423_LOCKED, detail=MessageCode.ACCOUNT_LOCK) + + return user + except jwt.ExpiredSignatureError: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="credentials have expired", + ) + except Exception: + raise credentials_exception diff --git a/fuware/core/message_code.py b/fuware/core/message_code.py index efb5094..11abb5a 100644 --- a/fuware/core/message_code.py +++ b/fuware/core/message_code.py @@ -1,8 +1,6 @@ -class MessageCode: + +class MessageCode(): CREATED_USER: str = 'CREATED_USER' WRONG_INPUT: str = 'LOGIN_WRONG' ACCOUNT_LOCK: str = 'USER_LOCK' - - -def message_code(): - return MessageCode() + REFRESH_TOKEN_EXPIRED: str = 'REFRESH_TOKEN_EXPIRED' diff --git a/fuware/core/security/__init__.py b/fuware/core/security/__init__.py index 040aee3..cfec0e0 100644 --- a/fuware/core/security/__init__.py +++ b/fuware/core/security/__init__.py @@ -1 +1 @@ -from .hasher import get_hasher +from .security import * diff --git a/fuware/core/security/security.py b/fuware/core/security/security.py new file mode 100644 index 0000000..558bb54 --- /dev/null +++ b/fuware/core/security/security.py @@ -0,0 +1,46 @@ +import secrets +from datetime import datetime, timedelta, timezone +from pathlib import Path + +import jwt + +from fuware.core.config import get_app_settings +from fuware.core import root_logger +from fuware.core.security.hasher import get_hasher + +ALGORITHM = "HS256" + +logger = root_logger.get_logger("security") +settings = get_app_settings() + +def create_access_token(data: dict, expires_delta: timedelta | None = None) -> str: + settings = get_app_settings() + + to_encode = data.copy() + expires_delta = expires_delta or timedelta(minutes=settings.EXP_TOKEN) + + expire = datetime.now(timezone.utc) + expires_delta + + to_encode["exp"] = expire + return jwt.encode(to_encode, settings.SECRET, algorithm=ALGORITHM) + +def create_refresh_token(data: dict) -> str: + return create_access_token(data, expires_delta=timedelta(days=settings.EXP_REFRESH)) + +def create_file_token(file_path: Path) -> str: + token_data = {"file": str(file_path)} + return create_access_token(token_data, expires_delta=timedelta(minutes=30)) + + +def hash_password(password: str) -> str: + """Takes in a raw password and hashes it. Used prior to saving a new password to the database.""" + return get_hasher().hash(password) + + +def url_safe_token() -> str: + """Generates a cryptographic token without embedded data. Used for password reset tokens and invitation tokens""" + return secrets.token_urlsafe(24) + +def verify_token(exp: int): + expried = datetime.fromtimestamp(exp / 1e3) + return expried < datetime.now(timezone.utc) diff --git a/fuware/core/settings/settings.py b/fuware/core/settings/settings.py index ec4901c..63fbb13 100644 --- a/fuware/core/settings/settings.py +++ b/fuware/core/settings/settings.py @@ -7,7 +7,7 @@ def determine_secrets(production: bool) -> str: if not production: return "shh-secret-test-key" - return "oWNhXlfo666JlMHk6UHYxeNB6z_CA2MisDDZJe4N0yc=" + return "1d00e664fb3b07aff5a191755ea72f9c4bc85a3f36868308d0b2c417aed3419e" def determine_cookie(production: bool) -> str: if not production: @@ -31,6 +31,10 @@ class AppSettings(BaseSettings): SECRET: str COOKIE_KEY: str + EXP_TOKEN: int = 30 + """in minutes, default is 30 minutes""" + EXP_REFRESH: int = 7 + """in days, default is 7 days""" LOG_CONFIG_OVERRIDE: Path | None = None """path to custom logging configuration file""" diff --git a/fuware/db/models/users/users.py b/fuware/db/models/users/users.py index 672240d..42aff88 100644 --- a/fuware/db/models/users/users.py +++ b/fuware/db/models/users/users.py @@ -16,19 +16,5 @@ class User(SqlAlchemyBase): is_admin: Mapped[bool | None] = mapped_column(Boolean, default=False) is_lock: Mapped[bool | None] = mapped_column(Boolean, default=False) - session_login = relationship("SessionLogin", back_populates="user", uselist=False) - def __repr__(self): return f"{self.__class__.__name__}, name: {self.name}, username: {self.username}" - -class SessionLogin(SqlAlchemyBase): - __tablename__ = 'session_login' - - id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) - session: Mapped[str] = mapped_column(String, unique=True, index=True, nullable=False) - user_id: Mapped[str] = mapped_column(ForeignKey("users.id"), unique=True, index=True, nullable=False) - - user = relationship("User", back_populates="session_login") - - def __repr__(self): - return f"{self.__class__.__name__}, session: {self.session}, user_id: {self.user_id}" diff --git a/fuware/db/seeder.py b/fuware/db/seeder.py deleted file mode 100644 index 1e28774..0000000 --- a/fuware/db/seeder.py +++ /dev/null @@ -1,28 +0,0 @@ -from fuware.core.security import get_hasher - -hasher = get_hasher() - -INITIAL_DATA = { - 'users': [ - { - 'username': 'sam', - 'password': hasher.hash('admin'), - 'name': 'Sam', - 'is_admin': 1, - 'is_lock': 0, - }, - { - 'username': 'sam1', - 'password': hasher.hash('admin'), - 'name': 'Sam1', - 'is_admin': 0, - 'is_lock': 1 - }, - ] -} - -# This method receives a table, a connection and inserts data to that table. -def initialize_table(target, connection, **kwargs): - tablename = str(target) - if tablename in INITIAL_DATA and len(INITIAL_DATA[tablename]) > 0: - connection.execute(target.insert(), INITIAL_DATA[tablename]) diff --git a/fuware/repos/repository_users.py b/fuware/repos/repository_users.py index fac39ee..443f2d0 100644 --- a/fuware/repos/repository_users.py +++ b/fuware/repos/repository_users.py @@ -1,16 +1,17 @@ from fuware.core.config import get_app_settings -from fuware.core.security.hasher import get_hasher -from fuware.db.models import SessionLogin, User +from fuware.core.security.security import hash_password +from fuware.db.models import User from fuware.schemas import UserCreate from sqlalchemy.orm import Session -from uuid import uuid4 +from uuid import UUID + +from fuware.schemas.user.user import UserSeeds settings = get_app_settings() class RepositoryUsers: def __init__(self): self.user = User() - self.sessionLogin = SessionLogin() def get_all(self, skip: int = 0, limit: int = 100): return self.user.query.offset(skip).limit(limit).all() @@ -18,10 +19,13 @@ class RepositoryUsers: def get_by_username(self, username: str): return self.user.query.filter_by(username=username).first() - def create(self, db: Session, user: UserCreate): + def get_by_id(self, user_id: str): + return self.user.query.filter_by(id=UUID(user_id)).first() + + def create(self, db: Session, user: UserCreate | UserSeeds): try: - hasher = get_hasher() - db_user = User(username=user.username, password=hasher.hash(user.password), name=user.name) + password = getattr(user, "password") + db_user = User(**user.dict(exclude={"password"}), password=hash_password(password)) db.add(db_user) db.commit() except Exception: @@ -30,36 +34,3 @@ class RepositoryUsers: db.refresh(db_user) return db_user - - def get_session_by_user_id(self, user_id: str): - return self.sessionLogin.query.filter_by(user_id=user_id).first() - - def create_session(self, db: Session, user_id: str): - try: - bhash = uuid4().hex[:10] - db_ss = SessionLogin(session=bhash,user_id=user_id) - db.add(db_ss) - db.commit() - except Exception: - db.rollback() - raise - - db.refresh(db_ss) - return db_ss - - def login(self, db: Session, user_id: str): - db_ss = self.get_session_by_user_id(user_id) - if not db_ss: - db_ss = self.create_session(db=db, user_id=user_id) - return db_ss - - def logout(self, db: Session, user_ss: str): - print(f"Logout: {user_ss}") - db_ss = self.sessionLogin.query.filter_by(session=user_ss).first() - print(f"db_ss: {db_ss}") - try: - db.delete(db_ss) - db.commit() - except Exception as e: - db.rollback() - raise e diff --git a/fuware/repos/seeder/init_users.py b/fuware/repos/seeder/init_users.py index 93dfde0..2be0506 100644 --- a/fuware/repos/seeder/init_users.py +++ b/fuware/repos/seeder/init_users.py @@ -3,7 +3,7 @@ from fuware.core.root_logger import get_logger from fuware.repos.repository_users import RepositoryUsers from sqlalchemy.orm import Session -from fuware.schemas.user.user import UserCreate +from fuware.schemas.user import UserSeeds logger = get_logger("init_users") @@ -15,19 +15,19 @@ def dev_users() -> list[dict]: "username": "sam", "password": "admin", "name": "Sam", - "is_admin": 1, - "is_lock": 0, + "is_admin": True, + "is_lock": False, }, { "username": "sam1", "password": "admin", "name": "Sam1", - "is_admin": 0, - "is_lock": 1 + "is_admin": False, + "is_lock": False, }, ] def default_users_init(session: Session): users = RepositoryUsers() for user in dev_users(): - users.create(session, UserCreate(**user)) + users.create(session, UserSeeds(**user)) diff --git a/fuware/routes/__init__.py b/fuware/routes/__init__.py index 5ca2a2d..2b9470e 100644 --- a/fuware/routes/__init__.py +++ b/fuware/routes/__init__.py @@ -1,7 +1,9 @@ from fastapi import APIRouter -from . import (auth) + +from . import (auth, user) router = APIRouter(prefix='/api') router.include_router(auth.router) +router.include_router(user.router) diff --git a/fuware/routes/auth/__init__.py b/fuware/routes/auth/__init__.py index e89c859..4c6c29b 100644 --- a/fuware/routes/auth/__init__.py +++ b/fuware/routes/auth/__init__.py @@ -4,4 +4,4 @@ from . import auth router = APIRouter(prefix='/auth') -router.include_router(auth.public_router) +router.include_router(auth.auth_router) diff --git a/fuware/routes/auth/auth.py b/fuware/routes/auth/auth.py index d946616..314fc65 100644 --- a/fuware/routes/auth/auth.py +++ b/fuware/routes/auth/auth.py @@ -1,43 +1,70 @@ -from typing import Any -from fastapi import APIRouter, Depends, HTTPException, Response, Request +from datetime import datetime, timedelta, timezone +from typing import Annotated, Any +from fastapi import APIRouter, Depends, HTTPException, Response, status -from fastapi.encoders import jsonable_encoder +# from fastapi.encoders import jsonable_encoder +from fastapi.security import OAuth2PasswordRequestForm from sqlalchemy.orm import Session from fuware.core.config import get_app_settings -from fuware.core.message_code import message_code -from fuware.core.security.hasher import get_hasher +from fuware.core.dependencies.dependencies import get_current_user +from fuware.core import MessageCode from fuware.db.db_setup import generate_session -from fuware.schemas import ReturnValue, UserRequest, PrivateUser, UserCreate -from fuware.services import UserService +from fuware.schemas import ReturnValue, UserRequest, LoginResponse, UserCreate, PrivateUser +from fuware.services.user import UserService -public_router = APIRouter(tags=["Users: Authentication"]) +auth_router = APIRouter(tags=["Users: Authentication"]) user_service = UserService() -hasher = get_hasher() settings = get_app_settings() -message = message_code() -@public_router.put('/register') -def register_user(user: UserCreate, db: Session = Depends(generate_session)) -> ReturnValue[Any]: +db_dependency = Annotated[Session, Depends(generate_session)] +current_user_token = Annotated[PrivateUser, Depends(get_current_user)] + +@auth_router.post('/token') +async def get_token(form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db: db_dependency): + user = user_service.check_exist(user=UserRequest(username=form_data.username, password=form_data.password)) + if not user: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=MessageCode.WRONG_INPUT) + token = user_service.get_access_token(user_id=user.id) + return {'access_token': token, 'token_type': 'bearer'} + + +@auth_router.put('/register') +def register_user(user: UserCreate, db: db_dependency) -> ReturnValue[Any]: db_user = user_service.get_by_username(username=user.username) if db_user: - raise HTTPException(status_code=400, detail=message.CREATED_USER) - user_return = user_service.create(db=db, user=user) - return ReturnValue(status=200, data=jsonable_encoder(user_return)) + raise HTTPException(status_code=400, detail=MessageCode.CREATED_USER) + user_service.create(db=db, user=user) + return ReturnValue(status=200, data="created") -@public_router.post('/login', response_model=ReturnValue[PrivateUser]) -def user_login(user: UserRequest, response: Response, db: Session = Depends(generate_session)) -> ReturnValue[Any]: +@auth_router.post('/login', response_model=ReturnValue[LoginResponse]) +def user_login(user: UserRequest, response: Response) -> ReturnValue[Any]: db_user = user_service.check_exist(user=user) - cookieEncode = user_service.check_login(db=db, user_id=db_user.id) - response.set_cookie(key=settings.COOKIE_KEY, value=cookieEncode, max_age=86400, httponly=True) - return ReturnValue(status=200, data=db_user) + if not db_user: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=MessageCode.WRONG_INPUT) + if db_user.is_lock is True: + raise HTTPException(status_code=status.HTTP_423_LOCKED, detail=MessageCode.ACCOUNT_LOCK) + access_token, refresh_token = user_service.generate_token(user_id=db_user.id) + duration_access = datetime.now(timezone.utc) + timedelta(minutes=settings.EXP_TOKEN) + duration_refresh = int(timedelta(days=settings.EXP_REFRESH).total_seconds()) + response.set_cookie( + key=settings.COOKIE_KEY, + value=refresh_token, + max_age=duration_refresh, + expires=duration_refresh, + httponly=True, + samesite="strict", + ) + return ReturnValue(status=200, data=dict(access_token=access_token, exp=int(duration_access.timestamp()), name=db_user.name)) -@public_router.get('/logout', response_model=ReturnValue[Any]) -def user_logout(request: Request, response: Response, db: Session = Depends(generate_session)) -> ReturnValue[Any]: - session_id = request.cookies.get(settings.COOKIE_KEY) - if not session_id: +@auth_router.get('/refresh') +def user_check(current_user: current_user_token) -> ReturnValue[Any]: + access_token = user_service.get_access_token(user_id=current_user.id) + duration_access = datetime.now(timezone.utc) + timedelta(minutes=settings.EXP_TOKEN) + return ReturnValue(status=200, data=dict(accessToken=access_token, exp=int(duration_access.timestamp()))) + +@auth_router.get('/logout') +def user_logout(response: Response, current_user: current_user_token) -> ReturnValue[Any]: + if current_user: response.delete_cookie(key=settings.COOKIE_KEY) - return ReturnValue(status=200, data='Logged out') - user_service.delete_session(db=db, user_ss=session_id) - response.delete_cookie(key=settings.COOKIE_KEY) return ReturnValue(status=200, data='Logged out') diff --git a/fuware/routes/user/__init__.py b/fuware/routes/user/__init__.py new file mode 100644 index 0000000..0200558 --- /dev/null +++ b/fuware/routes/user/__init__.py @@ -0,0 +1,7 @@ + +from fastapi import APIRouter +from . import user + +router = APIRouter(prefix='/user') + +router.include_router(user.public_router) diff --git a/fuware/routes/user/user.py b/fuware/routes/user/user.py new file mode 100644 index 0000000..e864627 --- /dev/null +++ b/fuware/routes/user/user.py @@ -0,0 +1,21 @@ +from typing import Annotated, Any +from fastapi import APIRouter, Depends +from sqlalchemy.orm import Session +from fuware.core.config import get_app_settings +from fuware.core.dependencies import is_logged_in +from fuware.db.db_setup import generate_session +from fuware.schemas.common import ReturnValue +from fuware.schemas.user import ProfileResponse +from fuware.services.user import UserService + + +public_router = APIRouter(tags=["Users: Info"]) +user_service = UserService() +settings = get_app_settings() + +db_dependency = Annotated[Session, Depends(generate_session)] +current_user_token = Annotated[ProfileResponse, Depends(is_logged_in)] + +@public_router.get("/me", response_model=ReturnValue[ProfileResponse]) +def get_user(current_user: current_user_token) -> ReturnValue[Any]: + return ReturnValue(status=200, data=current_user) diff --git a/fuware/schemas/user/user.py b/fuware/schemas/user/user.py index 0a7eb62..bf43af0 100644 --- a/fuware/schemas/user/user.py +++ b/fuware/schemas/user/user.py @@ -12,9 +12,12 @@ class UserRequest(UserBase): password: str = Form(...) class UserCreate(UserRequest): - password: str = Form(...) name: str +class UserSeeds(UserCreate): + is_admin: bool + is_lock: bool + class PrivateUser(UserBase): id: UUID name: str @@ -23,3 +26,16 @@ class PrivateUser(UserBase): created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True) + +class ProfileResponse(UserBase): + name: str + is_admin: bool + is_lock: bool + created_at: datetime + updated_at: datetime + model_config = ConfigDict(from_attributes=True) + +class LoginResponse(FuwareModel): + access_token: str + exp: int + name: str diff --git a/fuware/services/__init__.py b/fuware/services/__init__.py index f4a2da0..e69de29 100644 --- a/fuware/services/__init__.py +++ b/fuware/services/__init__.py @@ -1 +0,0 @@ -from .user import * diff --git a/fuware/services/user/user_service.py b/fuware/services/user/user_service.py index 0e65323..9377cea 100644 --- a/fuware/services/user/user_service.py +++ b/fuware/services/user/user_service.py @@ -1,15 +1,11 @@ - -from fastapi import HTTPException from sqlalchemy.orm import Session -from fuware.core.message_code import message_code from fuware.core.security.hasher import get_hasher +from fuware.core.security import create_access_token +from fuware.core.security.security import create_refresh_token from fuware.repos import RepositoryUsers from fuware.schemas import UserRequest, UserCreate from fuware.services._base_service import BaseService -hasher = get_hasher() -message = message_code() - class UserService(BaseService): def __init__(self): self.repos = RepositoryUsers() @@ -20,22 +16,24 @@ class UserService(BaseService): def get_by_username(self, username: str): return self.repos.get_by_username(username) + def get_by_id(self, user_id: str): + return self.repos.get_by_id(user_id) + def create(self, db: Session, user: UserCreate): return self.repos.create(db=db, user=user) def check_exist(self, user: UserRequest): db_user = self.get_by_username(username=user.username) if not db_user: - raise HTTPException(status_code=401, detail=message.WRONG_INPUT) - if not hasher.verify(password=user.password, hashed=db_user.password): - raise HTTPException(status_code=401, detail=message.WRONG_INPUT) - if db_user.is_lock is True: - raise HTTPException(status_code=401, detail=message.ACCOUNT_LOCK) + return False + if not get_hasher().verify(password=user.password, hashed=db_user.password): + return False return db_user - def check_login(self, db: Session, user_id: str): - db_session = self.repos.login(db=db, user_id=user_id) - return db_session.session + def generate_token(self, user_id: str): + access_token = create_access_token(data={"sub": str(user_id)}) + refresh_token = create_refresh_token(data={"sub": str(user_id)}) + return access_token, refresh_token - def delete_session(self, db: Session, user_ss: str): - self.repos.logout(db=db, user_ss=user_ss) + def get_access_token(self, user_id: str): + return create_access_token(data={"sub": str(user_id)}) diff --git a/poetry.lock b/poetry.lock index 0d55904..e5d40fc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -784,6 +784,23 @@ files = [ {file = "pyhumps-3.8.0.tar.gz", hash = "sha256:498026258f7ee1a8e447c2e28526c0bea9407f9a59c03260aee4bd6c04d681a3"}, ] +[[package]] +name = "pyjwt" +version = "2.8.0" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, + {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, +] + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + [[package]] name = "pylint" version = "3.1.0" @@ -827,6 +844,20 @@ files = [ [package.extras] cli = ["click (>=5.0)"] +[[package]] +name = "python-multipart" +version = "0.0.9" +description = "A streaming multipart parser for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"}, + {file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"}, +] + +[package.extras] +dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"] + [[package]] name = "pyyaml" version = "6.0.1" @@ -1331,4 +1362,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "88c334ca5304e6f095e81628512c132bb419f9ee5bb7e1e278a0b9d5f94b84c5" +content-hash = "4763f2b3b35e1b674b8636d573beb91e38da9e4a2b52634e6c6840dbca49f538" diff --git a/pyproject.toml b/pyproject.toml index 46beb45..5ce63f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,8 @@ text-unidecode = "^1.3" pyhumps = "^3.8.0" bcrypt = "^4.1.3" alembic = "^1.13.1" +python-multipart = "^0.0.9" +pyjwt = "^2.8.0" [tool.poetry.group.dev.dependencies] ruff = "^0.4.1"