From c8033fe3d7c77e082e81f2acca40f2380136436e Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Fri, 5 Dec 2025 15:37:23 +0800 Subject: [PATCH 01/94] created profiles and login/logout --- server/user_profile/permissions.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 server/user_profile/permissions.py diff --git a/server/user_profile/permissions.py b/server/user_profile/permissions.py new file mode 100644 index 0000000..610172a --- /dev/null +++ b/server/user_profile/permissions.py @@ -0,0 +1,10 @@ +from django.contrib.auth import get_user_model +from rest_framework import permissions + +User = get_user_model() + +class isUserOrReadOnly(permissions.BasePermission): + def has_object_permission(self, request, view, obj): + if isinstance(obj, User): + return obj == request.user + return obj.user == request.user From 12fe2a2e3441c00741fb4a6c1bf80e154bdecd37 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Fri, 5 Dec 2025 15:40:07 +0800 Subject: [PATCH 02/94] django workshop initial --- client/package-lock.json | 16 ----------- server/pyproject.toml | 1 + server/server/settings.py | 7 +++++ server/server/urls.py | 5 ++++ server/user_profile/__init__.py | 0 server/user_profile/admin.py | 7 +++++ server/user_profile/apps.py | 6 +++++ .../user_profile/migrations/0001_initial.py | 26 ++++++++++++++++++ server/user_profile/migrations/__init__.py | 0 server/user_profile/models.py | 21 +++++++++++++++ server/user_profile/serializers.py | 21 +++++++++++++++ server/user_profile/tests.py | 3 +++ server/user_profile/urls.py | 10 +++++++ server/user_profile/views.py | 27 +++++++++++++++++++ server/uv.lock | 25 +++++++++++++++++ 15 files changed, 159 insertions(+), 16 deletions(-) create mode 100644 server/user_profile/__init__.py create mode 100644 server/user_profile/admin.py create mode 100644 server/user_profile/apps.py create mode 100644 server/user_profile/migrations/0001_initial.py create mode 100644 server/user_profile/migrations/__init__.py create mode 100644 server/user_profile/models.py create mode 100644 server/user_profile/serializers.py create mode 100644 server/user_profile/tests.py create mode 100644 server/user_profile/urls.py create mode 100644 server/user_profile/views.py diff --git a/client/package-lock.json b/client/package-lock.json index 46f7ac1..f9648a0 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -145,7 +145,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -169,7 +168,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -1382,7 +1380,6 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.80.7.tgz", "integrity": "sha512-u2F0VK6+anItoEvB3+rfvTO9GEh2vb00Je05OwlUe/A0lkJBgW1HckiY3f9YZa+jx6IOe4dHPh10dyp9aY3iRQ==", "license": "MIT", - "peer": true, "dependencies": { "@tanstack/query-core": "5.80.7" }, @@ -1448,7 +1445,6 @@ "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -1469,7 +1465,6 @@ "integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.34.1", "@typescript-eslint/types": "8.34.1", @@ -1674,7 +1669,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2116,7 +2110,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001718", "electron-to-chromium": "^1.5.160", @@ -2853,7 +2846,6 @@ "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -3059,7 +3051,6 @@ "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -4558,7 +4549,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -5483,7 +5473,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5589,7 +5578,6 @@ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -5732,7 +5720,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -5742,7 +5729,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -6607,7 +6593,6 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "license": "MIT", - "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -6862,7 +6847,6 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/server/pyproject.toml b/server/pyproject.toml index d34292d..8850f7e 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -12,6 +12,7 @@ dependencies = [ "gunicorn~=23.0", "python-dotenv~=1.0", "psycopg[binary,pool]~=3.2.13", + "djangorestframework-simplejwt>=5.5.1", ] [dependency-groups] diff --git a/server/server/settings.py b/server/server/settings.py index af546bb..fb856da 100644 --- a/server/server/settings.py +++ b/server/server/settings.py @@ -48,6 +48,7 @@ "rest_framework", "corsheaders", "healthcheck", + "user_profile", ] MIDDLEWARE = [ @@ -70,6 +71,12 @@ ROOT_URLCONF = "server.urls" +REST_FRAMEWORK = { + "DEFAULT_AUTHENTICATION_CLASSES": ( + "rest_framework.authentication.SessionAuthentication", + "rest_framework_simplejwt.authentication.JWTAuthentication", + ), +} TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", diff --git a/server/server/urls.py b/server/server/urls.py index dd710be..a4cf80a 100644 --- a/server/server/urls.py +++ b/server/server/urls.py @@ -17,8 +17,13 @@ from django.contrib import admin from django.urls import include, path +from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView urlpatterns = [ path("admin/", admin.site.urls), + path("api-auth/", include("rest_framework.urls")), + path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), + path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh_view"), path("api/healthcheck/", include("healthcheck.urls")), + path("api/user/", include("user_profile.urls")), ] diff --git a/server/user_profile/__init__.py b/server/user_profile/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/user_profile/admin.py b/server/user_profile/admin.py new file mode 100644 index 0000000..8cbd2d1 --- /dev/null +++ b/server/user_profile/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin + +from .models import Profile + +# Register your models here. + +admin.site.register(Profile) diff --git a/server/user_profile/apps.py b/server/user_profile/apps.py new file mode 100644 index 0000000..fe0436b --- /dev/null +++ b/server/user_profile/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class UserProfileConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'user_profile' diff --git a/server/user_profile/migrations/0001_initial.py b/server/user_profile/migrations/0001_initial.py new file mode 100644 index 0000000..c9d3a2d --- /dev/null +++ b/server/user_profile/migrations/0001_initial.py @@ -0,0 +1,26 @@ +# Generated by Django 5.2.8 on 2025-11-29 06:32 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('bio', models.TextField()), + ('age', models.PositiveBigIntegerField(null=True)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/server/user_profile/migrations/__init__.py b/server/user_profile/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/user_profile/models.py b/server/user_profile/models.py new file mode 100644 index 0000000..ddba041 --- /dev/null +++ b/server/user_profile/models.py @@ -0,0 +1,21 @@ +from django.contrib.auth import get_user_model +from django.db import models +from django.db.models.signals import post_save +from django.dispatch import receiver + +User = get_user_model() + +# Create your models here. + +class Profile(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + bio = models.TextField() + age = models.PositiveBigIntegerField(null=True) + + def __str__(self): + return f"Profile: { self.user.username}" + + +@receiver(post_save, sender =User) +def create_or_update_user_profile(sender, instance, created, **kwargs): + Profile.objects.get_or_create(user = instance) diff --git a/server/user_profile/serializers.py b/server/user_profile/serializers.py new file mode 100644 index 0000000..c0c7738 --- /dev/null +++ b/server/user_profile/serializers.py @@ -0,0 +1,21 @@ +from rest_framework import serializers + +from .models import Profile, User + + +class ProfileSerializer(serializers.ModelSerializer): + class Meta: + model = Profile + fields = "__all__" + +class UserSerializer(serializers.ModelSerializer): + profile = ProfileSerializer(read_only = True) + + class Meta: + model = User + fields = ( + "id", + "username", + "email", + "profile" + ) diff --git a/server/user_profile/tests.py b/server/user_profile/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/server/user_profile/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/user_profile/urls.py b/server/user_profile/urls.py new file mode 100644 index 0000000..5811cc5 --- /dev/null +++ b/server/user_profile/urls.py @@ -0,0 +1,10 @@ +from django.urls import path + +from . import views + +app_name = "user_profile" +urlpatterns = [ + path("profile//", views.UserProfileDetail.as_view(), name="profile_detail"), + path("profile/", views.UserProfileList.as_view(), name="profile_list"), + path("user/", views.UserList.as_view(), name="user_list"), +] diff --git a/server/user_profile/views.py b/server/user_profile/views.py new file mode 100644 index 0000000..8bd55e2 --- /dev/null +++ b/server/user_profile/views.py @@ -0,0 +1,27 @@ +from django.shortcuts import render +from rest_framework import generics, permissions +from rest_framework.response import Response +from rest_framework.views import APIView + +from .models import Profile, User +from .permissions import isUserOrReadOnly +from .serializers import ProfileSerializer, UserSerializer + +# Create your views here. + +class UserList(APIView): + permission_classes = (permissions.IsAuthenticated) + + def get(self, request): + users = User.objects.all() + serializer = UserSerializer(users, many=True) + return Response(serializer.data) + +class UserProfileList(generics.ListAPIView): + queryset = Profile.objects.all() + serializer_class = ProfileSerializer + +class UserProfileDetail(generics.RetrieveUpdateAPIView): + permission_classes = (permissions.IsAuthenticated, isUserOrReadOnly ) + queryset = Profile.objects.all() + serializer_class = ProfileSerializer diff --git a/server/uv.lock b/server/uv.lock index 6a7af8c..d13fcab 100644 --- a/server/uv.lock +++ b/server/uv.lock @@ -120,6 +120,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b0/ce/bf8b9d3f415be4ac5588545b5fcdbbb841977db1c1d923f7568eeabe1689/djangorestframework-3.16.1-py3-none-any.whl", hash = "sha256:33a59f47fb9c85ede792cbf88bde71893bcda0667bc573f784649521f1102cec", size = 1080442, upload-time = "2025-08-06T17:50:50.667Z" }, ] +[[package]] +name = "djangorestframework-simplejwt" +version = "5.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "djangorestframework" }, + { name = "pyjwt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/27/2874a325c11112066139769f7794afae238a07ce6adf96259f08fd37a9d7/djangorestframework_simplejwt-5.5.1.tar.gz", hash = "sha256:e72c5572f51d7803021288e2057afcbd03f17fe11d484096f40a460abc76e87f", size = 101265, upload-time = "2025-07-21T16:52:25.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/94/fdfb7b2f0b16cd3ed4d4171c55c1c07a2d1e3b106c5978c8ad0c15b4a48b/djangorestframework_simplejwt-5.5.1-py3-none-any.whl", hash = "sha256:2c30f3707053d384e9f315d11c2daccfcb548d4faa453111ca19a542b732e469", size = 107674, upload-time = "2025-07-21T16:52:07.493Z" }, +] + [[package]] name = "gunicorn" version = "23.0.0" @@ -225,6 +239,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pyjwt" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, +] + [[package]] name = "pytest" version = "8.4.2" @@ -284,6 +307,7 @@ dependencies = [ { name = "django" }, { name = "django-cors-headers" }, { name = "djangorestframework" }, + { name = "djangorestframework-simplejwt" }, { name = "gunicorn" }, { name = "psycopg", extra = ["binary", "pool"] }, { name = "python-dotenv" }, @@ -301,6 +325,7 @@ requires-dist = [ { name = "django", specifier = "~=5.2" }, { name = "django-cors-headers", specifier = "~=4.9" }, { name = "djangorestframework", specifier = "~=3.16" }, + { name = "djangorestframework-simplejwt", specifier = ">=5.5.1" }, { name = "gunicorn", specifier = "~=23.0" }, { name = "psycopg", extras = ["binary", "pool"], specifier = "~=3.2.13" }, { name = "python-dotenv", specifier = "~=1.0" }, From 6ccbbbd33aac3a2fc7fed7b5fcf8afdd4a95acd0 Mon Sep 17 00:00:00 2001 From: Will Xu <22440804@student.uwa.edu.au> Date: Fri, 5 Dec 2025 19:43:44 +0800 Subject: [PATCH 03/94] Convert ERD into Django models --- server/advertising/__init__.py | 0 server/advertising/admin.py | 3 ++ server/advertising/apps.py | 6 ++++ server/advertising/migrations/0001_initial.py | 27 +++++++++++++++++ server/advertising/migrations/__init__.py | 0 server/advertising/models.py | 15 ++++++++++ server/advertising/serializers.py | 12 ++++++++ server/advertising/tests.py | 3 ++ server/advertising/urls.py | 8 +++++ server/advertising/views.py | 13 ++++++++ server/event/__init__.py | 0 server/event/admin.py | 3 ++ server/event/apps.py | 6 ++++ server/event/migrations/0001_initial.py | 30 +++++++++++++++++++ server/event/migrations/__init__.py | 0 server/event/models.py | 19 ++++++++++++ server/event/serializers.py | 13 ++++++++ server/event/tests.py | 3 ++ server/event/urls.py | 8 +++++ server/event/views.py | 13 ++++++++ server/pyproject.toml | 1 + server/server/settings.py | 12 ++++++++ server/server/urls.py | 9 ++++++ server/tag/__init__.py | 0 server/tag/admin.py | 3 ++ server/tag/apps.py | 6 ++++ server/tag/migrations/0001_initial.py | 22 ++++++++++++++ server/tag/migrations/__init__.py | 0 server/tag/models.py | 13 ++++++++ server/tag/serializers.py | 10 +++++++ server/tag/tests.py | 3 ++ server/tag/urls.py | 8 +++++ server/tag/views.py | 13 ++++++++ server/user/__init__.py | 0 server/user/admin.py | 3 ++ server/user/apps.py | 6 ++++ server/user/migrations/0001_initial.py | 26 ++++++++++++++++ server/user/migrations/__init__.py | 0 server/user/models.py | 23 ++++++++++++++ server/user/permissions.py | 12 ++++++++ server/user/serializers.py | 22 ++++++++++++++ server/user/tests.py | 3 ++ server/user/urls.py | 10 +++++++ server/user/views.py | 27 +++++++++++++++++ server/user_profile/__init__.py | 0 server/user_profile/admin.py | 8 +++++ server/user_profile/apps.py | 6 ++++ .../user_profile/migrations/0001_initial.py | 26 ++++++++++++++++ server/user_profile/migrations/__init__.py | 0 server/user_profile/models.py | 24 +++++++++++++++ server/user_profile/permissions.py | 12 ++++++++ server/user_profile/serializers.py | 22 ++++++++++++++ server/user_profile/tests.py | 3 ++ server/user_profile/urls.py | 10 +++++++ server/user_profile/views.py | 27 +++++++++++++++++ server/uv.lock | 25 ++++++++++++++++ 56 files changed, 577 insertions(+) create mode 100644 server/advertising/__init__.py create mode 100644 server/advertising/admin.py create mode 100644 server/advertising/apps.py create mode 100644 server/advertising/migrations/0001_initial.py create mode 100644 server/advertising/migrations/__init__.py create mode 100644 server/advertising/models.py create mode 100644 server/advertising/serializers.py create mode 100644 server/advertising/tests.py create mode 100644 server/advertising/urls.py create mode 100644 server/advertising/views.py create mode 100644 server/event/__init__.py create mode 100644 server/event/admin.py create mode 100644 server/event/apps.py create mode 100644 server/event/migrations/0001_initial.py create mode 100644 server/event/migrations/__init__.py create mode 100644 server/event/models.py create mode 100644 server/event/serializers.py create mode 100644 server/event/tests.py create mode 100644 server/event/urls.py create mode 100644 server/event/views.py create mode 100644 server/tag/__init__.py create mode 100644 server/tag/admin.py create mode 100644 server/tag/apps.py create mode 100644 server/tag/migrations/0001_initial.py create mode 100644 server/tag/migrations/__init__.py create mode 100644 server/tag/models.py create mode 100644 server/tag/serializers.py create mode 100644 server/tag/tests.py create mode 100644 server/tag/urls.py create mode 100644 server/tag/views.py create mode 100644 server/user/__init__.py create mode 100644 server/user/admin.py create mode 100644 server/user/apps.py create mode 100644 server/user/migrations/0001_initial.py create mode 100644 server/user/migrations/__init__.py create mode 100644 server/user/models.py create mode 100644 server/user/permissions.py create mode 100644 server/user/serializers.py create mode 100644 server/user/tests.py create mode 100644 server/user/urls.py create mode 100644 server/user/views.py create mode 100644 server/user_profile/__init__.py create mode 100644 server/user_profile/admin.py create mode 100644 server/user_profile/apps.py create mode 100644 server/user_profile/migrations/0001_initial.py create mode 100644 server/user_profile/migrations/__init__.py create mode 100644 server/user_profile/models.py create mode 100644 server/user_profile/permissions.py create mode 100644 server/user_profile/serializers.py create mode 100644 server/user_profile/tests.py create mode 100644 server/user_profile/urls.py create mode 100644 server/user_profile/views.py diff --git a/server/advertising/__init__.py b/server/advertising/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/advertising/admin.py b/server/advertising/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/server/advertising/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/server/advertising/apps.py b/server/advertising/apps.py new file mode 100644 index 0000000..593838d --- /dev/null +++ b/server/advertising/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AdvertisingConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'advertising' diff --git a/server/advertising/migrations/0001_initial.py b/server/advertising/migrations/0001_initial.py new file mode 100644 index 0000000..379b216 --- /dev/null +++ b/server/advertising/migrations/0001_initial.py @@ -0,0 +1,27 @@ +# Generated by Django 5.2.8 on 2025-12-05 11:38 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Advertising', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('promotion_price', models.DecimalField(decimal_places=2, max_digits=10)), + ('ad_content', models.TextField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('manager', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='advertised_events', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/server/advertising/migrations/__init__.py b/server/advertising/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/advertising/models.py b/server/advertising/models.py new file mode 100644 index 0000000..f7117c8 --- /dev/null +++ b/server/advertising/models.py @@ -0,0 +1,15 @@ +from django.db import models +from django.contrib.auth import get_user_model + +# Create your models here. + +User = get_user_model() + +class Advertising(models.Model): + manager = models.ForeignKey(User, on_delete=models.CASCADE, related_name="advertised_events") + promotion_price = models.DecimalField(max_digits=10, decimal_places=2) + ad_content = models.TextField(null=False, blank=False) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"Promoted by {self.manager.username} at ${self.promotion_price}" \ No newline at end of file diff --git a/server/advertising/serializers.py b/server/advertising/serializers.py new file mode 100644 index 0000000..c4d3860 --- /dev/null +++ b/server/advertising/serializers.py @@ -0,0 +1,12 @@ +from rest_framework import serializers +from .models import Advertising +from user.serializers import UserSerializer + + +class AdvertisingSerializer(serializers.ModelSerializer): + manager = UserSerializer(read_only=True) + + class Meta: + model = Advertising + fields = ("id", "manager", "promotion_price", "ad_content", "created_at" ) + read_only_fields = ("created_at",) diff --git a/server/advertising/tests.py b/server/advertising/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/server/advertising/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/advertising/urls.py b/server/advertising/urls.py new file mode 100644 index 0000000..1c9d2ef --- /dev/null +++ b/server/advertising/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from . import views + +app_name = "advertising" +urlpatterns = [ + path("", views.AdvertisingList.as_view(), name="advertising-list"), + ] + diff --git a/server/advertising/views.py b/server/advertising/views.py new file mode 100644 index 0000000..1bbe086 --- /dev/null +++ b/server/advertising/views.py @@ -0,0 +1,13 @@ +from django.shortcuts import render +from rest_framework import generics, permissions + + +from .models import Advertising +from .serializers import AdvertisingSerializer + +# Create your views here. + +class AdvertisingList(generics.ListCreateAPIView): + queryset = Advertising.objects.all() + serializer_class = AdvertisingSerializer + permission_classes = [permissions.IsAuthenticated] \ No newline at end of file diff --git a/server/event/__init__.py b/server/event/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/event/admin.py b/server/event/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/server/event/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/server/event/apps.py b/server/event/apps.py new file mode 100644 index 0000000..49fdd6a --- /dev/null +++ b/server/event/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class EventConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'event' diff --git a/server/event/migrations/0001_initial.py b/server/event/migrations/0001_initial.py new file mode 100644 index 0000000..ef94722 --- /dev/null +++ b/server/event/migrations/0001_initial.py @@ -0,0 +1,30 @@ +# Generated by Django 5.2.8 on 2025-12-05 10:26 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Event', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('event_name', models.CharField(max_length=200)), + ('event_description', models.TextField()), + ('event_date', models.DateField()), + ('event_location', models.CharField(max_length=200)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('organizer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organized_events', to=settings.AUTH_USER_MODEL)), + ('participants', models.ManyToManyField(related_name='participated_events', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/server/event/migrations/__init__.py b/server/event/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/event/models.py b/server/event/models.py new file mode 100644 index 0000000..553b9ed --- /dev/null +++ b/server/event/models.py @@ -0,0 +1,19 @@ +from django.db import models +from django.contrib.auth import get_user_model + +# Create your models here. + +User = get_user_model() + +class Event(models.Model): + organizer = models.ForeignKey(User, on_delete=models.CASCADE, related_name="organized_events") # Only event organizer can modify the event, + #and each event has one organizer, organizer can have multiple events (one-to-many) + participants = models.ManyToManyField(User, related_name="participated_events") # Users can join multiple events (many-to-many) + event_name = models.CharField(max_length=200) + event_description = models.TextField(null=False, blank=False) + event_date = models.DateField() + event_location = models.CharField(max_length=200) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"Event: {self.event_name} hosted by {self.organizer.username}" \ No newline at end of file diff --git a/server/event/serializers.py b/server/event/serializers.py new file mode 100644 index 0000000..422a392 --- /dev/null +++ b/server/event/serializers.py @@ -0,0 +1,13 @@ +from rest_framework import serializers +from .models import Event +from user.serializers import UserSerializer + + +class EventSerializer(serializers.ModelSerializer): + organizer = UserSerializer(read_only=True) + participants = UserSerializer(many=True, read_only=True) + + class Meta: + model = Event + fields = ("id", "organizer", "participants", "event_name", "event_description","event_date", "event_location", "created_at" ) + read_only_fields = ("created_at",) diff --git a/server/event/tests.py b/server/event/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/server/event/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/event/urls.py b/server/event/urls.py new file mode 100644 index 0000000..a8b704b --- /dev/null +++ b/server/event/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from . import views + +app_name = "event" +urlpatterns = [ + path("", views.EventList.as_view(), name="event-list"), + ] + diff --git a/server/event/views.py b/server/event/views.py new file mode 100644 index 0000000..fcbd119 --- /dev/null +++ b/server/event/views.py @@ -0,0 +1,13 @@ +from django.shortcuts import render +from rest_framework import generics, permissions + + +from .models import Event +from .serializers import EventSerializer + +# Create your views here. + +class EventList(generics.ListCreateAPIView): + queryset = Event.objects.all() + serializer_class = EventSerializer + permission_classes = [permissions.IsAuthenticated] \ No newline at end of file diff --git a/server/pyproject.toml b/server/pyproject.toml index d34292d..8850f7e 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -12,6 +12,7 @@ dependencies = [ "gunicorn~=23.0", "python-dotenv~=1.0", "psycopg[binary,pool]~=3.2.13", + "djangorestframework-simplejwt>=5.5.1", ] [dependency-groups] diff --git a/server/server/settings.py b/server/server/settings.py index af546bb..f992768 100644 --- a/server/server/settings.py +++ b/server/server/settings.py @@ -48,6 +48,11 @@ "rest_framework", "corsheaders", "healthcheck", + # "user_profile", + "user", + "event", + "tag", + "advertising", ] MIDDLEWARE = [ @@ -70,6 +75,13 @@ ROOT_URLCONF = "server.urls" +REST_FRAMEWORK = { + "DEFAULT_AUTHENTICATION_CLASSES": ( + "rest_framework.authentication.SessionAuthentication", + "rest_framework_simplejwt.authentication.JWTAuthentication", + ), +} + TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", diff --git a/server/server/urls.py b/server/server/urls.py index dd710be..76a51f3 100644 --- a/server/server/urls.py +++ b/server/server/urls.py @@ -17,8 +17,17 @@ from django.contrib import admin from django.urls import include, path +from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView urlpatterns = [ path("admin/", admin.site.urls), path("api/healthcheck/", include("healthcheck.urls")), + # path("api/user/", include("user_profile.urls")), + path("api-auth/", include("rest_framework.urls")), + path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), + path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), + path("api/user/", include("user.urls")), + path("api/event/", include("event.urls")), + path("api/tag/", include("tag.urls")), + path("api/advertising/", include("advertising.urls")), ] diff --git a/server/tag/__init__.py b/server/tag/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/tag/admin.py b/server/tag/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/server/tag/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/server/tag/apps.py b/server/tag/apps.py new file mode 100644 index 0000000..72862e5 --- /dev/null +++ b/server/tag/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class TagConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'tag' diff --git a/server/tag/migrations/0001_initial.py b/server/tag/migrations/0001_initial.py new file mode 100644 index 0000000..41b060b --- /dev/null +++ b/server/tag/migrations/0001_initial.py @@ -0,0 +1,22 @@ +# Generated by Django 5.2.8 on 2025-12-05 10:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + ] diff --git a/server/tag/migrations/__init__.py b/server/tag/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/tag/models.py b/server/tag/models.py new file mode 100644 index 0000000..b529e40 --- /dev/null +++ b/server/tag/models.py @@ -0,0 +1,13 @@ +from django.db import models +from django.contrib.auth import get_user_model + +# Create your models here. + +User = get_user_model() + +class Tag(models.Model): + name = models.CharField(max_length=100, unique=True) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return self.name \ No newline at end of file diff --git a/server/tag/serializers.py b/server/tag/serializers.py new file mode 100644 index 0000000..fb13fc3 --- /dev/null +++ b/server/tag/serializers.py @@ -0,0 +1,10 @@ +from rest_framework import serializers +from .models import Tag + + +class TagSerializer(serializers.ModelSerializer): + + class Meta: + model = Tag + fields = ("id", "name",) + read_only_fields = ("created_at",) diff --git a/server/tag/tests.py b/server/tag/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/server/tag/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/tag/urls.py b/server/tag/urls.py new file mode 100644 index 0000000..0aa8561 --- /dev/null +++ b/server/tag/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from . import views + +app_name = "tag" +urlpatterns = [ + path("", views.TagList.as_view(), name="tag-list"), + ] + diff --git a/server/tag/views.py b/server/tag/views.py new file mode 100644 index 0000000..5538582 --- /dev/null +++ b/server/tag/views.py @@ -0,0 +1,13 @@ +from django.shortcuts import render +from rest_framework import generics, permissions + + +from .models import Tag +from .serializers import TagSerializer + +# Create your views here. + +class TagList(generics.ListCreateAPIView): + queryset = Tag.objects.all() + serializer_class = TagSerializer + permission_classes = [permissions.IsAuthenticated] \ No newline at end of file diff --git a/server/user/__init__.py b/server/user/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/user/admin.py b/server/user/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/server/user/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/server/user/apps.py b/server/user/apps.py new file mode 100644 index 0000000..e6e9abb --- /dev/null +++ b/server/user/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class UsersConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'user' diff --git a/server/user/migrations/0001_initial.py b/server/user/migrations/0001_initial.py new file mode 100644 index 0000000..7605ca4 --- /dev/null +++ b/server/user/migrations/0001_initial.py @@ -0,0 +1,26 @@ +# Generated by Django 5.2.8 on 2025-12-05 10:06 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('profile_info', models.TextField(blank=True)), + ('role', models.CharField(choices=[('user', 'User'), ('admin', 'Admin')], default='user', max_length=20)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/server/user/migrations/__init__.py b/server/user/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/user/models.py b/server/user/models.py new file mode 100644 index 0000000..b67fd88 --- /dev/null +++ b/server/user/models.py @@ -0,0 +1,23 @@ +from django.db import models +from django.contrib.auth import get_user_model +from django.db.models.signals import post_save +from django.dispatch import receiver + +# Create your models here. + +User = get_user_model() + +class Profile(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + profile_info = models.TextField(blank=True) # Or keep it as 'bio'? + + ROLE_CHOICES = ('user','User'), ('admin','Admin') + role = models.CharField(max_length=20, default='user', choices=ROLE_CHOICES) # Or we can use BooleanField is_manager: + #is_manager = models.BooleanField(default=False) + def __str__(self): + return f"Profile: {self.user.username}" + +@receiver(post_save, sender=User) +def create_user_profile(sender, instance, created, **kwargs): + Profile.objects.get_or_create(user=instance) + diff --git a/server/user/permissions.py b/server/user/permissions.py new file mode 100644 index 0000000..f704e9d --- /dev/null +++ b/server/user/permissions.py @@ -0,0 +1,12 @@ +from rest_framework import permissions +from django.contrib.auth import get_user_model + +User = get_user_model() + +class IsUserOrReadOnly(permissions.BasePermission): + def has_object_permission(self, request, view, obj): + if isinstance(obj, User): + # If this is for the user object, check against logged in user + return obj == request.user + # Otherwise, check user field against logged in user + return obj.user == request.user \ No newline at end of file diff --git a/server/user/serializers.py b/server/user/serializers.py new file mode 100644 index 0000000..708e199 --- /dev/null +++ b/server/user/serializers.py @@ -0,0 +1,22 @@ +from rest_framework import serializers +from .models import Profile, User + +class ProfileSerializer(serializers.ModelSerializer): + class Meta: + model = Profile + fields = "__all__" + +class UserSerializer(serializers.ModelSerializer): + profile = ProfileSerializer(read_only=True) + + class Meta: + model = User + fields = ( + "id", + "username", + "email", + "first_name", + "last_name", + "is_staff", + "is_superuser", + "profile",) diff --git a/server/user/tests.py b/server/user/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/server/user/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/user/urls.py b/server/user/urls.py new file mode 100644 index 0000000..3f5a16f --- /dev/null +++ b/server/user/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from . import views + +app_name = "user" +urlpatterns = [ + path("", views.UserList.as_view(), name="user-list"), + path("profile/", views.UserProfileList.as_view(), name="profile-list"), + path("profile//", views.UserProfileDetail.as_view(), name="user-profile-detail"), + ] + diff --git a/server/user/views.py b/server/user/views.py new file mode 100644 index 0000000..a735f87 --- /dev/null +++ b/server/user/views.py @@ -0,0 +1,27 @@ +from django.shortcuts import render +from rest_framework import generics, permissions +from rest_framework.generics import ListAPIView +from rest_framework.response import Response +from rest_framework.views import APIView +from .permissions import IsUserOrReadOnly + +from .models import Profile, User +from .serializers import ProfileSerializer, UserSerializer + +# Create your views here. + +class UserList(APIView): + permission_classes = (permissions.IsAuthenticated,) + def get(self, request): + users = User.objects.all() + serializer = UserSerializer(users, many=True) + return Response(serializer.data) + +class UserProfileList(generics.ListAPIView): + queryset = Profile.objects.all() + serializer_class = ProfileSerializer + +class UserProfileDetail(generics.RetrieveUpdateAPIView): + permission_classes = (permissions.IsAuthenticated, IsUserOrReadOnly) + queryset = Profile.objects.all() + serializer_class = ProfileSerializer diff --git a/server/user_profile/__init__.py b/server/user_profile/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/user_profile/admin.py b/server/user_profile/admin.py new file mode 100644 index 0000000..503ad88 --- /dev/null +++ b/server/user_profile/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin + +from .models import Profile + +# Register your models here. + +admin.site.register(Profile) + diff --git a/server/user_profile/apps.py b/server/user_profile/apps.py new file mode 100644 index 0000000..fe0436b --- /dev/null +++ b/server/user_profile/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class UserProfileConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'user_profile' diff --git a/server/user_profile/migrations/0001_initial.py b/server/user_profile/migrations/0001_initial.py new file mode 100644 index 0000000..ca972e5 --- /dev/null +++ b/server/user_profile/migrations/0001_initial.py @@ -0,0 +1,26 @@ +# Generated by Django 5.2.8 on 2025-11-29 06:33 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('bio', models.TextField()), + ('age', models.IntegerField(null=True)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/server/user_profile/migrations/__init__.py b/server/user_profile/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/user_profile/models.py b/server/user_profile/models.py new file mode 100644 index 0000000..04327fe --- /dev/null +++ b/server/user_profile/models.py @@ -0,0 +1,24 @@ +from django.db import models +from django.contrib.auth import get_user_model +from django.db.models.signals import post_save +from django.dispatch import receiver + + +# Create your models here. + +User = get_user_model() + +class Profile(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + bio = models.TextField(blank=True) + age = models.IntegerField(null=True, blank=True) + + def __str__(self): + return f"Profile: {self.user.username}" + + + +@receiver(post_save, sender=User) +def create_user_profile(sender, instance, created, **kwargs): + Profile.objects.get_or_create(user=instance) + diff --git a/server/user_profile/permissions.py b/server/user_profile/permissions.py new file mode 100644 index 0000000..f704e9d --- /dev/null +++ b/server/user_profile/permissions.py @@ -0,0 +1,12 @@ +from rest_framework import permissions +from django.contrib.auth import get_user_model + +User = get_user_model() + +class IsUserOrReadOnly(permissions.BasePermission): + def has_object_permission(self, request, view, obj): + if isinstance(obj, User): + # If this is for the user object, check against logged in user + return obj == request.user + # Otherwise, check user field against logged in user + return obj.user == request.user \ No newline at end of file diff --git a/server/user_profile/serializers.py b/server/user_profile/serializers.py new file mode 100644 index 0000000..708e199 --- /dev/null +++ b/server/user_profile/serializers.py @@ -0,0 +1,22 @@ +from rest_framework import serializers +from .models import Profile, User + +class ProfileSerializer(serializers.ModelSerializer): + class Meta: + model = Profile + fields = "__all__" + +class UserSerializer(serializers.ModelSerializer): + profile = ProfileSerializer(read_only=True) + + class Meta: + model = User + fields = ( + "id", + "username", + "email", + "first_name", + "last_name", + "is_staff", + "is_superuser", + "profile",) diff --git a/server/user_profile/tests.py b/server/user_profile/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/server/user_profile/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/user_profile/urls.py b/server/user_profile/urls.py new file mode 100644 index 0000000..112ca91 --- /dev/null +++ b/server/user_profile/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from . import views + +app_name = "user_profile" +urlpatterns = [ + path("", views.UserList.as_view(), name="user-list"), + path("profile/", views.UserProfileList.as_view(), name="profile-list"), + path("profile//", views.UserProfileDetail.as_view(), name="user-profile-detail"), + ] + diff --git a/server/user_profile/views.py b/server/user_profile/views.py new file mode 100644 index 0000000..65814bf --- /dev/null +++ b/server/user_profile/views.py @@ -0,0 +1,27 @@ +from django.shortcuts import render +from rest_framework import generics, permissions +from rest_framework.generics import ListAPIView +from rest_framework.response import Response +from rest_framework.views import APIView +from .permissions import IsUserOrReadOnly + +from .models import Profile, User +from .serializers import ProfileSerializer, UserSerializer + +# Create your views here. + +class UserList(APIView): + permission_classes = (permissions.IsAuthenticated,) + def get(self, request): + users = User.objects.all() + serializer = UserSerializer(users, many=True) + return Response(serializer.data) + +class UserProfileList(generics.ListAPIView): + queryset = Profile.objects.all() + serializer_class = ProfileSerializer + +class UserProfileDetail(generics.RetrieveUpdateAPIView): + permission_classes = (permissions.IsAuthenticated, IsUserOrReadOnly) + queryset = Profile.objects.all() + serializer_class = ProfileSerializer \ No newline at end of file diff --git a/server/uv.lock b/server/uv.lock index 6a7af8c..d13fcab 100644 --- a/server/uv.lock +++ b/server/uv.lock @@ -120,6 +120,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b0/ce/bf8b9d3f415be4ac5588545b5fcdbbb841977db1c1d923f7568eeabe1689/djangorestframework-3.16.1-py3-none-any.whl", hash = "sha256:33a59f47fb9c85ede792cbf88bde71893bcda0667bc573f784649521f1102cec", size = 1080442, upload-time = "2025-08-06T17:50:50.667Z" }, ] +[[package]] +name = "djangorestframework-simplejwt" +version = "5.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "djangorestframework" }, + { name = "pyjwt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/27/2874a325c11112066139769f7794afae238a07ce6adf96259f08fd37a9d7/djangorestframework_simplejwt-5.5.1.tar.gz", hash = "sha256:e72c5572f51d7803021288e2057afcbd03f17fe11d484096f40a460abc76e87f", size = 101265, upload-time = "2025-07-21T16:52:25.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/94/fdfb7b2f0b16cd3ed4d4171c55c1c07a2d1e3b106c5978c8ad0c15b4a48b/djangorestframework_simplejwt-5.5.1-py3-none-any.whl", hash = "sha256:2c30f3707053d384e9f315d11c2daccfcb548d4faa453111ca19a542b732e469", size = 107674, upload-time = "2025-07-21T16:52:07.493Z" }, +] + [[package]] name = "gunicorn" version = "23.0.0" @@ -225,6 +239,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pyjwt" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, +] + [[package]] name = "pytest" version = "8.4.2" @@ -284,6 +307,7 @@ dependencies = [ { name = "django" }, { name = "django-cors-headers" }, { name = "djangorestframework" }, + { name = "djangorestframework-simplejwt" }, { name = "gunicorn" }, { name = "psycopg", extra = ["binary", "pool"] }, { name = "python-dotenv" }, @@ -301,6 +325,7 @@ requires-dist = [ { name = "django", specifier = "~=5.2" }, { name = "django-cors-headers", specifier = "~=4.9" }, { name = "djangorestframework", specifier = "~=3.16" }, + { name = "djangorestframework-simplejwt", specifier = ">=5.5.1" }, { name = "gunicorn", specifier = "~=23.0" }, { name = "psycopg", extras = ["binary", "pool"], specifier = "~=3.2.13" }, { name = "python-dotenv", specifier = "~=1.0" }, From f263cb16a68777c981432cb47d67eb753a276c6a Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Sat, 6 Dec 2025 09:35:12 +0800 Subject: [PATCH 04/94] clean up for files prior to merge, deleted duplicate urls in server url patterns --- server/server/urls.py | 3 -- server/user_profile/__init__.py | 0 server/user_profile/admin.py | 8 --- server/user_profile/apps.py | 6 --- .../user_profile/migrations/0001_initial.py | 34 ------------- server/user_profile/migrations/__init__.py | 0 server/user_profile/models.py | 48 ------------------ server/user_profile/permissions.py | 25 ---------- server/user_profile/serializers.py | 41 --------------- server/user_profile/tests.py | 3 -- server/user_profile/urls.py | 21 -------- server/user_profile/views.py | 50 ------------------- 12 files changed, 239 deletions(-) delete mode 100644 server/user_profile/__init__.py delete mode 100644 server/user_profile/admin.py delete mode 100644 server/user_profile/apps.py delete mode 100644 server/user_profile/migrations/0001_initial.py delete mode 100644 server/user_profile/migrations/__init__.py delete mode 100644 server/user_profile/models.py delete mode 100644 server/user_profile/permissions.py delete mode 100644 server/user_profile/serializers.py delete mode 100644 server/user_profile/tests.py delete mode 100644 server/user_profile/urls.py delete mode 100644 server/user_profile/views.py diff --git a/server/server/urls.py b/server/server/urls.py index 6718db7..a25a646 100644 --- a/server/server/urls.py +++ b/server/server/urls.py @@ -26,9 +26,6 @@ path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh_view"), path("api/healthcheck/", include("healthcheck.urls")), # path("api/user/", include("user_profile.urls")), - path("api-auth/", include("rest_framework.urls")), - path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), - path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), path("api/user/", include("user.urls")), path("api/event/", include("event.urls")), path("api/tag/", include("tag.urls")), diff --git a/server/user_profile/__init__.py b/server/user_profile/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/user_profile/admin.py b/server/user_profile/admin.py deleted file mode 100644 index 503ad88..0000000 --- a/server/user_profile/admin.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.contrib import admin - -from .models import Profile - -# Register your models here. - -admin.site.register(Profile) - diff --git a/server/user_profile/apps.py b/server/user_profile/apps.py deleted file mode 100644 index fe0436b..0000000 --- a/server/user_profile/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class UserProfileConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'user_profile' diff --git a/server/user_profile/migrations/0001_initial.py b/server/user_profile/migrations/0001_initial.py deleted file mode 100644 index 2478e97..0000000 --- a/server/user_profile/migrations/0001_initial.py +++ /dev/null @@ -1,34 +0,0 @@ -<<<<<<< HEAD -# Generated by Django 5.2.8 on 2025-11-29 06:32 -======= -# Generated by Django 5.2.8 on 2025-11-29 06:33 ->>>>>>> Will_branch - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Profile', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('bio', models.TextField()), -<<<<<<< HEAD - ('age', models.PositiveBigIntegerField(null=True)), -======= - ('age', models.IntegerField(null=True)), ->>>>>>> Will_branch - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - ] diff --git a/server/user_profile/migrations/__init__.py b/server/user_profile/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/server/user_profile/models.py b/server/user_profile/models.py deleted file mode 100644 index 835af50..0000000 --- a/server/user_profile/models.py +++ /dev/null @@ -1,48 +0,0 @@ -<<<<<<< HEAD -from django.contrib.auth import get_user_model -from django.db import models -from django.db.models.signals import post_save -from django.dispatch import receiver - -User = get_user_model() - -# Create your models here. - -class Profile(models.Model): - user = models.OneToOneField(User, on_delete=models.CASCADE) - bio = models.TextField() - age = models.PositiveBigIntegerField(null=True) - - def __str__(self): - return f"Profile: { self.user.username}" - - -@receiver(post_save, sender =User) -def create_or_update_user_profile(sender, instance, created, **kwargs): - Profile.objects.get_or_create(user = instance) -======= -from django.db import models -from django.contrib.auth import get_user_model -from django.db.models.signals import post_save -from django.dispatch import receiver - - -# Create your models here. - -User = get_user_model() - -class Profile(models.Model): - user = models.OneToOneField(User, on_delete=models.CASCADE) - bio = models.TextField(blank=True) - age = models.IntegerField(null=True, blank=True) - - def __str__(self): - return f"Profile: {self.user.username}" - - - -@receiver(post_save, sender=User) -def create_user_profile(sender, instance, created, **kwargs): - Profile.objects.get_or_create(user=instance) - ->>>>>>> Will_branch diff --git a/server/user_profile/permissions.py b/server/user_profile/permissions.py deleted file mode 100644 index 0e99785..0000000 --- a/server/user_profile/permissions.py +++ /dev/null @@ -1,25 +0,0 @@ -<<<<<<< HEAD -from django.contrib.auth import get_user_model -from rest_framework import permissions - -User = get_user_model() - -class isUserOrReadOnly(permissions.BasePermission): - def has_object_permission(self, request, view, obj): - if isinstance(obj, User): - return obj == request.user - return obj.user == request.user -======= -from rest_framework import permissions -from django.contrib.auth import get_user_model - -User = get_user_model() - -class IsUserOrReadOnly(permissions.BasePermission): - def has_object_permission(self, request, view, obj): - if isinstance(obj, User): - # If this is for the user object, check against logged in user - return obj == request.user - # Otherwise, check user field against logged in user - return obj.user == request.user ->>>>>>> Will_branch diff --git a/server/user_profile/serializers.py b/server/user_profile/serializers.py deleted file mode 100644 index ec79737..0000000 --- a/server/user_profile/serializers.py +++ /dev/null @@ -1,41 +0,0 @@ -from rest_framework import serializers -<<<<<<< HEAD - -from .models import Profile, User - - -======= -from .models import Profile, User - ->>>>>>> Will_branch -class ProfileSerializer(serializers.ModelSerializer): - class Meta: - model = Profile - fields = "__all__" - -class UserSerializer(serializers.ModelSerializer): -<<<<<<< HEAD - profile = ProfileSerializer(read_only = True) -======= - profile = ProfileSerializer(read_only=True) ->>>>>>> Will_branch - - class Meta: - model = User - fields = ( -<<<<<<< HEAD - "id", - "username", - "email", - "profile" - ) -======= - "id", - "username", - "email", - "first_name", - "last_name", - "is_staff", - "is_superuser", - "profile",) ->>>>>>> Will_branch diff --git a/server/user_profile/tests.py b/server/user_profile/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/server/user_profile/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/server/user_profile/urls.py b/server/user_profile/urls.py deleted file mode 100644 index 612f758..0000000 --- a/server/user_profile/urls.py +++ /dev/null @@ -1,21 +0,0 @@ -from django.urls import path -<<<<<<< HEAD - -======= ->>>>>>> Will_branch -from . import views - -app_name = "user_profile" -urlpatterns = [ -<<<<<<< HEAD - path("profile//", views.UserProfileDetail.as_view(), name="profile_detail"), - path("profile/", views.UserProfileList.as_view(), name="profile_list"), - path("user/", views.UserList.as_view(), name="user_list"), -] -======= - path("", views.UserList.as_view(), name="user-list"), - path("profile/", views.UserProfileList.as_view(), name="profile-list"), - path("profile//", views.UserProfileDetail.as_view(), name="user-profile-detail"), - ] - ->>>>>>> Will_branch diff --git a/server/user_profile/views.py b/server/user_profile/views.py deleted file mode 100644 index 5fb9264..0000000 --- a/server/user_profile/views.py +++ /dev/null @@ -1,50 +0,0 @@ -from django.shortcuts import render -from rest_framework import generics, permissions -<<<<<<< HEAD -from rest_framework.response import Response -from rest_framework.views import APIView - -from .models import Profile, User -from .permissions import isUserOrReadOnly -======= -from rest_framework.generics import ListAPIView -from rest_framework.response import Response -from rest_framework.views import APIView -from .permissions import IsUserOrReadOnly - -from .models import Profile, User ->>>>>>> Will_branch -from .serializers import ProfileSerializer, UserSerializer - -# Create your views here. - -class UserList(APIView): -<<<<<<< HEAD - permission_classes = (permissions.IsAuthenticated) - -======= - permission_classes = (permissions.IsAuthenticated,) ->>>>>>> Will_branch - def get(self, request): - users = User.objects.all() - serializer = UserSerializer(users, many=True) - return Response(serializer.data) -<<<<<<< HEAD - -======= - ->>>>>>> Will_branch -class UserProfileList(generics.ListAPIView): - queryset = Profile.objects.all() - serializer_class = ProfileSerializer - -class UserProfileDetail(generics.RetrieveUpdateAPIView): -<<<<<<< HEAD - permission_classes = (permissions.IsAuthenticated, isUserOrReadOnly ) - queryset = Profile.objects.all() - serializer_class = ProfileSerializer -======= - permission_classes = (permissions.IsAuthenticated, IsUserOrReadOnly) - queryset = Profile.objects.all() - serializer_class = ProfileSerializer ->>>>>>> Will_branch From 58af90d264838d49857568cc284b5da9f0a1c653 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Sat, 6 Dec 2025 09:41:06 +0800 Subject: [PATCH 05/94] registered apps to admin site --- server/advertising/admin.py | 5 +++++ server/event/admin.py | 3 +++ server/tag/admin.py | 3 +++ server/user/admin.py | 4 ++++ 4 files changed, 15 insertions(+) diff --git a/server/advertising/admin.py b/server/advertising/admin.py index 8c38f3f..e6e96dc 100644 --- a/server/advertising/admin.py +++ b/server/advertising/admin.py @@ -1,3 +1,8 @@ from django.contrib import admin +from .models import Advertising # Register your models here. + +admin.site.register(Advertising) + + diff --git a/server/event/admin.py b/server/event/admin.py index 8c38f3f..70ed94b 100644 --- a/server/event/admin.py +++ b/server/event/admin.py @@ -1,3 +1,6 @@ from django.contrib import admin +from .models import Event # Register your models here. + +admin.site.register(Event) diff --git a/server/tag/admin.py b/server/tag/admin.py index 8c38f3f..84b3758 100644 --- a/server/tag/admin.py +++ b/server/tag/admin.py @@ -1,3 +1,6 @@ from django.contrib import admin +from .models import Tag # Register your models here. + +admin.site.register(Tag) diff --git a/server/user/admin.py b/server/user/admin.py index 8c38f3f..8cbd2d1 100644 --- a/server/user/admin.py +++ b/server/user/admin.py @@ -1,3 +1,7 @@ from django.contrib import admin +from .models import Profile + # Register your models here. + +admin.site.register(Profile) From fcfa6bc1d8f33a3394233cbfd9c1563138f168c0 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Sat, 6 Dec 2025 10:06:56 +0800 Subject: [PATCH 06/94] moved to JWT authentication --- server/server/settings.py | 1 - server/server/urls.py | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server/server/settings.py b/server/server/settings.py index f992768..361c704 100644 --- a/server/server/settings.py +++ b/server/server/settings.py @@ -77,7 +77,6 @@ REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ( - "rest_framework.authentication.SessionAuthentication", "rest_framework_simplejwt.authentication.JWTAuthentication", ), } diff --git a/server/server/urls.py b/server/server/urls.py index a25a646..e35e8e1 100644 --- a/server/server/urls.py +++ b/server/server/urls.py @@ -20,10 +20,14 @@ from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView urlpatterns = [ + # admin path("admin/", admin.site.urls), - path("api-auth/", include("rest_framework.urls")), + + # using JWT for auth for front end path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh_view"), + + # URLS for meaningful stuff path("api/healthcheck/", include("healthcheck.urls")), # path("api/user/", include("user_profile.urls")), path("api/user/", include("user.urls")), From 392fe3257af31c40b89c65fc72798ac20b8b0534 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Tue, 9 Dec 2025 20:42:32 +0800 Subject: [PATCH 07/94] added JWT authentication back.. for now --- server/server/settings.py | 1 + server/server/urls.py | 1 + 2 files changed, 2 insertions(+) diff --git a/server/server/settings.py b/server/server/settings.py index 361c704..c992cad 100644 --- a/server/server/settings.py +++ b/server/server/settings.py @@ -77,6 +77,7 @@ REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ( + 'rest_framework.authentication.SessionAuthentication', "rest_framework_simplejwt.authentication.JWTAuthentication", ), } diff --git a/server/server/urls.py b/server/server/urls.py index e35e8e1..c203449 100644 --- a/server/server/urls.py +++ b/server/server/urls.py @@ -26,6 +26,7 @@ # using JWT for auth for front end path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh_view"), + path("api-auth/", include("rest_framework.urls")), # URLS for meaningful stuff path("api/healthcheck/", include("healthcheck.urls")), From 1a2b9548aca0f7259389aacafc4753f2aedb9949 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Sat, 13 Dec 2025 09:49:55 +0800 Subject: [PATCH 08/94] added landing page with shadcn navmenu --- client/package-lock.json | 330 ++++++++++++++++++- client/package.json | 1 + client/src/components/ui/navigation-menu.tsx | 168 ++++++++++ client/src/pages/home.tsx | 35 ++ 4 files changed, 516 insertions(+), 18 deletions(-) create mode 100644 client/src/components/ui/navigation-menu.tsx create mode 100644 client/src/pages/home.tsx diff --git a/client/package-lock.json b/client/package-lock.json index f9648a0..835b64b 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -8,6 +8,7 @@ "name": "client", "version": "0.1.0", "dependencies": { + "@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-slot": "^1.2.3", "@tanstack/react-query": "^5.80.7", "@tanstack/react-query-devtools": "^5.80.7", @@ -442,13 +443,12 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.2.tgz", - "integrity": "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.15.0", + "@eslint/core": "^0.15.2", "levn": "^0.4.1" }, "engines": { @@ -456,11 +456,10 @@ } }, "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.0.tgz", - "integrity": "sha512-b7ePw78tEWWkpgZCDYkbqDOP8dmM6qe+AOC6iuJqlq1R/0ahMAeH3qynpnqKFGkMltrp44ohV4ubGyvLX28tzw==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, @@ -1282,6 +1281,36 @@ "node": ">=14" } }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==" + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", @@ -1297,6 +1326,157 @@ } } }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", + "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", @@ -1315,6 +1495,122 @@ } } }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -1453,7 +1749,7 @@ "version": "19.1.6", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz", "integrity": "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.0.0" @@ -3800,10 +4096,9 @@ } }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "license": "ISC", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -4561,11 +4856,10 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, diff --git a/client/package.json b/client/package.json index ce70203..3d4dd28 100644 --- a/client/package.json +++ b/client/package.json @@ -15,6 +15,7 @@ "prepare": "cd .. && husky client/.husky" }, "dependencies": { + "@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-slot": "^1.2.3", "@tanstack/react-query": "^5.80.7", "@tanstack/react-query-devtools": "^5.80.7", diff --git a/client/src/components/ui/navigation-menu.tsx b/client/src/components/ui/navigation-menu.tsx new file mode 100644 index 0000000..3c03297 --- /dev/null +++ b/client/src/components/ui/navigation-menu.tsx @@ -0,0 +1,168 @@ +import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"; +import { cva } from "class-variance-authority"; +import { ChevronDownIcon } from "lucide-react"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +function NavigationMenu({ + className, + children, + viewport = true, + ...props +}: React.ComponentProps & { + viewport?: boolean; +}) { + return ( + + {children} + {viewport && } + + ); +} + +function NavigationMenuList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function NavigationMenuItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +const navigationMenuTriggerStyle = cva( + "group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1", +); + +function NavigationMenuTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + {children}{" "} + + ); +} + +function NavigationMenuContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function NavigationMenuViewport({ + className, + ...props +}: React.ComponentProps) { + return ( +
+ +
+ ); +} + +function NavigationMenuLink({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function NavigationMenuIndicator({ + className, + ...props +}: React.ComponentProps) { + return ( + +
+ + ); +} + +export { + NavigationMenu, + NavigationMenuContent, + NavigationMenuIndicator, + NavigationMenuItem, + NavigationMenuLink, + NavigationMenuList, + NavigationMenuTrigger, + navigationMenuTriggerStyle, + NavigationMenuViewport, +}; diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx new file mode 100644 index 0000000..8c4ed85 --- /dev/null +++ b/client/src/pages/home.tsx @@ -0,0 +1,35 @@ +import { Button } from "@/components/ui/button"; +import { + NavigationMenu, + NavigationMenuItem, + NavigationMenuList, + NavigationMenuTrigger, +} from "@/components/ui/navigation-menu"; + +export default function Home() { + return ( +
+ + + + Events + + + Clubs + + + + Idk another placeholder + + + + About us + + + +
+ +
+
+ ); +} From 394e42c0aba0223a88ca4c22bc248f5accdfe3c5 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Sat, 13 Dec 2025 09:54:36 +0800 Subject: [PATCH 09/94] landing page comment --- client/src/pages/home.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index 8c4ed85..9f73a28 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -6,6 +6,8 @@ import { NavigationMenuTrigger, } from "@/components/ui/navigation-menu"; +// Landing page has nav menu on top with a signup on the right +// scrolling content underneath? export default function Home() { return (
From 64d2ad12584b0d941c0464d75f3c827bc2ce3fe8 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Sat, 13 Dec 2025 10:36:17 +0800 Subject: [PATCH 10/94] adjusted join button on home page --- client/src/pages/home.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index 9f73a28..e0a4db2 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -29,7 +29,7 @@ export default function Home() { -
+
From adc2c600d4f656c602d5a89a00403f8fa5428b73 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Sat, 13 Dec 2025 10:44:59 +0800 Subject: [PATCH 11/94] added a test navigation link --- client/src/pages/home.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index e0a4db2..3f778de 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -1,6 +1,10 @@ +import { NavigationMenuLink } from "@radix-ui/react-navigation-menu"; +import Link from "next/link"; + import { Button } from "@/components/ui/button"; import { NavigationMenu, + NavigationMenuContent, NavigationMenuItem, NavigationMenuList, NavigationMenuTrigger, @@ -15,6 +19,11 @@ export default function Home() { Events + + + INDEX + + Clubs From f0abb828b56b88fefff76370139a8fe1061f869d Mon Sep 17 00:00:00 2001 From: Coffee <153749000+CoffeeFolf@users.noreply.github.com> Date: Sat, 13 Dec 2025 12:26:06 +0800 Subject: [PATCH 12/94] layout --- client/package-lock.json | 17 +++++++++++++ client/src/pages/index.tsx | 31 +++++++++++++----------- client/src/pages/layout.tsx | 48 +++++++++++++++++++++++++++++++++++++ client/src/pages/try.tsx | 12 ++++++++++ 4 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 client/src/pages/layout.tsx create mode 100644 client/src/pages/try.tsx diff --git a/client/package-lock.json b/client/package-lock.json index 835b64b..1e4a319 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -146,6 +146,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -169,6 +170,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -1676,6 +1678,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.80.7.tgz", "integrity": "sha512-u2F0VK6+anItoEvB3+rfvTO9GEh2vb00Je05OwlUe/A0lkJBgW1HckiY3f9YZa+jx6IOe4dHPh10dyp9aY3iRQ==", "license": "MIT", + "peer": true, "dependencies": { "@tanstack/query-core": "5.80.7" }, @@ -1741,6 +1744,7 @@ "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -1751,6 +1755,7 @@ "integrity": "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.0.0" } @@ -1761,6 +1766,7 @@ "integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.34.1", "@typescript-eslint/types": "8.34.1", @@ -1965,6 +1971,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2406,6 +2413,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001718", "electron-to-chromium": "^1.5.160", @@ -3142,6 +3150,7 @@ "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -3347,6 +3356,7 @@ "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -4844,6 +4854,7 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -5767,6 +5778,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5872,6 +5884,7 @@ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -6014,6 +6027,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -6023,6 +6037,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -6887,6 +6902,7 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "license": "MIT", + "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -7141,6 +7157,7 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/client/src/pages/index.tsx b/client/src/pages/index.tsx index c051281..8fc7fd0 100644 --- a/client/src/pages/index.tsx +++ b/client/src/pages/index.tsx @@ -5,6 +5,7 @@ import { usePings } from "@/hooks/pings"; import { cn } from "@/lib/utils"; import { Button } from "../components/ui/button"; +import Layout from "./layout"; const fontSans = FontSans({ subsets: ["latin"], @@ -18,19 +19,21 @@ export default function Home() { }); return ( -
-

Test title

- -

- Response from server: {data as string} -

-
+ +
+

Test title

+ +

+ Response from server: {data as string} +

+
+
); } diff --git a/client/src/pages/layout.tsx b/client/src/pages/layout.tsx new file mode 100644 index 0000000..753d17f --- /dev/null +++ b/client/src/pages/layout.tsx @@ -0,0 +1,48 @@ +import { NavigationMenuLink } from "@radix-ui/react-navigation-menu"; +import Link from "next/link"; + +import { Button } from "@/components/ui/button"; +import { + NavigationMenu, + NavigationMenuContent, + NavigationMenuItem, + NavigationMenuList, + NavigationMenuTrigger, +} from "@/components/ui/navigation-menu"; + +type LayoutProps = { + children: React.ReactNode; +}; + +export default function Layout({ children }: LayoutProps) { + return ( + <> +
+ + + + Events + + + Index + + + + + + Clubs + + + + About us + + + + + +
+ +
{children}
+ + ); +} diff --git a/client/src/pages/try.tsx b/client/src/pages/try.tsx new file mode 100644 index 0000000..03a86d3 --- /dev/null +++ b/client/src/pages/try.tsx @@ -0,0 +1,12 @@ +import Layout from "./layout"; + +export default function Home() { + return ( + +
+

Home

+

This is the home page.

+
+
+ ); +} From 56b55be5c9d06b81ed64dd045b2448ce462ec417 Mon Sep 17 00:00:00 2001 From: Coffee <153749000+CoffeeFolf@users.noreply.github.com> Date: Sat, 13 Dec 2025 13:02:47 +0800 Subject: [PATCH 13/94] Added better navbar UI, added pages for each link --- client/src/pages/index.tsx | 2 +- client/src/pages/layout.tsx | 53 +++++++++-------------- client/src/pages/messages.tsx | 12 +++++ client/src/pages/notification.tsx | 12 +++++ client/src/pages/{try.tsx => profile.tsx} | 4 +- 5 files changed, 48 insertions(+), 35 deletions(-) create mode 100644 client/src/pages/messages.tsx create mode 100644 client/src/pages/notification.tsx rename client/src/pages/{try.tsx => profile.tsx} (62%) diff --git a/client/src/pages/index.tsx b/client/src/pages/index.tsx index 8fc7fd0..9452c4b 100644 --- a/client/src/pages/index.tsx +++ b/client/src/pages/index.tsx @@ -26,7 +26,7 @@ export default function Home() { fontSans.variable, )} > -

Test title

+

HOME

diff --git a/client/src/pages/layout.tsx b/client/src/pages/layout.tsx index 753d17f..d374d4e 100644 --- a/client/src/pages/layout.tsx +++ b/client/src/pages/layout.tsx @@ -1,15 +1,6 @@ -import { NavigationMenuLink } from "@radix-ui/react-navigation-menu"; +import { Bell,Home, Mail, User } from "lucide-react"; import Link from "next/link"; -import { Button } from "@/components/ui/button"; -import { - NavigationMenu, - NavigationMenuContent, - NavigationMenuItem, - NavigationMenuList, - NavigationMenuTrigger, -} from "@/components/ui/navigation-menu"; - type LayoutProps = { children: React.ReactNode; }; @@ -17,32 +8,30 @@ type LayoutProps = { export default function Layout({ children }: LayoutProps) { return ( <> -
- - - - Events - - - Index - - - +
{children}
- - Clubs - +
+ ); } diff --git a/client/src/pages/messages.tsx b/client/src/pages/messages.tsx new file mode 100644 index 0000000..e512421 --- /dev/null +++ b/client/src/pages/messages.tsx @@ -0,0 +1,12 @@ +import Layout from "./layout"; + +export default function Home() { + return ( + +
+

Messages

+

This is the Messages page.

+
+
+ ); +} diff --git a/client/src/pages/notification.tsx b/client/src/pages/notification.tsx new file mode 100644 index 0000000..8c54482 --- /dev/null +++ b/client/src/pages/notification.tsx @@ -0,0 +1,12 @@ +import Layout from "./layout"; + +export default function Home() { + return ( + +
+

Notifiocation

+

This is the Notification page.

+
+
+ ); +} diff --git a/client/src/pages/try.tsx b/client/src/pages/profile.tsx similarity index 62% rename from client/src/pages/try.tsx rename to client/src/pages/profile.tsx index 03a86d3..800ab8f 100644 --- a/client/src/pages/try.tsx +++ b/client/src/pages/profile.tsx @@ -4,8 +4,8 @@ export default function Home() { return (
-

Home

-

This is the home page.

+

Profile

+

Profile

); From 58374d244c5f05a87089c766e4506ef8070c5040 Mon Sep 17 00:00:00 2001 From: Coffee <153749000+CoffeeFolf@users.noreply.github.com> Date: Sat, 13 Dec 2025 13:48:50 +0800 Subject: [PATCH 14/94] changed "notification.tsx" to notifications --- client/src/pages/{notification.tsx => notifications.tsx} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename client/src/pages/{notification.tsx => notifications.tsx} (76%) diff --git a/client/src/pages/notification.tsx b/client/src/pages/notifications.tsx similarity index 76% rename from client/src/pages/notification.tsx rename to client/src/pages/notifications.tsx index 8c54482..86a6143 100644 --- a/client/src/pages/notification.tsx +++ b/client/src/pages/notifications.tsx @@ -4,7 +4,7 @@ export default function Home() { return (
-

Notifiocation

+

Notification

This is the Notification page.

From 8d0bc5089c20eccc2541e6d90aad892b5c1d9555 Mon Sep 17 00:00:00 2001 From: Coffee <153749000+CoffeeFolf@users.noreply.github.com> Date: Sat, 13 Dec 2025 13:59:37 +0800 Subject: [PATCH 15/94] Changed index to welcome page, and linked a separate home page to the nav bar --- client/src/pages/Testing/homeTest.tsx | 46 +++++++++++++++++++++++++++ client/src/pages/home.tsx | 46 ++++----------------------- client/src/pages/index.tsx | 2 +- client/src/pages/layout.tsx | 4 +-- 4 files changed, 55 insertions(+), 43 deletions(-) create mode 100644 client/src/pages/Testing/homeTest.tsx diff --git a/client/src/pages/Testing/homeTest.tsx b/client/src/pages/Testing/homeTest.tsx new file mode 100644 index 0000000..3f778de --- /dev/null +++ b/client/src/pages/Testing/homeTest.tsx @@ -0,0 +1,46 @@ +import { NavigationMenuLink } from "@radix-ui/react-navigation-menu"; +import Link from "next/link"; + +import { Button } from "@/components/ui/button"; +import { + NavigationMenu, + NavigationMenuContent, + NavigationMenuItem, + NavigationMenuList, + NavigationMenuTrigger, +} from "@/components/ui/navigation-menu"; + +// Landing page has nav menu on top with a signup on the right +// scrolling content underneath? +export default function Home() { + return ( +
+ + + + Events + + + INDEX + + + + + Clubs + + + + Idk another placeholder + + + + About us + + + +
+ +
+
+ ); +} diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index 3f778de..073811e 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -1,46 +1,12 @@ -import { NavigationMenuLink } from "@radix-ui/react-navigation-menu"; -import Link from "next/link"; +import Layout from "./layout"; -import { Button } from "@/components/ui/button"; -import { - NavigationMenu, - NavigationMenuContent, - NavigationMenuItem, - NavigationMenuList, - NavigationMenuTrigger, -} from "@/components/ui/navigation-menu"; - -// Landing page has nav menu on top with a signup on the right -// scrolling content underneath? export default function Home() { return ( -
- - - - Events - - - INDEX - - - - - Clubs - - - - Idk another placeholder - - - - About us - - - -
- + +
+

Home

+

This is the Home page.

-
+ ); } diff --git a/client/src/pages/index.tsx b/client/src/pages/index.tsx index 9452c4b..2e2639b 100644 --- a/client/src/pages/index.tsx +++ b/client/src/pages/index.tsx @@ -26,7 +26,7 @@ export default function Home() { fontSans.variable, )} > -

HOME

+

Welcome Page

diff --git a/client/src/pages/layout.tsx b/client/src/pages/layout.tsx index d374d4e..eff34fe 100644 --- a/client/src/pages/layout.tsx +++ b/client/src/pages/layout.tsx @@ -1,4 +1,4 @@ -import { Bell,Home, Mail, User } from "lucide-react"; +import { Bell, Home, Mail, User } from "lucide-react"; import Link from "next/link"; type LayoutProps = { @@ -12,7 +12,7 @@ export default function Layout({ children }: LayoutProps) { + {/* welcome section */}
{/* welcome pill */} @@ -174,6 +183,7 @@ export default function AboutPage() { people, build new friendships, and make every event better.

+ {/* buttons */}
+ + {/* about section */}
- About +
+
+

+ Walking into a room full of strangers is scary +

+

+ { + "We know the feeling. You're excited about a club event, workshop, or social gathering, but the thought of going alone stops you." + } +

+

+ {"You're not alone in feeling alone."} +

+

+ Many university students miss out on amazing experiences and + opportunities simply because attending events alone is too nerve + wrecking. +

+
+ + + + + Our Solution + + + +

+ UniConnect helps by bridging the gap between wanting to + participate and having the confidence to go. +

+

+ { + "We've created a platform that lets you discover attendees with similar interests as you before the event even begins. By matching you with students who share your interests, hobbies, and personality traits, we transform the nerve wracking experience of going alone into the excitement of meeting new friends that you've already connected with through this app." + } +

+
+
+
+ + {/* What the app does */}
- How It Works +
+

+ How It Works +

+

+ Six simple steps to never feel alone at events again +

+
+ +
+ {[ + { + step: "1", + title: "Create Your Profile", + description: + "Add tags to your profile that describe you. Are you introverted or outgoing? Into photography or gaming?", + icon: Users, + color: COLORS.badge.red, + }, + { + step: "2", + title: "Define What You're Looking For", + description: + "Not just who you are, but who you want to meet. Looking for someone extroverted to balance your introvertness?", + icon: Heart, + color: COLORS.badge.purple, + }, + { + step: "3", + title: "Discover Events", + description: + "Browse university club events, workshops, and socials. Filter by your interests.", + icon: Calendar, + color: COLORS.badge.blue, + }, + { + step: "4", + title: "See Who's Going", + description: + "View other attendees and see your compatibility based on shared interests.", + icon: Sparkles, + color: COLORS.badge.green, + }, + { + step: "5", + title: "Connect Before You Go", + // Not sure if we are still using chat or questions + description: + "Send connection requests, make brief introductions, and plan to meet up.", + icon: MessageCircle, + color: COLORS.badge.yellow, + }, + { + step: "6", + title: "Show Up With Confidence", + description: + "Walk in knowing exactly who to look for. No more awkward hovering. You've got this.", + icon: TrendingUp, + color: COLORS.badge.orange, + }, + ].map((item, index) => ( + + +
+ + {item.step} + + +
+ + {item.title} + +
+ +

+ {item.description} +

+
+
+ ))} +
+ + {/* why this app section */}
- Why APPNAME +
+

+ Why UniConnect? +

+

+ Benefits for everyone in the university community +

+
- Get Started (Login/ Signup) + {/*
+

+ Ready to Get Started? +

+

+ Join thousands of students who've found their community through UniConnect +

+
*/} + + + + + Ready to Get Started? + +

+ Find your own community through UniConnect +

+
+ +
+
+ + +
+
+ + +
+
+ + + +
+
+ +
+
+ + or + +
+
+ + + + {/* Placeholder, there is no link rn */} +

+ By signing up, you agree to our Terms of Service and Privacy + Policy +

+
+
- Contact Us +
+

+ Get in Touch +

+

+ { + "Have questions? Want to partner with us? We'd love to hear from you." + } +

+
); From 647b108b563ea880af91836c982209e53c4c338d Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Tue, 6 Jan 2026 08:55:05 +0800 Subject: [PATCH 77/94] merge will -> phillip. implements a profile view --- .vscode/settings.json | 3 + client/package-lock.json | 93 + client/package.json | 1 + client/public/test.png | Bin 0 -> 40471 bytes client/src/components/ui/avatar.tsx | 48 + client/src/hooks/userprofile.ts | 38 + client/src/pages/edit.tsx | 79 + client/src/pages/profile.tsx | 66 +- my-app/.gitignore | 41 + my-app/README.md | 36 + my-app/app/favicon.ico | Bin 0 -> 25931 bytes my-app/app/globals.css | 26 + my-app/app/layout.tsx | 34 + my-app/app/page.tsx | 65 + my-app/eslint.config.mjs | 18 + my-app/next.config.ts | 7 + my-app/package-lock.json | 6549 +++++++++++++++++++++++++++ my-app/package.json | 26 + my-app/postcss.config.mjs | 7 + my-app/public/file.svg | 1 + my-app/public/globe.svg | 1 + my-app/public/next.svg | 1 + my-app/public/vercel.svg | 1 + my-app/public/window.svg | 1 + my-app/tsconfig.json | 34 + server/package-lock.json | 291 ++ server/package.json | 5 + server/user/views.py | 7 +- 28 files changed, 7476 insertions(+), 3 deletions(-) create mode 100644 client/public/test.png create mode 100644 client/src/components/ui/avatar.tsx create mode 100644 client/src/hooks/userprofile.ts create mode 100644 client/src/pages/edit.tsx create mode 100644 my-app/.gitignore create mode 100644 my-app/README.md create mode 100644 my-app/app/favicon.ico create mode 100644 my-app/app/globals.css create mode 100644 my-app/app/layout.tsx create mode 100644 my-app/app/page.tsx create mode 100644 my-app/eslint.config.mjs create mode 100644 my-app/next.config.ts create mode 100644 my-app/package-lock.json create mode 100644 my-app/package.json create mode 100644 my-app/postcss.config.mjs create mode 100644 my-app/public/file.svg create mode 100644 my-app/public/globe.svg create mode 100644 my-app/public/next.svg create mode 100644 my-app/public/vercel.svg create mode 100644 my-app/public/window.svg create mode 100644 my-app/tsconfig.json create mode 100644 server/package-lock.json create mode 100644 server/package.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 8cbd32b..d675d9c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,8 @@ "typescript.tsdk": "${workspaceFolder}/client/node_modules/typescript/lib", "shellcheck.ignorePatterns": { "**/.env*": true + }, + "[typescriptreact]": { + "editor.defaultFormatter": "vscode.typescript-language-features" } } diff --git a/client/package-lock.json b/client/package-lock.json index 22ad493..3bd69f2 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -8,6 +8,7 @@ "name": "client", "version": "0.1.0", "dependencies": { + "@radix-ui/react-avatar": "^1.1.11", "@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", @@ -1289,6 +1290,71 @@ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==" }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", + "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collection": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", @@ -1646,6 +1712,24 @@ } } }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-layout-effect": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", @@ -7315,6 +7399,15 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/client/package.json b/client/package.json index dd48b88..d1c0bc4 100644 --- a/client/package.json +++ b/client/package.json @@ -15,6 +15,7 @@ "prepare": "cd .. && husky client/.husky" }, "dependencies": { + "@radix-ui/react-avatar": "^1.1.11", "@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", diff --git a/client/public/test.png b/client/public/test.png new file mode 100644 index 0000000000000000000000000000000000000000..dad2c4af6c3e89597752c48a005c97b0a2645b80 GIT binary patch literal 40471 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

oA#~nGpH`?1i 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 EKjVZy761SM literal 0 HcmV?d00001 diff --git a/client/src/components/ui/avatar.tsx b/client/src/components/ui/avatar.tsx new file mode 100644 index 0000000..05c569c --- /dev/null +++ b/client/src/components/ui/avatar.tsx @@ -0,0 +1,48 @@ +import * as AvatarPrimitive from "@radix-ui/react-avatar"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; + +export { Avatar, AvatarFallback, AvatarImage }; diff --git a/client/src/hooks/userprofile.ts b/client/src/hooks/userprofile.ts new file mode 100644 index 0000000..d8295ec --- /dev/null +++ b/client/src/hooks/userprofile.ts @@ -0,0 +1,38 @@ +import { useQuery, UseQueryOptions } from "@tanstack/react-query"; + +import api from "@/lib/api"; + +type UserProfile = { + id: number; + username: string; + email: string; + first_name: string; + last_name: string; + is_staff: boolean; + is_superuser: boolean; + profile: { + id: number; + profile_info: string; + role: string; + user: number; + }; +}; + +export const useUserProfile = ( + args?: Omit, +) => { + return useQuery({ + ...args, + queryKey: ["userProfile"], + queryFn: async () => { + const user_id = 1; /* for now here just put 1 to make sure we can still fetch before the login system is created" */ + const res = await api.get("/user/"); + const user_profile = res.data; + const CurrentUser = user_profile.find( + (u: UserProfile) => u.id === user_id, + ); + + return CurrentUser; + }, + }); +}; diff --git a/client/src/pages/edit.tsx b/client/src/pages/edit.tsx new file mode 100644 index 0000000..9dd86cf --- /dev/null +++ b/client/src/pages/edit.tsx @@ -0,0 +1,79 @@ +import { useEffect, useState } from "react"; + +import { Button } from "@/components/ui/button"; +import { useUserProfile } from "@/hooks/userprofile"; +import api from "@/lib/api"; + +import Layout from "./layout"; + +export default function EditProfile() { + const { data, isLoading } = useUserProfile(); + const [username, setUsername] = useState(""); + const [email, setEmail] = useState(""); + const [bio, setBio] = useState(""); + + useEffect(() => { + if (data) { + setUsername(data.username); + setEmail(data.email); + setBio(data.profile.profile_info); + } + }, [data]); + + const handleSave = async () => { + try { + await api.patch(`/user/profile/${data.profile.id}/`, { + profile_info: bio, + }); // 只改profile info用patch,暂时****因为ProfileSerializer的fields = "__all__"要求全部字段,但目前user, role没有传 + alert("Profile updated!"); + } catch (error) { + console.error("Failed to update profile:", error); + } + }; + + return ( + +

+

Edit Profile

+ + {isLoading ? ( +

Loading...

+ ) : ( + <> +
+ + setUsername(e.target.value)} + className="w-full rounded border p-2" + /> +
+ +
+ + setEmail(e.target.value)} + className="w-full rounded border p-2" + /> +
+ +
+ + +
+ + + + )} +
+ + ); +} diff --git a/client/src/pages/profile.tsx b/client/src/pages/profile.tsx index 800ab8f..8dd771a 100644 --- a/client/src/pages/profile.tsx +++ b/client/src/pages/profile.tsx @@ -1,12 +1,76 @@ +import { useRouter } from "next/router"; +import { useEffect } from "react"; + +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardFooter } from "@/components/ui/card"; +import { Separator } from "@/components/ui/separator"; +import { useUserProfile } from "@/hooks/userprofile"; + import Layout from "./layout"; export default function Home() { + const router = useRouter(); + const { data, isLoading } = useUserProfile(); + useEffect(() => { + console.log("user profile:", data); + }, [data]); + return ( + + +
+ + + Profile Picture + +
+

+ {isLoading ? "Loading" : data?.username} +

+
+
+

+ {isLoading ? "Loading" : data?.email} +

+
+
+ + Outdoor Enthusiast + + + Anime Geek + + + Traveler + + + Gamer + +
+
+ +
+
{data?.profile.profile_info}
+
+ + + +
+
+ + {/*

Profile

Profile

-
+

{isLoading ? "Loading" : `Username: ${data?.username}`}

+

{isLoading ? "Loading" : data?.email}

+ +
*/} ); } diff --git a/my-app/.gitignore b/my-app/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/my-app/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/my-app/README.md b/my-app/README.md new file mode 100644 index 0000000..e215bc4 --- /dev/null +++ b/my-app/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/my-app/app/favicon.ico b/my-app/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 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 LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/my-app/app/globals.css b/my-app/app/globals.css new file mode 100644 index 0000000..a2dc41e --- /dev/null +++ b/my-app/app/globals.css @@ -0,0 +1,26 @@ +@import "tailwindcss"; + +:root { + --background: #ffffff; + --foreground: #171717; +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + } +} + +body { + background: var(--background); + color: var(--foreground); + font-family: Arial, Helvetica, sans-serif; +} diff --git a/my-app/app/layout.tsx b/my-app/app/layout.tsx new file mode 100644 index 0000000..f7fa87e --- /dev/null +++ b/my-app/app/layout.tsx @@ -0,0 +1,34 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/my-app/app/page.tsx b/my-app/app/page.tsx new file mode 100644 index 0000000..295f8fd --- /dev/null +++ b/my-app/app/page.tsx @@ -0,0 +1,65 @@ +import Image from "next/image"; + +export default function Home() { + return ( +
+
+ Next.js logo +
+

+ To get started, edit the page.tsx file. +

+

+ Looking for a starting point or more instructions? Head over to{" "} + + Templates + {" "} + or the{" "} + + Learning + {" "} + center. +

+
+ +
+
+ ); +} diff --git a/my-app/eslint.config.mjs b/my-app/eslint.config.mjs new file mode 100644 index 0000000..05e726d --- /dev/null +++ b/my-app/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/my-app/next.config.ts b/my-app/next.config.ts new file mode 100644 index 0000000..e9ffa30 --- /dev/null +++ b/my-app/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; diff --git a/my-app/package-lock.json b/my-app/package-lock.json new file mode 100644 index 0000000..43ea2a9 --- /dev/null +++ b/my-app/package-lock.json @@ -0,0 +1,6549 @@ +{ + "name": "my-app", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "my-app", + "version": "0.1.0", + "dependencies": { + "next": "16.1.1", + "react": "19.2.3", + "react-dom": "19.2.3" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.1.1", + "tailwindcss": "^4", + "typescript": "^5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@next/env": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.1.tgz", + "integrity": "sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.1.tgz", + "integrity": "sha512-Ovb/6TuLKbE1UiPcg0p39Ke3puyTCIKN9hGbNItmpQsp+WX3qrjO3WaMVSi6JHr9X1NrmthqIguVHodMJbh/dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.1.tgz", + "integrity": "sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.1.tgz", + "integrity": "sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.1.tgz", + "integrity": "sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.1.tgz", + "integrity": "sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.1.tgz", + "integrity": "sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.1.tgz", + "integrity": "sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.1.tgz", + "integrity": "sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.1.tgz", + "integrity": "sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", + "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", + "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-x64": "4.1.18", + "@tailwindcss/oxide-freebsd-x64": "4.1.18", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-x64-musl": "4.1.18", + "@tailwindcss/oxide-wasm32-wasi": "4.1.18", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz", + "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz", + "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz", + "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz", + "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz", + "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz", + "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz", + "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz", + "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz", + "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz", + "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.0", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", + "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz", + "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.18.tgz", + "integrity": "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", + "postcss": "^8.4.41", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", + "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", + "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.51.0.tgz", + "integrity": "sha512-XtssGWJvypyM2ytBnSnKtHYOGT+4ZwTnBVl36TA4nRO2f4PRNGz5/1OszHzcZCvcBMh+qb7I06uoCmLTRdR9og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.51.0", + "@typescript-eslint/type-utils": "8.51.0", + "@typescript-eslint/utils": "8.51.0", + "@typescript-eslint/visitor-keys": "8.51.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.51.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.51.0.tgz", + "integrity": "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.51.0", + "@typescript-eslint/types": "8.51.0", + "@typescript-eslint/typescript-estree": "8.51.0", + "@typescript-eslint/visitor-keys": "8.51.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.51.0.tgz", + "integrity": "sha512-Luv/GafO07Z7HpiI7qeEW5NW8HUtZI/fo/kE0YbtQEFpJRUuR0ajcWfCE5bnMvL7QQFrmT/odMe8QZww8X2nfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.51.0", + "@typescript-eslint/types": "^8.51.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.51.0.tgz", + "integrity": "sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.51.0", + "@typescript-eslint/visitor-keys": "8.51.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.51.0.tgz", + "integrity": "sha512-Qi5bSy/vuHeWyir2C8u/uqGMIlIDu8fuiYWv48ZGlZ/k+PRPHtaAu7erpc7p5bzw2WNNSniuxoMSO4Ar6V9OXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.51.0.tgz", + "integrity": "sha512-0XVtYzxnobc9K0VU7wRWg1yiUrw4oQzexCG2V2IDxxCxhqBMSMbjB+6o91A+Uc0GWtgjCa3Y8bi7hwI0Tu4n5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.51.0", + "@typescript-eslint/typescript-estree": "8.51.0", + "@typescript-eslint/utils": "8.51.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.51.0.tgz", + "integrity": "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.51.0.tgz", + "integrity": "sha512-1qNjGqFRmlq0VW5iVlcyHBbCjPB7y6SxpBkrbhNWMy/65ZoncXCEPJxkRZL8McrseNH6lFhaxCIaX+vBuFnRng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.51.0", + "@typescript-eslint/tsconfig-utils": "8.51.0", + "@typescript-eslint/types": "8.51.0", + "@typescript-eslint/visitor-keys": "8.51.0", + "debug": "^4.3.4", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.51.0.tgz", + "integrity": "sha512-11rZYxSe0zabiKaCP2QAwRf/dnmgFgvTmeDTtZvUvXG3UuAdg/GU02NExmmIXzz3vLGgMdtrIosI84jITQOxUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.51.0", + "@typescript-eslint/types": "8.51.0", + "@typescript-eslint/typescript-estree": "8.51.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.51.0.tgz", + "integrity": "sha512-mM/JRQOzhVN1ykejrvwnBRV3+7yTKK8tVANVN3o1O0t0v7o+jqdVu9crPy5Y9dov15TJk/FTIgoUGHrTOVL3Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.51.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.0.tgz", + "integrity": "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.11", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", + "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001762", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz", + "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.4", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", + "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-abstract": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz", + "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.1", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-next": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.1.tgz", + "integrity": "sha512-55nTpVWm3qeuxoQKLOjQVciKZJUphKrNM0fCcQHAIOGl6VFXgaqeMfv0aKJhs7QtcnlAPhNVqsqRfRjeKBPIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "16.1.1", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^7.0.0", + "globals": "16.4.0", + "typescript-eslint": "^8.46.0" + }, + "peerDependencies": { + "eslint": ">=9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-next/node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.1.tgz", + "integrity": "sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==", + "license": "MIT", + "dependencies": { + "@next/env": "16.1.1", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.8.3", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.1.1", + "@next/swc-darwin-x64": "16.1.1", + "@next/swc-linux-arm64-gnu": "16.1.1", + "@next/swc-linux-arm64-musl": "16.1.1", + "@next/swc-linux-x64-gnu": "16.1.1", + "@next/swc-linux-x64-musl": "16.1.1", + "@next/swc-win32-arm64-msvc": "16.1.1", + "@next/swc-win32-x64-msvc": "16.1.1", + "sharp": "^0.34.4" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.3" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.3.0.tgz", + "integrity": "sha512-6eg3Y9SF7SsAvGzRHQvvc1skDAhwI4YQ32ui1scxD1Ccr0G5qIIbUBT3pFTKX8kmWIQClHobtUdNuaBgwdfdWg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.51.0.tgz", + "integrity": "sha512-jh8ZuM5oEh2PSdyQG9YAEM1TCGuWenLSuSUhf/irbVUNW9O5FhbFVONviN2TgMTBnUmyHv7E56rYnfLZK6TkiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.51.0", + "@typescript-eslint/parser": "8.51.0", + "@typescript-eslint/typescript-estree": "8.51.0", + "@typescript-eslint/utils": "8.51.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.4.tgz", + "integrity": "sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/my-app/package.json b/my-app/package.json new file mode 100644 index 0000000..e9ea24e --- /dev/null +++ b/my-app/package.json @@ -0,0 +1,26 @@ +{ + "name": "my-app", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "next": "16.1.1", + "react": "19.2.3", + "react-dom": "19.2.3" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.1.1", + "tailwindcss": "^4", + "typescript": "^5" + } +} diff --git a/my-app/postcss.config.mjs b/my-app/postcss.config.mjs new file mode 100644 index 0000000..61e3684 --- /dev/null +++ b/my-app/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/my-app/public/file.svg b/my-app/public/file.svg new file mode 100644 index 0000000..004145c --- /dev/null +++ b/my-app/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/my-app/public/globe.svg b/my-app/public/globe.svg new file mode 100644 index 0000000..567f17b --- /dev/null +++ b/my-app/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/my-app/public/next.svg b/my-app/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/my-app/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/my-app/public/vercel.svg b/my-app/public/vercel.svg new file mode 100644 index 0000000..7705396 --- /dev/null +++ b/my-app/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/my-app/public/window.svg b/my-app/public/window.svg new file mode 100644 index 0000000..b2b2a44 --- /dev/null +++ b/my-app/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/my-app/tsconfig.json b/my-app/tsconfig.json new file mode 100644 index 0000000..3a13f90 --- /dev/null +++ b/my-app/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "**/*.mts" + ], + "exclude": ["node_modules"] +} diff --git a/server/package-lock.json b/server/package-lock.json new file mode 100644 index 0000000..d540a0a --- /dev/null +++ b/server/package-lock.json @@ -0,0 +1,291 @@ +{ + "name": "server", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "axios": "^1.13.2" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + } + } +} diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..c6bf726 --- /dev/null +++ b/server/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "axios": "^1.13.2" + } +} diff --git a/server/user/views.py b/server/user/views.py index d32ee51..b3e73ef 100644 --- a/server/user/views.py +++ b/server/user/views.py @@ -9,21 +9,24 @@ from .models import Profile, User from .serializers import ProfileSerializer, UserSerializer, RegisterSerializer +from rest_framework.permissions import AllowAny # 暂时加上 + # Create your views here. class UserList(APIView): - permission_classes = (permissions.IsAuthenticated,) + permission_classes = (AllowAny,)#permissions.IsAuthenticated def get(self, request): users = User.objects.all() serializer = UserSerializer(users, many=True) return Response(serializer.data) class UserProfileList(generics.ListAPIView): + permission_classes = (AllowAny,) queryset = Profile.objects.all() serializer_class = ProfileSerializer class UserProfileDetail(generics.RetrieveUpdateAPIView): - permission_classes = (permissions.IsAuthenticated, IsUserOrReadOnly) + permission_classes = (AllowAny, ) queryset = Profile.objects.all() serializer_class = ProfileSerializer From 6cf88b169535c88ac2e4eae4f40c73948336d0ef Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Wed, 7 Jan 2026 08:09:49 +0800 Subject: [PATCH 78/94] merge aj -> phillip. implements authentication/chat/friends --- client/package-lock.json | 93 ++++++----- client/package.json | 3 +- client/src/components/Layout.tsx | 13 ++ client/src/components/ui/Navbar.tsx | 33 ++++ client/src/context/AuthContext.tsx | 62 ++++++++ client/src/pages/_app.tsx | 12 +- client/src/pages/add-friend.tsx | 45 ++++++ client/src/pages/chat.tsx | 19 +++ client/src/pages/chat/[id].tsx | 93 +++++++++++ client/src/pages/friends.tsx | 43 ++++++ client/src/pages/login.tsx | 144 +++++++----------- client/src/pages/signup.tsx | 113 ++++++++++++++ server/chat/__init__.py | 0 server/chat/admin.py | 3 + server/chat/apps.py | 6 + server/chat/consumers.py | 60 ++++++++ server/chat/middleware.py | 46 ++++++ server/chat/migrations/0001_initial.py | 41 +++++ server/chat/migrations/__init__.py | 0 server/chat/models.py | 40 +++++ server/chat/routing.py | 6 + server/chat/serializers.py | 20 +++ server/chat/tests.py | 3 + server/chat/urls.py | 8 + server/chat/views.py | 43 ++++++ server/chatapp/__init__.py | 0 server/chatapp/admin.py | 3 + server/chatapp/apps.py | 6 + server/chatapp/migrations/__init__.py | 0 server/chatapp/models.py | 3 + server/chatapp/tests.py | 3 + server/chatapp/views.py | 3 + server/chats/__init__.py | 0 server/chats/admin.py | 3 + server/chats/apps.py | 6 + server/chats/migrations/__init__.py | 0 server/chats/models.py | 3 + server/chats/routing.py | 0 server/chats/tests.py | 3 + server/chats/views.py | 3 + server/package-lock.json | 12 +- server/package.json | 3 +- server/server/asgi.py | 22 +-- server/server/settings.py | 11 ++ server/server/urls.py | 5 +- server/user/serializers.py | 21 +-- server/user/urls.py | 4 +- server/user/views.py | 16 +- server/user_profile/__init__.py | 0 server/user_profile/admin.py | 7 + server/user_profile/apps.py | 6 + .../user_profile/migrations/0001_initial.py | 26 ++++ server/user_profile/migrations/__init__.py | 0 server/user_profile/models.py | 20 +++ server/user_profile/permissions.py | 12 ++ server/user_profile/serializers.py | 22 +++ server/user_profile/tests.py | 3 + server/user_profile/urls.py | 9 ++ server/user_profile/views.py | 25 +++ 59 files changed, 1045 insertions(+), 164 deletions(-) create mode 100644 client/src/components/Layout.tsx create mode 100644 client/src/components/ui/Navbar.tsx create mode 100644 client/src/context/AuthContext.tsx create mode 100644 client/src/pages/add-friend.tsx create mode 100644 client/src/pages/chat.tsx create mode 100644 client/src/pages/chat/[id].tsx create mode 100644 client/src/pages/friends.tsx create mode 100644 client/src/pages/signup.tsx create mode 100644 server/chat/__init__.py create mode 100644 server/chat/admin.py create mode 100644 server/chat/apps.py create mode 100644 server/chat/consumers.py create mode 100644 server/chat/middleware.py create mode 100644 server/chat/migrations/0001_initial.py create mode 100644 server/chat/migrations/__init__.py create mode 100644 server/chat/models.py create mode 100644 server/chat/routing.py create mode 100644 server/chat/serializers.py create mode 100644 server/chat/tests.py create mode 100644 server/chat/urls.py create mode 100644 server/chat/views.py create mode 100644 server/chatapp/__init__.py create mode 100644 server/chatapp/admin.py create mode 100644 server/chatapp/apps.py create mode 100644 server/chatapp/migrations/__init__.py create mode 100644 server/chatapp/models.py create mode 100644 server/chatapp/tests.py create mode 100644 server/chatapp/views.py create mode 100644 server/chats/__init__.py create mode 100644 server/chats/admin.py create mode 100644 server/chats/apps.py create mode 100644 server/chats/migrations/__init__.py create mode 100644 server/chats/models.py create mode 100644 server/chats/routing.py create mode 100644 server/chats/tests.py create mode 100644 server/chats/views.py create mode 100644 server/user_profile/__init__.py create mode 100644 server/user_profile/admin.py create mode 100644 server/user_profile/apps.py create mode 100644 server/user_profile/migrations/0001_initial.py create mode 100644 server/user_profile/migrations/__init__.py create mode 100644 server/user_profile/models.py create mode 100644 server/user_profile/permissions.py create mode 100644 server/user_profile/serializers.py create mode 100644 server/user_profile/tests.py create mode 100644 server/user_profile/urls.py create mode 100644 server/user_profile/views.py diff --git a/client/package-lock.json b/client/package-lock.json index 3bd69f2..8d2c600 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -19,8 +19,9 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "is-inside-container": "^1.0.0", + "jwt-decode": "^4.0.0", "lucide-react": "^0.516.0", - "next": "15.4.7", + "next": "^15.5.9", "react": "19.1.0", "react-dom": "19.1.0", "tailwind-merge": "^3.3.1", @@ -1067,9 +1068,9 @@ } }, "node_modules/@next/env": { - "version": "15.4.7", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.4.7.tgz", - "integrity": "sha512-PrBIpO8oljZGTOe9HH0miix1w5MUiGJ/q83Jge03mHEE0E3pyqzAy2+l5G6aJDbXoobmxPJTVhbCuwlLtjSHwg==", + "version": "15.5.9", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.9.tgz", + "integrity": "sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -1113,9 +1114,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.4.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.7.tgz", - "integrity": "sha512-2Dkb+VUTp9kHHkSqtws4fDl2Oxms29HcZBwFIda1X7Ztudzy7M6XF9HDS2dq85TmdN47VpuhjE+i6wgnIboVzQ==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.7.tgz", + "integrity": "sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==", "cpu": [ "arm64" ], @@ -1129,9 +1130,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.4.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.4.7.tgz", - "integrity": "sha512-qaMnEozKdWezlmh1OGDVFueFv2z9lWTcLvt7e39QA3YOvZHNpN2rLs/IQLwZaUiw2jSvxW07LxMCWtOqsWFNQg==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.7.tgz", + "integrity": "sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==", "cpu": [ "x64" ], @@ -1145,9 +1146,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.4.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.4.7.tgz", - "integrity": "sha512-ny7lODPE7a15Qms8LZiN9wjNWIeI+iAZOFDOnv2pcHStncUr7cr9lD5XF81mdhrBXLUP9yT9RzlmSWKIazWoDw==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.7.tgz", + "integrity": "sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==", "cpu": [ "arm64" ], @@ -1161,9 +1162,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.4.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.4.7.tgz", - "integrity": "sha512-4SaCjlFR/2hGJqZLLWycccy1t+wBrE/vyJWnYaZJhUVHccpGLG5q0C+Xkw4iRzUIkE+/dr90MJRUym3s1+vO8A==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.7.tgz", + "integrity": "sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==", "cpu": [ "arm64" ], @@ -1177,9 +1178,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.4.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.4.7.tgz", - "integrity": "sha512-2uNXjxvONyRidg00VwvlTYDwC9EgCGNzPAPYbttIATZRxmOZ3hllk/YYESzHZb65eyZfBR5g9xgCZjRAl9YYGg==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.7.tgz", + "integrity": "sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==", "cpu": [ "x64" ], @@ -1193,9 +1194,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.4.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.4.7.tgz", - "integrity": "sha512-ceNbPjsFgLscYNGKSu4I6LYaadq2B8tcK116nVuInpHHdAWLWSwVK6CHNvCi0wVS9+TTArIFKJGsEyVD1H+4Kg==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.7.tgz", + "integrity": "sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==", "cpu": [ "x64" ], @@ -1209,9 +1210,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.4.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.4.7.tgz", - "integrity": "sha512-pZyxmY1iHlZJ04LUL7Css8bNvsYAMYOY9JRwFA3HZgpaNKsJSowD09Vg2R9734GxAcLJc2KDQHSCR91uD6/AAw==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.7.tgz", + "integrity": "sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==", "cpu": [ "arm64" ], @@ -1225,9 +1226,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.4.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.4.7.tgz", - "integrity": "sha512-HjuwPJ7BeRzgl3KrjKqD2iDng0eQIpIReyhpF5r4yeAHFwWRuAhfW92rWv/r3qeQHEwHsLRzFDvMqRjyM5DI6A==", + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.7.tgz", + "integrity": "sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==", "cpu": [ "x64" ], @@ -4276,6 +4277,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -5095,6 +5097,15 @@ "node": ">=4.0" } }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -5489,12 +5500,12 @@ "license": "MIT" }, "node_modules/next": { - "version": "15.4.7", - "resolved": "https://registry.npmjs.org/next/-/next-15.4.7.tgz", - "integrity": "sha512-OcqRugwF7n7mC8OSYjvsZhhG1AYSvulor1EIUsIkbbEbf1qoE5EbH36Swj8WhF4cHqmDgkiam3z1c1W0J1Wifg==", + "version": "15.5.9", + "resolved": "https://registry.npmjs.org/next/-/next-15.5.9.tgz", + "integrity": "sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==", "license": "MIT", "dependencies": { - "@next/env": "15.4.7", + "@next/env": "15.5.9", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", @@ -5507,14 +5518,14 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.4.7", - "@next/swc-darwin-x64": "15.4.7", - "@next/swc-linux-arm64-gnu": "15.4.7", - "@next/swc-linux-arm64-musl": "15.4.7", - "@next/swc-linux-x64-gnu": "15.4.7", - "@next/swc-linux-x64-musl": "15.4.7", - "@next/swc-win32-arm64-msvc": "15.4.7", - "@next/swc-win32-x64-msvc": "15.4.7", + "@next/swc-darwin-arm64": "15.5.7", + "@next/swc-darwin-x64": "15.5.7", + "@next/swc-linux-arm64-gnu": "15.5.7", + "@next/swc-linux-arm64-musl": "15.5.7", + "@next/swc-linux-x64-gnu": "15.5.7", + "@next/swc-linux-x64-musl": "15.5.7", + "@next/swc-win32-arm64-msvc": "15.5.7", + "@next/swc-win32-x64-msvc": "15.5.7", "sharp": "^0.34.3" }, "peerDependencies": { @@ -7653,4 +7664,4 @@ } } } -} +} \ No newline at end of file diff --git a/client/package.json b/client/package.json index d1c0bc4..8e8832e 100644 --- a/client/package.json +++ b/client/package.json @@ -26,8 +26,9 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "is-inside-container": "^1.0.0", + "jwt-decode": "^4.0.0", "lucide-react": "^0.516.0", - "next": "15.4.7", + "next": "^15.5.9", "react": "19.1.0", "react-dom": "19.1.0", "tailwind-merge": "^3.3.1", diff --git a/client/src/components/Layout.tsx b/client/src/components/Layout.tsx new file mode 100644 index 0000000..262d982 --- /dev/null +++ b/client/src/components/Layout.tsx @@ -0,0 +1,13 @@ +import Navbar from "@/components/ui/Navbar"; + +type LayoutProps = { children: React.ReactNode }; + +export default function Layout({ children }: LayoutProps) { + return ( +
+ +
{children}
+
© 2026 My App
+
+ ); +} diff --git a/client/src/components/ui/Navbar.tsx b/client/src/components/ui/Navbar.tsx new file mode 100644 index 0000000..2617401 --- /dev/null +++ b/client/src/components/ui/Navbar.tsx @@ -0,0 +1,33 @@ +import Link from "next/link"; + +import { useAuth } from "@/context/AuthContext"; + +const Navbar = () => { + const { isLoggedIn, logout } = useAuth(); + + return ( + + ); +}; + +export default Navbar; diff --git a/client/src/context/AuthContext.tsx b/client/src/context/AuthContext.tsx new file mode 100644 index 0000000..b9cd112 --- /dev/null +++ b/client/src/context/AuthContext.tsx @@ -0,0 +1,62 @@ +import { useRouter } from "next/router"; +import { + createContext, + ReactNode, + useContext, + useEffect, + useState, +} from "react"; + +type AuthContextType = { + accessToken: string | null; + refreshToken: string | null; + login: (access: string, refresh: string) => void; + logout: () => void; + isLoggedIn: boolean; +}; + +const AuthContext = createContext(undefined); + +export const AuthProvider = ({ children }: { children: ReactNode }) => { + const [accessToken, setAccessToken] = useState(null); + const [refreshToken, setRefreshToken] = useState(null); + const router = useRouter(); + + useEffect(() => { + const storedAccess = localStorage.getItem("accessToken"); + const storedRefresh = localStorage.getItem("refreshToken"); + if (storedAccess) setAccessToken(storedAccess); + if (storedRefresh) setRefreshToken(storedRefresh); + }, []); + + const login = (access: string, refresh: string) => { + setAccessToken(access); + setRefreshToken(refresh); + localStorage.setItem("accessToken", access); + localStorage.setItem("refreshToken", refresh); + }; + + const logout = () => { + setAccessToken(null); + setRefreshToken(null); + localStorage.removeItem("accessToken"); + localStorage.removeItem("refreshToken"); + router.push("/login"); + }; + + const isLoggedIn = !!accessToken; + + return ( + + {children} + + ); +}; + +export const useAuth = () => { + const context = useContext(AuthContext); + if (!context) throw new Error("useAuth must be used within AuthProvider"); + return context; +}; diff --git a/client/src/pages/_app.tsx b/client/src/pages/_app.tsx index 628e9f2..a242830 100644 --- a/client/src/pages/_app.tsx +++ b/client/src/pages/_app.tsx @@ -4,13 +4,17 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import type { AppProps } from "next/app"; +import { AuthProvider } from "@/context/AuthContext"; + const queryClient = new QueryClient(); export default function App({ Component, pageProps }: AppProps) { return ( - - - - + + + + + + ); } diff --git a/client/src/pages/add-friend.tsx b/client/src/pages/add-friend.tsx new file mode 100644 index 0000000..e744f79 --- /dev/null +++ b/client/src/pages/add-friend.tsx @@ -0,0 +1,45 @@ +import { useState } from "react"; + +import Layout from "@/components/Layout"; +import { useAuth } from "@/context/AuthContext"; + +export default function AddFriend() { + const { accessToken } = useAuth(); + const [username, setUsername] = useState(""); + const [message, setMessage] = useState(""); + + const handleAdd = async () => { + const res = await fetch("http://localhost:8000/api/chat/add_friend/", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + }, + body: JSON.stringify({ username }), + }); + const data = await res.json(); + setMessage(data.detail || "Error"); + }; + + return ( + +
+

Add Friend

+ setUsername(e.target.value)} + placeholder="Enter username" + className="mb-2 w-full border p-2" + /> + + {message &&

{message}

} +
+
+ ); +} diff --git a/client/src/pages/chat.tsx b/client/src/pages/chat.tsx new file mode 100644 index 0000000..f86ba4a --- /dev/null +++ b/client/src/pages/chat.tsx @@ -0,0 +1,19 @@ +import { useRouter } from "next/router"; +import { useEffect } from "react"; + +import Layout from "@/components/Layout"; +import { useAuth } from "@/context/AuthContext"; + +export default function Chat() { + const { isLoggedIn } = useAuth(); + const router = useRouter(); + + useEffect(() => { + if (!isLoggedIn) { + router.push("/login"); + } + }, [isLoggedIn, router]); + + if (!isLoggedIn) return

Redirecting to login...

; + return This is the chat page; +} diff --git a/client/src/pages/chat/[id].tsx b/client/src/pages/chat/[id].tsx new file mode 100644 index 0000000..33b2010 --- /dev/null +++ b/client/src/pages/chat/[id].tsx @@ -0,0 +1,93 @@ +import { useRouter } from "next/router"; +import { useEffect, useRef, useState } from "react"; + +import Layout from "@/components/Layout"; +import { useAuth } from "@/context/AuthContext"; + +type Message = { + sender_id: number; + sender_username: string; + message: string; +}; + +export default function ChatPage() { + const router = useRouter(); + const { id: friendId } = router.query; + const { isLoggedIn, accessToken, userId } = useAuth(); + const [messages, setMessages] = useState([]); + const [newMessage, setNewMessage] = useState(""); + const wsRef = useRef(null); + const chatEndRef = useRef(null); + + useEffect(() => { + if (!isLoggedIn) router.push("/login"); + }, [isLoggedIn, router]); + + useEffect(() => { + if (!friendId || !accessToken) return; + + const ws = new WebSocket(`ws://localhost:8000/ws/chat/${friendId}/`); + wsRef.current = ws; + + ws.onmessage = (e) => { + const data = JSON.parse(e.data); + setMessages((prev) => [ + ...prev, + { + sender_id: data.sender_id, + sender_username: data.sender_username, + message: data.message, + }, + ]); + }; + + ws.onclose = () => console.log("WebSocket disconnected"); + + return () => ws.close(); + }, [friendId, accessToken]); + + const sendMessage = () => { + if (!newMessage.trim()) return; + wsRef.current?.send(JSON.stringify({ message: newMessage })); + setNewMessage(""); + }; + + useEffect(() => { + chatEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [messages]); + + if (!isLoggedIn) return

Redirecting...

; + + return ( + +
+

Chat with User {friendId}

+
+ {messages.map((msg, idx) => ( +
+ {msg.sender_username}: {msg.message} +
+ ))} +
+
+
+ setNewMessage(e.target.value)} + placeholder="Type a message..." + /> + +
+
+ + ); +} diff --git a/client/src/pages/friends.tsx b/client/src/pages/friends.tsx new file mode 100644 index 0000000..772a30a --- /dev/null +++ b/client/src/pages/friends.tsx @@ -0,0 +1,43 @@ +import Link from "next/link"; +import { useEffect, useState } from "react"; + +import Layout from "@/components/Layout"; +import { useAuth } from "@/context/AuthContext"; + +type Friend = { + id: number; + friend: number; + friend_username: string; +}; + +export default function FriendsPage() { + const { accessToken } = useAuth(); + const [friends, setFriends] = useState([]); + + useEffect(() => { + if (!accessToken) return; + fetch("http://localhost:8000/api/chat/friends/", { + headers: { Authorization: `Bearer ${accessToken}` }, + }) + .then((res) => res.json()) + .then((data) => { + if (Array.isArray(data)) setFriends(data); + }); + }, [accessToken]); + + return ( + +
+

Friends

+ {friends.length === 0 &&

You have no friends yet.

} +
    + {friends.map((f) => ( +
  • + {f.friend_username} +
  • + ))} +
+
+
+ ); +} diff --git a/client/src/pages/login.tsx b/client/src/pages/login.tsx index b8334d1..0e0a379 100644 --- a/client/src/pages/login.tsx +++ b/client/src/pages/login.tsx @@ -1,102 +1,76 @@ -import Link from "next/link"; import { useRouter } from "next/router"; import { useState } from "react"; -import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { Input } from "@/components/ui/input"; -import api from "@/lib/api"; -import { clearTokens, setTokens } from "@/lib/auth"; +import Layout from "@/components/Layout"; +import { useAuth } from "@/context/AuthContext"; -export default function Login() { +export default function LoginPage() { const router = useRouter(); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); + const { login } = useAuth(); + const [form, setForm] = useState({ username: "", password: "" }); + const [message, setMessage] = useState(""); - //function to return JWT - const login = async (username: string, password: string) => { - clearTokens(); - const res = await api.post("/token/", { - username, - password, - }); - const { access, refresh } = res.data; - setTokens(access, refresh); + const handleChange = (e: React.ChangeEvent) => { + setForm({ ...form, [e.target.name]: e.target.value }); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setMessage(""); - // once logged in, get user role and redirect to appropriate page - const userResponse = await api.get("/user/me/"); - const userRole = userResponse.data.profile.role; + try { + const res = await fetch("http://localhost:8000/api/user/login/", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(form), + }); + const data = await res.json(); - switch (userRole) { - case "manager": - router.push("manager/dashboard"); - break; - case "user": - router.push("/home"); - break; - default: - router.push("/home"); + if (res.ok) { + login(data.access, data.refresh); + router.push("/"); + } else { + setMessage(data.detail || "Login failed"); + } + } catch (error) { + // Temporary fix to commit + const x = error; + console.log(x); + setMessage("Login failed. Please try again"); } }; return ( -
- - - Login to your account - - Enter your email below to login to your account - - - - - - -
-
-
- setUsername(e.target.value)} - /> -
-
- - setPassword(e.target.value)} - /> -
-
-
-
- - - -
-
+ + +
+
); } diff --git a/client/src/pages/signup.tsx b/client/src/pages/signup.tsx new file mode 100644 index 0000000..1d93d98 --- /dev/null +++ b/client/src/pages/signup.tsx @@ -0,0 +1,113 @@ +import { useRouter } from "next/router"; +import { useState } from "react"; + +import Layout from "@/components/Layout"; + +export default function SignupPage() { + const router = useRouter(); + const [form, setForm] = useState({ + username: "", + email: "", + first_name: "", + last_name: "", + password: "", + password2: "", + }); + const [message, setMessage] = useState(""); + + const handleChange = (e: React.ChangeEvent) => { + setForm({ ...form, [e.target.name]: e.target.value }); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setMessage(""); + + try { + const res = await fetch("http://localhost:8000/api/user/signup/", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(form), + }); + const data = await res.json(); + + if (res.ok) { + alert("Signup successful! Please log in."); + router.push("/login"); + } else { + setMessage(JSON.stringify(data)); + } + } catch (error) { + // Temporary fix to commit + const x = error; + console.log(x); + setMessage("Signup failed. Please try again."); + } + }; + + return ( + +
+

Sign Up

+ {message &&

{message}

} +
+ + + + + + + +
+
+
+ ); +} diff --git a/server/chat/__init__.py b/server/chat/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/chat/admin.py b/server/chat/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/server/chat/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/server/chat/apps.py b/server/chat/apps.py new file mode 100644 index 0000000..2fe899a --- /dev/null +++ b/server/chat/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ChatConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'chat' diff --git a/server/chat/consumers.py b/server/chat/consumers.py new file mode 100644 index 0000000..69e7606 --- /dev/null +++ b/server/chat/consumers.py @@ -0,0 +1,60 @@ +import json +from channels.generic.websocket import AsyncWebsocketConsumer +from channels.db import database_sync_to_async +from django.contrib.auth import get_user_model +from .models import Message +from django.db.models import Q + +User = get_user_model() + +class ChatConsumer(AsyncWebsocketConsumer): + async def connect(self): + self.user = self.scope["user"] + self.friend_id = int(self.scope["url_route"]["kwargs"]["friend_id"]) + self.room_name = f"chat_{min(self.user.id, self.friend_id)}_{max(self.user.id, self.friend_id)}" + self.room_group_name = self.room_name + + await self.channel_layer.group_add(self.room_group_name, self.channel_name) + await self.accept() + + previous_messages = await self.get_previous_messages() + for msg in previous_messages: + await self.send(text_data=json.dumps(msg)) + + async def disconnect(self, close_code): + await self.channel_layer.group_discard(self.room_group_name, self.channel_name) + + async def receive(self, text_data): + data = json.loads(text_data) + message = data.get("message") + if message: + msg_obj = await self.save_message(message) + payload = { + "sender_id": self.user.id, + "sender_username": self.user.username, + "message": message, + } + await self.channel_layer.group_send(self.room_group_name, {"type": "chat_message", **payload}) + + async def chat_message(self, event): + await self.send(text_data=json.dumps(event)) + + @database_sync_to_async + def save_message(self, message): + receiver = User.objects.get(id=self.friend_id) + return Message.objects.create(sender=self.user, receiver=receiver, content=message) + + @database_sync_to_async + def get_previous_messages(self): + messages = Message.objects.filter( + Q(sender_id=self.user.id, receiver_id=self.friend_id) | + Q(sender_id=self.friend_id, receiver_id=self.user.id) + ).order_by("timestamp") + return [ + { + "sender_id": m.sender.id, + "sender_username": m.sender.username, + "message": m.content, + } + for m in messages + ] diff --git a/server/chat/middleware.py b/server/chat/middleware.py new file mode 100644 index 0000000..8bd974a --- /dev/null +++ b/server/chat/middleware.py @@ -0,0 +1,46 @@ +# chat/middleware.py +from urllib.parse import parse_qs +from channels.db import database_sync_to_async +from django.contrib.auth.models import AnonymousUser +from rest_framework_simplejwt.tokens import UntypedToken +from rest_framework_simplejwt.authentication import JWTAuthentication +from django.contrib.auth import get_user_model + +User = get_user_model() + +@database_sync_to_async +def get_user(token): + try: + validated_token = UntypedToken(token) + user = JWTAuthentication().get_user(validated_token) + return user + except Exception: + return AnonymousUser() + +class JWTAuthMiddleware: + """Custom middleware for JWT auth in Channels""" + def __init__(self, inner): + self.inner = inner + + def __call__(self, scope): + return JWTAuthMiddlewareInstance(scope, self.inner) + +class JWTAuthMiddlewareInstance: + def __init__(self, scope, inner): + self.scope = dict(scope) + self.inner = inner + + async def __call__(self, receive, send): + query_string = self.scope.get("query_string", b"").decode() + token = parse_qs(query_string).get("token") + if token: + self.scope["user"] = await get_user(token[0]) + else: + self.scope["user"] = AnonymousUser() + inner = self.inner(self.scope) + return await inner(receive, send) + +# Helper to wrap AuthMiddlewareStack +from channels.auth import AuthMiddlewareStack +def JWTAuthMiddlewareStack(inner): + return JWTAuthMiddleware(AuthMiddlewareStack(inner)) diff --git a/server/chat/migrations/0001_initial.py b/server/chat/migrations/0001_initial.py new file mode 100644 index 0000000..bcc1508 --- /dev/null +++ b/server/chat/migrations/0001_initial.py @@ -0,0 +1,41 @@ +# Generated by Django 5.2.8 on 2026-01-03 02:20 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Message', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('content', models.TextField()), + ('timestamp', models.DateTimeField(auto_now_add=True)), + ('receiver', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='received_messages', to=settings.AUTH_USER_MODEL)), + ('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['timestamp'], + }, + ), + migrations.CreateModel( + name='Friend', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('friend', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='friend_of', to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='friends', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('user', 'friend')}, + }, + ), + ] diff --git a/server/chat/migrations/__init__.py b/server/chat/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/chat/models.py b/server/chat/models.py new file mode 100644 index 0000000..394b50a --- /dev/null +++ b/server/chat/models.py @@ -0,0 +1,40 @@ +from django.db import models +from django.conf import settings + +User = settings.AUTH_USER_MODEL + +class Friend(models.Model): + user = models.ForeignKey(User, related_name="friends", on_delete=models.CASCADE) + friend = models.ForeignKey(User, related_name="friend_of", on_delete=models.CASCADE) + + class Meta: + unique_together = ("user", "friend") + +class Message(models.Model): + sender = models.ForeignKey(User, related_name="sent_messages", on_delete=models.CASCADE) + receiver = models.ForeignKey(User, related_name="received_messages", on_delete=models.CASCADE) + content = models.TextField() + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + ordering = ["timestamp"] +from django.db import models +from django.conf import settings + +User = settings.AUTH_USER_MODEL + +class Friend(models.Model): + user = models.ForeignKey(User, related_name="friends", on_delete=models.CASCADE) + friend = models.ForeignKey(User, related_name="friend_of", on_delete=models.CASCADE) + + class Meta: + unique_together = ("user", "friend") + +class Message(models.Model): + sender = models.ForeignKey(User, related_name="sent_messages", on_delete=models.CASCADE) + receiver = models.ForeignKey(User, related_name="received_messages", on_delete=models.CASCADE) + content = models.TextField() + timestamp = models.DateTimeField(auto_now_add=True) + + class Meta: + ordering = ["timestamp"] diff --git a/server/chat/routing.py b/server/chat/routing.py new file mode 100644 index 0000000..caf6cb0 --- /dev/null +++ b/server/chat/routing.py @@ -0,0 +1,6 @@ +from django.urls import re_path +from . import consumers + +websocket_urlpatterns = [ + re_path(r"ws/chat/(?P\d+)/$", consumers.ChatConsumer.as_asgi()), +] diff --git a/server/chat/serializers.py b/server/chat/serializers.py new file mode 100644 index 0000000..0bd0205 --- /dev/null +++ b/server/chat/serializers.py @@ -0,0 +1,20 @@ +from rest_framework import serializers +from .models import Friend, Message +from django.contrib.auth import get_user_model + +User = get_user_model() + +class FriendSerializer(serializers.ModelSerializer): + friend_username = serializers.CharField(source="friend.username", read_only=True) + + class Meta: + model = Friend + fields = ["id", "friend", "friend_username"] + +class MessageSerializer(serializers.ModelSerializer): + sender_username = serializers.CharField(source="sender.username", read_only=True) + receiver_username = serializers.CharField(source="receiver.username", read_only=True) + + class Meta: + model = Message + fields = ["id", "sender", "receiver", "sender_username", "receiver_username", "content", "timestamp"] diff --git a/server/chat/tests.py b/server/chat/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/server/chat/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/chat/urls.py b/server/chat/urls.py new file mode 100644 index 0000000..6fa16d6 --- /dev/null +++ b/server/chat/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path("friends/", views.list_friends), + path("add_friend/", views.add_friend), + path("messages//", views.messages_with_friend), +] diff --git a/server/chat/views.py b/server/chat/views.py new file mode 100644 index 0000000..81e97da --- /dev/null +++ b/server/chat/views.py @@ -0,0 +1,43 @@ +from rest_framework.decorators import api_view, permission_classes +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from django.contrib.auth import get_user_model +from django.db.models import Q +from .models import Friend, Message +from .serializers import FriendSerializer, MessageSerializer + +User = get_user_model() + +@api_view(["POST"]) +@permission_classes([IsAuthenticated]) +def add_friend(request): + username = request.data.get("username") + try: + friend_user = User.objects.get(username=username) + except User.DoesNotExist: + return Response({"detail": "User not found"}, status=404) + + if Friend.objects.filter(user=request.user, friend=friend_user).exists(): + return Response({"detail": "Already friends"}, status=400) + + Friend.objects.create(user=request.user, friend=friend_user) + Friend.objects.create(user=friend_user, friend=request.user) + return Response({"detail": "Friend added"}) + +@api_view(["GET"]) +@permission_classes([IsAuthenticated]) +def list_friends(request): + friends = Friend.objects.filter(user=request.user) + serializer = FriendSerializer(friends, many=True) + return Response(serializer.data) + +@api_view(["GET"]) +@permission_classes([IsAuthenticated]) +def messages_with_friend(request, friend_id): + user = request.user + messages = Message.objects.filter( + Q(sender=user, receiver_id=friend_id) | + Q(sender_id=friend_id, receiver=user) + ).order_by("timestamp") + serializer = MessageSerializer(messages, many=True) + return Response(serializer.data) diff --git a/server/chatapp/__init__.py b/server/chatapp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/chatapp/admin.py b/server/chatapp/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/server/chatapp/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/server/chatapp/apps.py b/server/chatapp/apps.py new file mode 100644 index 0000000..7d59db9 --- /dev/null +++ b/server/chatapp/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ChatappConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'chatapp' diff --git a/server/chatapp/migrations/__init__.py b/server/chatapp/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/chatapp/models.py b/server/chatapp/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/server/chatapp/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/server/chatapp/tests.py b/server/chatapp/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/server/chatapp/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/chatapp/views.py b/server/chatapp/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/server/chatapp/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/server/chats/__init__.py b/server/chats/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/chats/admin.py b/server/chats/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/server/chats/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/server/chats/apps.py b/server/chats/apps.py new file mode 100644 index 0000000..10c2349 --- /dev/null +++ b/server/chats/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ChatsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'chats' diff --git a/server/chats/migrations/__init__.py b/server/chats/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/chats/models.py b/server/chats/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/server/chats/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/server/chats/routing.py b/server/chats/routing.py new file mode 100644 index 0000000..e69de29 diff --git a/server/chats/tests.py b/server/chats/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/server/chats/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/chats/views.py b/server/chats/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/server/chats/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/server/package-lock.json b/server/package-lock.json index d540a0a..9b4c620 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -286,6 +286,14 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" + }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } } - } -} + } \ No newline at end of file diff --git a/server/package.json b/server/package.json index c6bf726..6faa021 100644 --- a/server/package.json +++ b/server/package.json @@ -1,5 +1,6 @@ { "dependencies": { + "jwt-decode": "^4.0.0", "axios": "^1.13.2" } -} +} \ No newline at end of file diff --git a/server/server/asgi.py b/server/server/asgi.py index 6e90b88..266c986 100644 --- a/server/server/asgi.py +++ b/server/server/asgi.py @@ -1,16 +1,16 @@ -""" -ASGI config for server project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/ -""" - import os - +from channels.auth import AuthMiddlewareStack +from channels.routing import ProtocolTypeRouter, URLRouter from django.core.asgi import get_asgi_application +import chat.routing + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "your_project_name.settings") + +django_asgi_app = get_asgi_application() os.environ.setdefault("DJANGO_SETTINGS_MODULE", "server.settings") +application = ProtocolTypeRouter({ + "http": django_asgi_app, +}) -application = get_asgi_application() +ASGI_APPLICATION = 'server.asgi.application' \ No newline at end of file diff --git a/server/server/settings.py b/server/server/settings.py index 799c4eb..d3f3830 100644 --- a/server/server/settings.py +++ b/server/server/settings.py @@ -38,6 +38,8 @@ # Application definition INSTALLED_APPS = [ + # "chats.apps.serverConfig" + "daphne", "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", @@ -49,6 +51,8 @@ "corsheaders", "healthcheck", # "user_profile", + "channels", + "chat", "user", "event", "tag", @@ -98,6 +102,7 @@ ] WSGI_APPLICATION = "server.wsgi.application" +ASGI_APPLICATION = "server.asgi.application" # Database @@ -173,3 +178,9 @@ # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +# CHANNEL_LAYERS = { +# "default": { +# "BACKEND": "channels.layers.InMemoryChannelLayer", +# } +# } \ No newline at end of file diff --git a/server/server/urls.py b/server/server/urls.py index a1b8950..f0beb4a 100644 --- a/server/server/urls.py +++ b/server/server/urls.py @@ -26,9 +26,8 @@ path("admin/", admin.site.urls), # using JWT for auth for front end - path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), - path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh_view"), - path("api-auth/", include("rest_framework.urls")), + path("api/user/login/", TokenObtainPairView.as_view(), name="login"), + path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), # URLS for meaningful stuff path("api/healthcheck/", include("healthcheck.urls")), diff --git a/server/user/serializers.py b/server/user/serializers.py index 84b7c66..72f35c6 100644 --- a/server/user/serializers.py +++ b/server/user/serializers.py @@ -21,17 +21,20 @@ class Meta: "is_superuser", "profile",) -class RegisterSerializer(serializers.ModelSerializer): - password = serializers.CharField(write_only=True) +class SignupSerializer(serializers.ModelSerializer): + password2 = serializers.CharField(write_only=True, required=True) class Meta: model = User - fields = ("username", "email", "password") + fields = ['username', 'email', 'first_name', 'last_name', 'password', 'password2'] + extra_kwargs = {'password': {'write_only': True}} + + def validate(self, data): + if data['password'] != data['password2']: + raise serializers.ValidationError("Passwords do not match") + return data def create(self, validated_data): - user = User.objects.create_user( - username=validated_data["username"], - email=validated_data.get("email", ""), - password=validated_data["password"], - ) - return user \ No newline at end of file + validated_data.pop('password2') + user = User.objects.create_user(**validated_data) + return user diff --git a/server/user/urls.py b/server/user/urls.py index 0d1987d..5f4866e 100644 --- a/server/user/urls.py +++ b/server/user/urls.py @@ -6,7 +6,7 @@ path("", views.UserList.as_view(), name="user-list"), path("profile/", views.UserProfileList.as_view(), name="profile-list"), path("profile//", views.UserProfileDetail.as_view(), name="user-profile-detail"), + path('signup/', views.SignupView.as_view(), name='signup'), path("register/", views.RegisterView.as_view(), name="user-register"), path("me/", views.MeView.as_view(), name="me"), - ] - + ] \ No newline at end of file diff --git a/server/user/views.py b/server/user/views.py index b3e73ef..8bdbeb7 100644 --- a/server/user/views.py +++ b/server/user/views.py @@ -1,17 +1,23 @@ from django.shortcuts import render from rest_framework import generics, permissions, status -from rest_framework.generics import ListAPIView from rest_framework.response import Response from rest_framework.views import APIView from .permissions import IsUserOrReadOnly from rest_framework.permissions import AllowAny from .models import Profile, User -from .serializers import ProfileSerializer, UserSerializer, RegisterSerializer -from rest_framework.permissions import AllowAny # 暂时加上 +from .serializers import ProfileSerializer, UserSerializer, SignupSerializer -# Create your views here. +class SignupView(generics.CreateAPIView): + serializer_class = SignupSerializer + + def post(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + if serializer.is_valid(): + serializer.save() + return Response({"message": "User created successfully"}, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class UserList(APIView): permission_classes = (AllowAny,)#permissions.IsAuthenticated @@ -41,7 +47,7 @@ def get(self, request): class RegisterView(APIView): authentication_classes = [] permission_classes = [AllowAny] - serializer_class = RegisterSerializer + serializer_class = UserSerializer def post(self, request): serializer = RegisterSerializer(data=request.data) if serializer.is_valid(): diff --git a/server/user_profile/__init__.py b/server/user_profile/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/user_profile/admin.py b/server/user_profile/admin.py new file mode 100644 index 0000000..bf51dd6 --- /dev/null +++ b/server/user_profile/admin.py @@ -0,0 +1,7 @@ + +from .models import Profile +from django.contrib import admin + +# Register your models here. +admin.site.register(Profile) + diff --git a/server/user_profile/apps.py b/server/user_profile/apps.py new file mode 100644 index 0000000..fe0436b --- /dev/null +++ b/server/user_profile/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class UserProfileConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'user_profile' diff --git a/server/user_profile/migrations/0001_initial.py b/server/user_profile/migrations/0001_initial.py new file mode 100644 index 0000000..4427334 --- /dev/null +++ b/server/user_profile/migrations/0001_initial.py @@ -0,0 +1,26 @@ +# Generated by Django 5.2.8 on 2025-11-29 06:33 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('bio', models.TextField()), + ('age', models.PositiveIntegerField(null=True)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/server/user_profile/migrations/__init__.py b/server/user_profile/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/user_profile/models.py b/server/user_profile/models.py new file mode 100644 index 0000000..fd28b8a --- /dev/null +++ b/server/user_profile/models.py @@ -0,0 +1,20 @@ +from django.contrib.auth import get_user_model +from django.db import models +from django.db.models.signals import post_save +from django.dispatch import receiver + +# Create your models here. + +User = get_user_model() + +class Profile(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + bio = models.TextField(blank=True) + age = models.PositiveIntegerField(null=True, blank=True) + + def __str__(self): + return f"Profile: {self.user.username}" + +@receiver(post_save, sender=User) +def create_or_update_user_profile(sender, instance, created, **kwargs): + Profile.objects.get_or_create(user=instance) \ No newline at end of file diff --git a/server/user_profile/permissions.py b/server/user_profile/permissions.py new file mode 100644 index 0000000..37b8a61 --- /dev/null +++ b/server/user_profile/permissions.py @@ -0,0 +1,12 @@ +from rest_framework import permissions +from django.contrib.auth import get_user_model + +User = get_user_model() + +class IsUserOrReadOnly(permissions.BasePermission): + def has_object_permission(self, request, view, obj): + if isinstance(obj, User): + # If this is for the user object check against logged in user + return obj == request.user + # otherwise check user field against logged in user + return obj.user == request.user \ No newline at end of file diff --git a/server/user_profile/serializers.py b/server/user_profile/serializers.py new file mode 100644 index 0000000..f978de0 --- /dev/null +++ b/server/user_profile/serializers.py @@ -0,0 +1,22 @@ +from rest_framework import serializers +from .models import Profile, User + +class ProfileSerializer(serializers.ModelSerializer): + class Meta: + model = Profile + fields = "__all__" + +class UserSerializer(serializers.ModelSerializer): + profile = ProfileSerializer(read_only=True) + + class Meta: + model = User + fields = ( + "id", + "username", + "email", + "first_name", + "last_name", + "is_staff", + "is_superuser" + ) \ No newline at end of file diff --git a/server/user_profile/tests.py b/server/user_profile/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/server/user_profile/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/user_profile/urls.py b/server/user_profile/urls.py new file mode 100644 index 0000000..22d848e --- /dev/null +++ b/server/user_profile/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from . import views + +app_name = "user_profile" +urlpatterns = [ + path("", views.UserList.as_view(), name="user-list"), + path("profile/", views.UserProfileList.as_view(), name="profile-list"), + path("profile//", views.UserProfileDetail.as_view(), name="profile_detail") +] \ No newline at end of file diff --git a/server/user_profile/views.py b/server/user_profile/views.py new file mode 100644 index 0000000..64fc6c6 --- /dev/null +++ b/server/user_profile/views.py @@ -0,0 +1,25 @@ +from django.shortcuts import render +from rest_framework import generics, permissions +from rest_framework.response import Response +from rest_framework.views import APIView +from .permissions import IsUserOrReadOnly +from .models import Profile, User +from .serializers import ProfileSerializer, UserSerializer + +# Create your views here. + +class UserList(APIView): + permission_classes = (permissions.IsAuthenticated,) + def get(self, request): + users = User.objects.all() + serializer = UserSerializer(users, many=True) + return Response(serializer.data) + +class UserProfileList(generics.ListAPIView): + queryset = Profile.objects.all() + serializer_class = ProfileSerializer + +class UserProfileDetail(generics.RetrieveUpdateAPIView): + permission_classes = (permissions.IsAuthenticated, IsUserOrReadOnly) + queryset = Profile.objects.all() + serializer_class = ProfileSerializer \ No newline at end of file From e7992a4265ed1b38b44946ea01fc1e391f4f463f Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Wed, 7 Jan 2026 08:23:35 +0800 Subject: [PATCH 79/94] bug fix [chat]: Adds authentication loading state to prevent premature redirects on protected routes. --- client/src/context/AuthContext.tsx | 12 +++++++++++- client/src/pages/chat.tsx | 9 +++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/client/src/context/AuthContext.tsx b/client/src/context/AuthContext.tsx index b9cd112..0582607 100644 --- a/client/src/context/AuthContext.tsx +++ b/client/src/context/AuthContext.tsx @@ -13,6 +13,7 @@ type AuthContextType = { login: (access: string, refresh: string) => void; logout: () => void; isLoggedIn: boolean; + isLoading: boolean; }; const AuthContext = createContext(undefined); @@ -20,6 +21,7 @@ const AuthContext = createContext(undefined); export const AuthProvider = ({ children }: { children: ReactNode }) => { const [accessToken, setAccessToken] = useState(null); const [refreshToken, setRefreshToken] = useState(null); + const [isLoading, setIsLoading] = useState(true); const router = useRouter(); useEffect(() => { @@ -27,6 +29,7 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { const storedRefresh = localStorage.getItem("refreshToken"); if (storedAccess) setAccessToken(storedAccess); if (storedRefresh) setRefreshToken(storedRefresh); + setIsLoading(false); }, []); const login = (access: string, refresh: string) => { @@ -48,7 +51,14 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { return ( {children} diff --git a/client/src/pages/chat.tsx b/client/src/pages/chat.tsx index f86ba4a..59b5932 100644 --- a/client/src/pages/chat.tsx +++ b/client/src/pages/chat.tsx @@ -5,15 +5,16 @@ import Layout from "@/components/Layout"; import { useAuth } from "@/context/AuthContext"; export default function Chat() { - const { isLoggedIn } = useAuth(); + const { isLoggedIn, isLoading } = useAuth(); const router = useRouter(); useEffect(() => { - if (!isLoggedIn) { + if (!isLoading && !isLoggedIn) { router.push("/login"); } - }, [isLoggedIn, router]); + }, [isLoggedIn, isLoading, router]); - if (!isLoggedIn) return

Redirecting to login...

; + if (isLoading) return

Loading...

; + if (!isLoggedIn) return null; return This is the chat page; } From 33befc06ba8a3b703351ec8bd08b22db3874783d Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Thu, 8 Jan 2026 09:03:52 +0800 Subject: [PATCH 80/94] feature fix [login]: uses new login page, uses correct authentication, api interceptor updated --- client/src/lib/api.ts | 6 +- client/src/pages/login.tsx | 137 ++++++++++++++++++++++--------------- 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/client/src/lib/api.ts b/client/src/lib/api.ts index c98893a..31ce4a5 100644 --- a/client/src/lib/api.ts +++ b/client/src/lib/api.ts @@ -1,13 +1,11 @@ import axios from "axios"; -import { clearTokens,getAccessToken } from "./auth"; - // use env URL to call API const api = axios.create({ baseURL: process.env.NEXT_PUBLIC_BACKEND_URL }); // request interceptor attaches bearer token (logins & non public pages) api.interceptors.request.use((config) => { - const token = getAccessToken(); + const token = localStorage.getItem("accessToken"); if (token) { config.headers.Authorization = `Bearer ${token}`; } @@ -21,8 +19,6 @@ api.interceptors.response.use( }, (error) => { if (error.response?.status === 401) { - clearTokens(); - // Redirect to login page if (typeof window !== "undefined") { window.location.href = "/login"; diff --git a/client/src/pages/login.tsx b/client/src/pages/login.tsx index 0e0a379..c31fcce 100644 --- a/client/src/pages/login.tsx +++ b/client/src/pages/login.tsx @@ -1,76 +1,99 @@ +import Link from "next/link"; import { useRouter } from "next/router"; import { useState } from "react"; -import Layout from "@/components/Layout"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; import { useAuth } from "@/context/AuthContext"; +import api from "@/lib/api"; -export default function LoginPage() { +export default function Login() { const router = useRouter(); const { login } = useAuth(); - const [form, setForm] = useState({ username: "", password: "" }); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); const [message, setMessage] = useState(""); - const handleChange = (e: React.ChangeEvent) => { - setForm({ ...form, [e.target.name]: e.target.value }); - }; - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setMessage(""); - + //function to return JWT + const handleLogin = async () => { try { - const res = await fetch("http://localhost:8000/api/user/login/", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(form), + const res = await api.post("/user/login/", { + username, + password, }); - const data = await res.json(); + const { access, refresh } = res.data; + login(access, refresh); - if (res.ok) { - login(data.access, data.refresh); - router.push("/"); - } else { - setMessage(data.detail || "Login failed"); - } - } catch (error) { - // Temporary fix to commit - const x = error; - console.log(x); - setMessage("Login failed. Please try again"); + // redirect based on role + const me = await api.get("/user/me/"); + const role = me.data.profile.role; + router.push(role === "manager" ? "/manager/dashboard" : "/home"); + } catch (err) { + console.log(err); + setMessage("Login failed. Please check your credentials."); } }; return ( - -
-

Login

- {message &&

{message}

} -
- - - + + + + {message && ( +

+ {message} +

+ )} + +
+
+ setUsername(e.target.value)} + /> +
+
+ + setPassword(e.target.value)} + /> +
+
+ +
+ + - -
-
+ + + +
); } From 7715ffc631ced7299444dd38e52a7a52d5763ada Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Thu, 8 Jan 2026 10:39:36 +0800 Subject: [PATCH 81/94] feature fix [home]: now redirects based on profile role (manager), toasts added for status updates --- client/package-lock.json | 39 +++++++++-------- client/package.json | 2 + client/src/components/ui/sonner.tsx | 43 ++++++++++++++++++ client/src/pages/_app.tsx | 2 + client/src/pages/home.tsx | 30 ++++++++++--- client/src/pages/login.tsx | 68 +++++++++++++---------------- 6 files changed, 121 insertions(+), 63 deletions(-) create mode 100644 client/src/components/ui/sonner.tsx diff --git a/client/package-lock.json b/client/package-lock.json index 8d2c600..4e45e6d 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -22,8 +22,10 @@ "jwt-decode": "^4.0.0", "lucide-react": "^0.516.0", "next": "^15.5.9", + "next-themes": "^0.4.6", "react": "19.1.0", "react-dom": "19.1.0", + "sonner": "^2.0.7", "tailwind-merge": "^3.3.1", "tailwindcss-animate": "^1.0.7" }, @@ -149,7 +151,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -173,7 +174,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -1846,7 +1846,6 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.80.7.tgz", "integrity": "sha512-u2F0VK6+anItoEvB3+rfvTO9GEh2vb00Je05OwlUe/A0lkJBgW1HckiY3f9YZa+jx6IOe4dHPh10dyp9aY3iRQ==", "license": "MIT", - "peer": true, "dependencies": { "@tanstack/query-core": "5.80.7" }, @@ -1912,7 +1911,6 @@ "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -1923,7 +1921,6 @@ "integrity": "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.0.0" } @@ -1934,7 +1931,6 @@ "integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.34.1", "@typescript-eslint/types": "8.34.1", @@ -2139,7 +2135,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2581,7 +2576,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001718", "electron-to-chromium": "^1.5.160", @@ -3318,7 +3312,6 @@ "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -3524,7 +3517,6 @@ "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -5023,7 +5015,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -5551,6 +5542,15 @@ } } }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -5956,7 +5956,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -6062,7 +6061,6 @@ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -6205,7 +6203,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -6215,7 +6212,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -6704,6 +6700,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/sonner": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", + "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -7080,7 +7085,6 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "license": "MIT", - "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -7335,7 +7339,6 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7664,4 +7667,4 @@ } } } -} \ No newline at end of file +} diff --git a/client/package.json b/client/package.json index 8e8832e..89db1b9 100644 --- a/client/package.json +++ b/client/package.json @@ -29,8 +29,10 @@ "jwt-decode": "^4.0.0", "lucide-react": "^0.516.0", "next": "^15.5.9", + "next-themes": "^0.4.6", "react": "19.1.0", "react-dom": "19.1.0", + "sonner": "^2.0.7", "tailwind-merge": "^3.3.1", "tailwindcss-animate": "^1.0.7" }, diff --git a/client/src/components/ui/sonner.tsx b/client/src/components/ui/sonner.tsx new file mode 100644 index 0000000..ef50e2f --- /dev/null +++ b/client/src/components/ui/sonner.tsx @@ -0,0 +1,43 @@ +import { + CircleCheck, + Info, + LoaderCircle, + OctagonX, + TriangleAlert, +} from "lucide-react"; +import { useTheme } from "next-themes"; +import { Toaster as Sonner } from "sonner"; + +type ToasterProps = React.ComponentProps; + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = "system" } = useTheme(); + + return ( + , + info: , + warning: , + error: , + loading: , + }} + toastOptions={{ + classNames: { + toast: + "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg", + description: "group-[.toast]:text-muted-foreground", + actionButton: + "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground", + cancelButton: + "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground", + }, + }} + {...props} + /> + ); +}; + +export { Toaster }; diff --git a/client/src/pages/_app.tsx b/client/src/pages/_app.tsx index a242830..b9297eb 100644 --- a/client/src/pages/_app.tsx +++ b/client/src/pages/_app.tsx @@ -4,6 +4,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import type { AppProps } from "next/app"; +import { Toaster } from "@/components/ui/sonner"; import { AuthProvider } from "@/context/AuthContext"; const queryClient = new QueryClient(); @@ -14,6 +15,7 @@ export default function App({ Component, pageProps }: AppProps) { + ); diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index c61d811..fab6024 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -1,21 +1,37 @@ import { useRouter } from "next/router"; +import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import EventCard from "@/components/ui/event-card"; +import { useAuth } from "@/context/AuthContext"; import { useEvents } from "@/hooks/events"; import { useMe } from "@/hooks/me"; -import { clearTokens } from "@/lib/auth"; import SearchDock from "../components/ui/search-dock"; import DockLayout from "./layouts/docklayout"; export default function Home() { - const { data: events, isLoading } = useEvents(); - const { data: me } = useMe(); + const { data: events, isLoading: eventsLoading } = useEvents(); + const { logout } = useAuth(); const router = useRouter(); + const { data: me, isLoading: meLoading } = useMe(); - const logout = () => { - clearTokens(); + if (me?.profile.role === "manager") { + router.replace("/manager/dashboard"); + return null; + } + + if (meLoading) { + return ( +
+ Loading… +
+ ); + } + + const handleLogout = () => { + logout(); + toast("Logged out successfully"); router.push("/login"); }; @@ -28,10 +44,10 @@ export default function Home() {

Hello {me.first_name} ({me.username} {me.profile.role})

- + )} - {!isLoading && + {!eventsLoading && events?.map((event) => ( ))} diff --git a/client/src/pages/login.tsx b/client/src/pages/login.tsx index c31fcce..1de7035 100644 --- a/client/src/pages/login.tsx +++ b/client/src/pages/login.tsx @@ -1,6 +1,7 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { useState } from "react"; +import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { @@ -17,14 +18,14 @@ import api from "@/lib/api"; export default function Login() { const router = useRouter(); - const { login } = useAuth(); + const { login, logout } = useAuth(); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); - const [message, setMessage] = useState(""); //function to return JWT const handleLogin = async () => { try { + logout(); const res = await api.post("/user/login/", { username, password, @@ -32,13 +33,11 @@ export default function Login() { const { access, refresh } = res.data; login(access, refresh); - // redirect based on role - const me = await api.get("/user/me/"); - const role = me.data.profile.role; - router.push(role === "manager" ? "/manager/dashboard" : "/home"); + toast("Logged in successfully"); + router.push("/home"); } catch (err) { console.log(err); - setMessage("Login failed. Please check your credentials."); + toast("Login failed. Please check your credentials."); } }; @@ -55,41 +54,34 @@ export default function Login() { - {message && ( -

- {message} -

- )} -
-
-
- setUsername(e.target.value)} - /> -
-
- - setPassword(e.target.value)} - /> +
+
+ setUsername(e.target.value)} + /> +
+
+
+
+ setPassword(e.target.value)} + />
- +
- From 230599367afc25527ab218ddf36f726a1c6997d7 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Thu, 8 Jan 2026 10:47:02 +0800 Subject: [PATCH 82/94] feature fix [profile]: profiles now fetch correctly using me hook --- client/src/pages/profile.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/src/pages/profile.tsx b/client/src/pages/profile.tsx index 8dd771a..b61dfdc 100644 --- a/client/src/pages/profile.tsx +++ b/client/src/pages/profile.tsx @@ -6,16 +6,16 @@ import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardFooter } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; -import { useUserProfile } from "@/hooks/userprofile"; +import { useMe } from "@/hooks/me"; import Layout from "./layout"; export default function Home() { const router = useRouter(); - const { data, isLoading } = useUserProfile(); + const { data: me, isLoading } = useMe(); useEffect(() => { - console.log("user profile:", data); - }, [data]); + console.log("user profile:", me); + }, [me]); return ( @@ -28,12 +28,12 @@ export default function Home() {

- {isLoading ? "Loading" : data?.username} + {isLoading ? "Loading" : me?.username}

- {isLoading ? "Loading" : data?.email} + {isLoading ? "Loading" : me?.email}

@@ -53,7 +53,7 @@ export default function Home() {
-
{data?.profile.profile_info}
+
{me?.profile.profile_info}
} primaryAction={ - +
@@ -448,7 +637,7 @@ export default function AboutPage() { variant="outline" className={`w-full ${COLORS.button.outline} py-6 text-lg`} > - Sign In + Create Account {/* Placeholder, there is no link rn */} From b6814093862b667ff643f003a62976db92b29e50 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Sat, 10 Jan 2026 10:28:14 +0800 Subject: [PATCH 86/94] updated the ui of the event hub --- client/src/pages/events/[id]/hub.tsx | 55 ++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/client/src/pages/events/[id]/hub.tsx b/client/src/pages/events/[id]/hub.tsx index 1c6219e..b42bff0 100644 --- a/client/src/pages/events/[id]/hub.tsx +++ b/client/src/pages/events/[id]/hub.tsx @@ -1,7 +1,10 @@ +import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/router"; +import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; import { useEvent } from "@/hooks/events"; import ActionLayout from "@/pages/layouts/actionlayout"; @@ -25,21 +28,51 @@ export default function ParticipantsPage() { } primaryAction={ - - + + } > - {!isLoading && event?.participants && event.participants.length > 0 && ( -
- {event.participants.map((p) => ( -

{p.username}

- ))} +
+
+ {event?.images?.[0]?.image && ( + {event.event_name} + )}
- )} + {!isLoading && + event?.participants && + event.participants.length > 0 && ( +
+ {event.participants.map((p) => ( + + + + + {p.username.slice(0, 2).toUpperCase()} + + + +
+

{p.username}

+

+ Attending this event +

+
+ + +
+
+ ))} +
+ )} +
{!isLoading && event?.participants?.length === 0 && (

No participants yet.

From a4da16a72b0b8229eeb8484fa73ebc146bdc31d1 Mon Sep 17 00:00:00 2001 From: Coffee <153749000+CoffeeFolf@users.noreply.github.com> Date: Sat, 10 Jan 2026 11:23:03 +0800 Subject: [PATCH 87/94] added get in touch section in index.tsx --- client/src/pages/index.tsx | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/client/src/pages/index.tsx b/client/src/pages/index.tsx index 97d8448..441dd07 100644 --- a/client/src/pages/index.tsx +++ b/client/src/pages/index.tsx @@ -664,6 +664,48 @@ export default function AboutPage() { }

+
+ {[ + { + title: "gen", + email: "generalenquiries@gmail.com", + desc: "General Inquiries", + icon: Mail, + }, + { + title: "stu", + email: "studentenquiries@gmail.com", + desc: "Student Inquiries", + icon: Users, + }, + { + title: "org", + email: "organiserenquiries@gmail.com", + desc: "Event Organiser Inquiries", + icon: Star, + }, + ].map((value, index) => ( + + + +

+ {value.desc} +

+ + {value.email} + +
+
+ ))} +
); From f6dc6bec14c7629f725068f1ae4381ed9baf8163 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Sat, 10 Jan 2026 11:23:06 +0800 Subject: [PATCH 88/94] added confetti to hub --- client/package-lock.json | 20 ++++++++++++++++++++ client/package.json | 1 + client/src/pages/events/[id]/hub.tsx | 4 +++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/client/package-lock.json b/client/package-lock.json index 4e45e6d..1dc905a 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -24,6 +24,7 @@ "next": "^15.5.9", "next-themes": "^0.4.6", "react": "19.1.0", + "react-confetti": "^6.4.0", "react-dom": "19.1.0", "sonner": "^2.0.7", "tailwind-merge": "^3.3.1", @@ -6207,6 +6208,20 @@ "node": ">=0.10.0" } }, + "node_modules/react-confetti": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.4.0.tgz", + "integrity": "sha512-5MdGUcqxrTU26I2EU7ltkWPwxvucQTuqMm8dUz72z2YMqTD6s9vMcDUysk7n9jnC+lXuCPeJJ7Knf98VEYE9Rg==", + "dependencies": { + "tween-functions": "^1.2.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.1 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/react-dom": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", @@ -7242,6 +7257,11 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tween-functions": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", + "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/client/package.json b/client/package.json index 89db1b9..8f17c89 100644 --- a/client/package.json +++ b/client/package.json @@ -31,6 +31,7 @@ "next": "^15.5.9", "next-themes": "^0.4.6", "react": "19.1.0", + "react-confetti": "^6.4.0", "react-dom": "19.1.0", "sonner": "^2.0.7", "tailwind-merge": "^3.3.1", diff --git a/client/src/pages/events/[id]/hub.tsx b/client/src/pages/events/[id]/hub.tsx index b42bff0..5ffc553 100644 --- a/client/src/pages/events/[id]/hub.tsx +++ b/client/src/pages/events/[id]/hub.tsx @@ -1,6 +1,7 @@ import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/router"; +import Confetti from "react-confetti"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; @@ -17,6 +18,7 @@ export default function ParticipantsPage() { return ( <> + 0 && ( -
+
{event.participants.map((p) => ( From a65ccd24e2e0b398b1e1f2ac8e46bb5d3626fa30 Mon Sep 17 00:00:00 2001 From: Coffee <153749000+CoffeeFolf@users.noreply.github.com> Date: Sat, 10 Jan 2026 12:48:44 +0800 Subject: [PATCH 89/94] Linked login, and added packages --- client/src/pages/index.tsx | 47 +++- server/pyproject.toml | 2 + server/uv.lock | 443 +++++++++++++++++++++++++++++++++++++ 3 files changed, 485 insertions(+), 7 deletions(-) diff --git a/client/src/pages/index.tsx b/client/src/pages/index.tsx index 441dd07..377757b 100644 --- a/client/src/pages/index.tsx +++ b/client/src/pages/index.tsx @@ -14,12 +14,16 @@ import { Users, Workflow, } from "lucide-react"; -import React from "react"; +import { useRouter } from "next/router"; +import React, { useState } from "react"; +import { toast } from "sonner"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; +import { useAuth } from "@/context/AuthContext"; +import api from "@/lib/api"; // Added this so that we can change colors more easily const COLORS = { @@ -98,6 +102,30 @@ const scrollTo = (id: string) => { }; export default function AboutPage() { + const router = useRouter(); + const { login, logout } = useAuth(); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + + //function to return JWT + const handleLogin = async () => { + try { + logout(); + const res = await api.post("/user/login/", { + username, + password, + }); + const { access, refresh } = res.data; + login(access, refresh); + + toast("Logged in successfully"); + router.push("/home"); + } catch (err) { + console.log(err); + toast("Login failed. Please check your credentials."); + } + }; + return (
{/* nav */} @@ -588,12 +616,14 @@ export default function AboutPage() { setUsername(e.target.value)} />
@@ -603,9 +633,11 @@ export default function AboutPage() { Password setPassword(e.target.value)} />
@@ -613,6 +645,7 @@ export default function AboutPage() { diff --git a/server/pyproject.toml b/server/pyproject.toml index 3c69647..9c34b7f 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -14,6 +14,8 @@ dependencies = [ "psycopg[binary,pool]~=3.2.13", "djangorestframework-simplejwt>=5.5.1", "pillow", + "daphne>=4.2.1", + "channels>=4.3.2", ] [dependency-groups] diff --git a/server/uv.lock b/server/uv.lock index a5c3509..62a4641 100644 --- a/server/uv.lock +++ b/server/uv.lock @@ -11,6 +11,131 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/91/be/317c2c55b8bbec407257d45f5c8d1b6867abc76d12043f2d3d58c538a4ea/asgiref-3.11.0-py3-none-any.whl", hash = "sha256:1db9021efadb0d9512ce8ffaf72fcef601c7b73a8807a1bb2ef143dc6b14846d", size = 24096, upload-time = "2025-11-19T15:32:19.004Z" }, ] +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "autobahn" +version = "25.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cbor2" }, + { name = "cffi" }, + { name = "cryptography" }, + { name = "hyperlink" }, + { name = "msgpack", marker = "platform_python_implementation == 'CPython'" }, + { name = "py-ubjson" }, + { name = "txaio" }, + { name = "u-msgpack-python", marker = "platform_python_implementation != 'CPython'" }, + { name = "ujson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/d5/9adf0f5b9eb244e58e898e9f3db4b00c09835ef4b6c37d491886e0376b4f/autobahn-25.12.2.tar.gz", hash = "sha256:754c06a54753aeb7e8d10c5cbf03249ad9e2a1a32bca8be02865c6f00628a98c", size = 13893652, upload-time = "2025-12-15T11:13:19.086Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/30/ef9c47038e4e9257319d6e1b87668b3df360a0c488d66ccff9d11aaff6ba/autobahn-25.12.2-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:bc17f6cab9438156d2701c293c76fd02a144f9be0a992c065dfee1935ce4845b", size = 1960447, upload-time = "2025-12-15T11:13:05.007Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e4/f3d5cb70bc0b9b5523d940734b2e0a251510d051a50d2e723f321e890859/autobahn-25.12.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5297a782fc7d0a26842438ef1342549ceee29496cda52672ac44635c79eeb94", size = 2053955, upload-time = "2025-12-15T11:13:06.052Z" }, + { url = "https://files.pythonhosted.org/packages/ea/49/4e592a19ae58fd9c796821a882b22598fac295ede50f899cc9d14a0282b6/autobahn-25.12.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0c3f1d5dafda52f8dc962ab583b6f3473b7b7186cab082d05372ed43a8261a5", size = 2225441, upload-time = "2025-12-15T11:13:07.527Z" }, + { url = "https://files.pythonhosted.org/packages/ed/f7/430074a5ea3f6187335a4ddc26f16dd75d5125e346a84cf132ddbd41a3e8/autobahn-25.12.2-cp313-cp313-win_amd64.whl", hash = "sha256:e9e2a962f2de0bc4c53b452916458417a15f5137c956245ac6d0a783a83fa1f7", size = 2151873, upload-time = "2025-12-15T11:13:08.89Z" }, + { url = "https://files.pythonhosted.org/packages/54/b7/0a0e3ecb2af7e452f5f359d19bdc647cbc8658f3f498bfa3bf8545cf4768/autobahn-25.12.2-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c840ee136bfaf6560467160129b0b25a0e33c9a51e2b251e98c5474f27583915", size = 1960463, upload-time = "2025-12-15T11:13:10.183Z" }, + { url = "https://files.pythonhosted.org/packages/19/8b/4215ac49d6b793b592fb08698f3a0e21a59eb3520be7f7ed288fcb52d919/autobahn-25.12.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9abda5cf817c0f8a19a55a67a031adf2fc70ed351719b5bd9e6fa0f5f4bc8f89", size = 2225590, upload-time = "2025-12-15T11:13:11.367Z" }, + { url = "https://files.pythonhosted.org/packages/f6/58/e498821606db57305c8f3c26d9b28fd73e4e0583a1f48330df500721c418/autobahn-25.12.2-cp314-cp314-win_amd64.whl", hash = "sha256:18b12e8af7fc115487715afa10b3f5b5a4b5989bebbe05b71722cf9fce7b1bfb", size = 2184111, upload-time = "2025-12-15T11:13:12.461Z" }, +] + +[[package]] +name = "automat" +version = "25.4.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/0f/d40bbe294bbf004d436a8bcbcfaadca8b5140d39ad0ad3d73d1a8ba15f14/automat-25.4.16.tar.gz", hash = "sha256:0017591a5477066e90d26b0e696ddc143baafd87b588cfac8100bc6be9634de0", size = 129977, upload-time = "2025-04-16T20:12:16.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl", hash = "sha256:04e9bce696a8d5671ee698005af6e5a9fa15354140a87f4870744604dcdd3ba1", size = 42842, upload-time = "2025-04-16T20:12:14.447Z" }, +] + +[[package]] +name = "cbor2" +version = "5.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d9/8e/8b4fdde28e42ffcd741a37f4ffa9fb59cd4fe01625b544dfcfd9ccb54f01/cbor2-5.8.0.tar.gz", hash = "sha256:b19c35fcae9688ac01ef75bad5db27300c2537eb4ee00ed07e05d8456a0d4931", size = 107825, upload-time = "2025-12-30T18:44:22.455Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/0d/5a3f20bafaefeb2c1903d961416f051c0950f0d09e7297a3aa6941596b29/cbor2-5.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6d8d104480845e2f28c6165b4c961bbe58d08cb5638f368375cfcae051c28015", size = 70332, upload-time = "2025-12-30T18:43:54.694Z" }, + { url = "https://files.pythonhosted.org/packages/57/66/177a3f089e69db69c987453ab4934086408c3338551e4984734597be9f80/cbor2-5.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:43efee947e5ab67d406d6e0dc61b5dee9d2f5e89ae176f90677a3741a20ca2e7", size = 285985, upload-time = "2025-12-30T18:43:55.733Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8e/9e17b8e4ed80a2ce97e2dfa5915c169dbb31599409ddb830f514b57f96cc/cbor2-5.8.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be7ae582f50be539e09c134966d0fd63723fc4789b8dff1f6c2e3f24ae3eaf32", size = 285173, upload-time = "2025-12-30T18:43:57.321Z" }, + { url = "https://files.pythonhosted.org/packages/cc/33/9f92e107d78f88ac22723ac15d0259d220ba98c1d855e51796317f4c4114/cbor2-5.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:50f5c709561a71ea7970b4cd2bf9eda4eccacc0aac212577080fdfe64183e7f5", size = 278395, upload-time = "2025-12-30T18:43:58.497Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3f/46b80050a4a35ce5cf7903693864a9fdea7213567dc8faa6e25cb375c182/cbor2-5.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a6790ecc73aa93e76d2d9076fc42bf91a9e69f2295e5fa702e776dbe986465bd", size = 278330, upload-time = "2025-12-30T18:43:59.656Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d2/d41f8c04c783a4d204e364be2d38043d4f732a3bed6f4c732e321cf34c7b/cbor2-5.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:c114af8099fa65a19a514db87ce7a06e942d8fea2730afd49be39f8e16e7f5e0", size = 69841, upload-time = "2025-12-30T18:44:01.159Z" }, + { url = "https://files.pythonhosted.org/packages/1b/8c/0397a82f6e67665009951453c83058e4c77ba54b9a9017ede56d6870306c/cbor2-5.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:ab3ba00494ad8669a459b12a558448d309c271fa4f89b116ad496ee35db38fea", size = 64982, upload-time = "2025-12-30T18:44:02.138Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0c/0654233d7543ac8a50f4785f172430ddc97538ba418eb305d6e529d1a120/cbor2-5.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ad72381477133046ce217617d839ea4e9454f8b77d9a6351b229e214102daeb7", size = 70710, upload-time = "2025-12-30T18:44:03.209Z" }, + { url = "https://files.pythonhosted.org/packages/84/62/4671d24e557d7f5a74a01b422c538925140c0495e57decde7e566f91d029/cbor2-5.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6da25190fad3434ce99876b11d4ca6b8828df6ca232cf7344cd14ae1166fb718", size = 285005, upload-time = "2025-12-30T18:44:05.109Z" }, + { url = "https://files.pythonhosted.org/packages/87/85/0c67d763a08e848c9a80d7e4723ba497cce676f41bc7ca1828ae90a0a872/cbor2-5.8.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c13919e3a24c5a6d286551fa288848a4cedc3e507c58a722ccd134e461217d99", size = 282435, upload-time = "2025-12-30T18:44:06.465Z" }, + { url = "https://files.pythonhosted.org/packages/b2/01/0650972b4dbfbebcfbe37cbba7fc3cd9019a8da6397ab3446e07175e342b/cbor2-5.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f8c40d32e5972047a777f9bf730870828f3cf1c43b3eb96fd0429c57a1d3b9e6", size = 277493, upload-time = "2025-12-30T18:44:07.609Z" }, + { url = "https://files.pythonhosted.org/packages/b3/6c/7704a4f32adc7f10f3b41ec067f500a4458f7606397af5e4cf2d368fd288/cbor2-5.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7627894bc0b3d5d0807f31e3107e11b996205470c4429dc2bb4ef8bfe7f64e1e", size = 276085, upload-time = "2025-12-30T18:44:09.021Z" }, + { url = "https://files.pythonhosted.org/packages/88/6d/e43452347630efe8133f5304127539100d937c138c0996d27ec63963ec2c/cbor2-5.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:b51c5e59becae746ca4de2bbaa8a2f5c64a68fec05cea62941b1a84a8335f7d1", size = 71657, upload-time = "2025-12-30T18:44:10.162Z" }, + { url = "https://files.pythonhosted.org/packages/8b/66/9a780ef34ab10a0437666232e885378cdd5f60197b1b5e61a62499e5a10a/cbor2-5.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:53b630f4db4b9f477ad84077283dd17ecf9894738aa17ef4938c369958e02a71", size = 67171, upload-time = "2025-12-30T18:44:11.619Z" }, + { url = "https://files.pythonhosted.org/packages/d6/4f/101071f880b4da05771128c0b89f41e334cff044dee05fb013c8f4be661c/cbor2-5.8.0-py3-none-any.whl", hash = "sha256:3727d80f539567b03a7aa11890e57798c67092c38df9e6c23abb059e0f65069c", size = 24374, upload-time = "2025-12-30T18:44:21.476Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "channels" +version = "4.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/92/b18d4bb54d14986a8b35215a1c9e6a7f9f4d57ca63ac9aee8290ebb4957d/channels-4.3.2.tar.gz", hash = "sha256:f2bb6bfb73ad7fb4705041d07613c7b4e69528f01ef8cb9fb6c21d9295f15667", size = 27023, upload-time = "2025-11-20T15:13:05.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl", hash = "sha256:fef47e9055a603900cf16cef85f050d522d9ac4b3daccf24835bd9580705c176", size = 31313, upload-time = "2025-11-20T15:13:02.357Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -20,6 +145,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "constantly" +version = "23.10.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/6f/cb2a94494ff74aa9528a36c5b1422756330a75a8367bf20bd63171fc324d/constantly-23.10.4.tar.gz", hash = "sha256:aa92b70a33e2ac0bb33cd745eb61776594dc48764b06c35e0efd050b7f1c7cbd", size = 13300, upload-time = "2023-10-28T23:18:24.316Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl", hash = "sha256:3fd9b4d1c3dc1ec9757f3c52aef7e53ad9323dbe39f51dfd4c43853b68dfa3f9", size = 13547, upload-time = "2023-10-28T23:18:23.038Z" }, +] + [[package]] name = "coverage" version = "7.12.0" @@ -81,6 +215,76 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/a3/43b749004e3c09452e39bb56347a008f0a0668aad37324a99b5c8ca91d9e/coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a", size = 209503, upload-time = "2025-11-18T13:34:18.892Z" }, ] +[[package]] +name = "cryptography" +version = "46.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258, upload-time = "2025-10-15T23:18:31.74Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004, upload-time = "2025-10-15T23:16:52.239Z" }, + { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667, upload-time = "2025-10-15T23:16:54.369Z" }, + { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807, upload-time = "2025-10-15T23:16:56.414Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615, upload-time = "2025-10-15T23:16:58.442Z" }, + { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800, upload-time = "2025-10-15T23:17:00.378Z" }, + { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707, upload-time = "2025-10-15T23:17:01.98Z" }, + { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541, upload-time = "2025-10-15T23:17:04.078Z" }, + { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464, upload-time = "2025-10-15T23:17:05.483Z" }, + { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838, upload-time = "2025-10-15T23:17:07.425Z" }, + { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596, upload-time = "2025-10-15T23:17:09.343Z" }, + { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782, upload-time = "2025-10-15T23:17:11.22Z" }, + { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381, upload-time = "2025-10-15T23:17:12.829Z" }, + { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988, upload-time = "2025-10-15T23:17:14.65Z" }, + { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451, upload-time = "2025-10-15T23:17:16.142Z" }, + { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007, upload-time = "2025-10-15T23:17:18.04Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e2/a510aa736755bffa9d2f75029c229111a1d02f8ecd5de03078f4c18d91a3/cryptography-46.0.3-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217", size = 7158012, upload-time = "2025-10-15T23:17:19.982Z" }, + { url = "https://files.pythonhosted.org/packages/73/dc/9aa866fbdbb95b02e7f9d086f1fccfeebf8953509b87e3f28fff927ff8a0/cryptography-46.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5", size = 4288728, upload-time = "2025-10-15T23:17:21.527Z" }, + { url = "https://files.pythonhosted.org/packages/c5/fd/bc1daf8230eaa075184cbbf5f8cd00ba9db4fd32d63fb83da4671b72ed8a/cryptography-46.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715", size = 4435078, upload-time = "2025-10-15T23:17:23.042Z" }, + { url = "https://files.pythonhosted.org/packages/82/98/d3bd5407ce4c60017f8ff9e63ffee4200ab3e23fe05b765cab805a7db008/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54", size = 4293460, upload-time = "2025-10-15T23:17:24.885Z" }, + { url = "https://files.pythonhosted.org/packages/26/e9/e23e7900983c2b8af7a08098db406cf989d7f09caea7897e347598d4cd5b/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459", size = 3995237, upload-time = "2025-10-15T23:17:26.449Z" }, + { url = "https://files.pythonhosted.org/packages/91/15/af68c509d4a138cfe299d0d7ddb14afba15233223ebd933b4bbdbc7155d3/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422", size = 4967344, upload-time = "2025-10-15T23:17:28.06Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e3/8643d077c53868b681af077edf6b3cb58288b5423610f21c62aadcbe99f4/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7", size = 4466564, upload-time = "2025-10-15T23:17:29.665Z" }, + { url = "https://files.pythonhosted.org/packages/0e/43/c1e8726fa59c236ff477ff2b5dc071e54b21e5a1e51aa2cee1676f1c986f/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044", size = 4292415, upload-time = "2025-10-15T23:17:31.686Z" }, + { url = "https://files.pythonhosted.org/packages/42/f9/2f8fefdb1aee8a8e3256a0568cffc4e6d517b256a2fe97a029b3f1b9fe7e/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665", size = 4931457, upload-time = "2025-10-15T23:17:33.478Z" }, + { url = "https://files.pythonhosted.org/packages/79/30/9b54127a9a778ccd6d27c3da7563e9f2d341826075ceab89ae3b41bf5be2/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3", size = 4466074, upload-time = "2025-10-15T23:17:35.158Z" }, + { url = "https://files.pythonhosted.org/packages/ac/68/b4f4a10928e26c941b1b6a179143af9f4d27d88fe84a6a3c53592d2e76bf/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20", size = 4420569, upload-time = "2025-10-15T23:17:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/a3/49/3746dab4c0d1979888f125226357d3262a6dd40e114ac29e3d2abdf1ec55/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de", size = 4681941, upload-time = "2025-10-15T23:17:39.236Z" }, + { url = "https://files.pythonhosted.org/packages/fd/30/27654c1dbaf7e4a3531fa1fc77986d04aefa4d6d78259a62c9dc13d7ad36/cryptography-46.0.3-cp314-cp314t-win32.whl", hash = "sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914", size = 3022339, upload-time = "2025-10-15T23:17:40.888Z" }, + { url = "https://files.pythonhosted.org/packages/f6/30/640f34ccd4d2a1bc88367b54b926b781b5a018d65f404d409aba76a84b1c/cryptography-46.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db", size = 3494315, upload-time = "2025-10-15T23:17:42.769Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8b/88cc7e3bd0a8e7b861f26981f7b820e1f46aa9d26cc482d0feba0ecb4919/cryptography-46.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21", size = 2919331, upload-time = "2025-10-15T23:17:44.468Z" }, + { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248, upload-time = "2025-10-15T23:17:46.294Z" }, + { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089, upload-time = "2025-10-15T23:17:48.269Z" }, + { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029, upload-time = "2025-10-15T23:17:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222, upload-time = "2025-10-15T23:17:51.357Z" }, + { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280, upload-time = "2025-10-15T23:17:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958, upload-time = "2025-10-15T23:17:54.965Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714, upload-time = "2025-10-15T23:17:56.754Z" }, + { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970, upload-time = "2025-10-15T23:17:58.588Z" }, + { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236, upload-time = "2025-10-15T23:18:00.897Z" }, + { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642, upload-time = "2025-10-15T23:18:02.749Z" }, + { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126, upload-time = "2025-10-15T23:18:04.85Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573, upload-time = "2025-10-15T23:18:06.908Z" }, + { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695, upload-time = "2025-10-15T23:18:08.672Z" }, + { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720, upload-time = "2025-10-15T23:18:10.632Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" }, +] + +[[package]] +name = "daphne" +version = "4.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "autobahn" }, + { name = "twisted", extra = ["tls"] }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/9d/322b605fdc03b963cf2d33943321c8f4405e8d82e698bf49d1eed1ca40c4/daphne-4.2.1.tar.gz", hash = "sha256:5f898e700a1fda7addf1541d7c328606415e96a7bd768405f0463c312fcb31b3", size = 45600, upload-time = "2025-07-02T12:57:04.935Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/34/6171ab34715ed210bcd6c2b38839cc792993cff4fe2493f50bc92b0086a0/daphne-4.2.1-py3-none-any.whl", hash = "sha256:881e96b387b95b35ad85acd855f229d7f5b79073d6649089c8a33f661885e055", size = 29015, upload-time = "2025-07-02T12:57:03.793Z" }, +] + [[package]] name = "django" version = "5.2.8" @@ -146,6 +350,39 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029, upload-time = "2024-08-10T20:25:24.996Z" }, ] +[[package]] +name = "hyperlink" +version = "21.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/51/1947bd81d75af87e3bb9e34593a4cf118115a8feb451ce7a69044ef1412e/hyperlink-21.0.0.tar.gz", hash = "sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b", size = 140743, upload-time = "2021-01-08T05:51:20.972Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl", hash = "sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4", size = 74638, upload-time = "2021-01-08T05:51:22.906Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "incremental" +version = "24.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/3c/82e84109e02c492f382c711c58a3dd91badda6d746def81a1465f74dc9f5/incremental-24.11.0.tar.gz", hash = "sha256:87d3480dbb083c1d736222511a8cf380012a8176c2456d01ef483242abbbcf8c", size = 24000, upload-time = "2025-11-28T02:30:17.861Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl", hash = "sha256:a34450716b1c4341fe6676a0598e88a39e04189f4dce5dc96f656e040baa10b3", size = 21109, upload-time = "2025-11-28T02:30:16.442Z" }, +] + [[package]] name = "iniconfig" version = "2.3.0" @@ -155,6 +392,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] +[[package]] +name = "msgpack" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/31/b46518ecc604d7edf3a4f94cb3bf021fc62aa301f0cb849936968164ef23/msgpack-1.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", size = 81212, upload-time = "2025-10-08T09:15:14.552Z" }, + { url = "https://files.pythonhosted.org/packages/92/dc/c385f38f2c2433333345a82926c6bfa5ecfff3ef787201614317b58dd8be/msgpack-1.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", size = 84315, upload-time = "2025-10-08T09:15:15.543Z" }, + { url = "https://files.pythonhosted.org/packages/d3/68/93180dce57f684a61a88a45ed13047558ded2be46f03acb8dec6d7c513af/msgpack-1.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", size = 412721, upload-time = "2025-10-08T09:15:16.567Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ba/459f18c16f2b3fc1a1ca871f72f07d70c07bf768ad0a507a698b8052ac58/msgpack-1.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", size = 424657, upload-time = "2025-10-08T09:15:17.825Z" }, + { url = "https://files.pythonhosted.org/packages/38/f8/4398c46863b093252fe67368b44edc6c13b17f4e6b0e4929dbf0bdb13f23/msgpack-1.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162", size = 402668, upload-time = "2025-10-08T09:15:19.003Z" }, + { url = "https://files.pythonhosted.org/packages/28/ce/698c1eff75626e4124b4d78e21cca0b4cc90043afb80a507626ea354ab52/msgpack-1.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", size = 419040, upload-time = "2025-10-08T09:15:20.183Z" }, + { url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037, upload-time = "2025-10-08T09:15:21.416Z" }, + { url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631, upload-time = "2025-10-08T09:15:22.431Z" }, + { url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118, upload-time = "2025-10-08T09:15:23.402Z" }, + { url = "https://files.pythonhosted.org/packages/22/71/201105712d0a2ff07b7873ed3c220292fb2ea5120603c00c4b634bcdafb3/msgpack-1.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", size = 81127, upload-time = "2025-10-08T09:15:24.408Z" }, + { url = "https://files.pythonhosted.org/packages/1b/9f/38ff9e57a2eade7bf9dfee5eae17f39fc0e998658050279cbb14d97d36d9/msgpack-1.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", size = 84981, upload-time = "2025-10-08T09:15:25.812Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a9/3536e385167b88c2cc8f4424c49e28d49a6fc35206d4a8060f136e71f94c/msgpack-1.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", size = 411885, upload-time = "2025-10-08T09:15:27.22Z" }, + { url = "https://files.pythonhosted.org/packages/2f/40/dc34d1a8d5f1e51fc64640b62b191684da52ca469da9cd74e84936ffa4a6/msgpack-1.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", size = 419658, upload-time = "2025-10-08T09:15:28.4Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ef/2b92e286366500a09a67e03496ee8b8ba00562797a52f3c117aa2b29514b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", size = 403290, upload-time = "2025-10-08T09:15:29.764Z" }, + { url = "https://files.pythonhosted.org/packages/78/90/e0ea7990abea5764e4655b8177aa7c63cdfa89945b6e7641055800f6c16b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", size = 415234, upload-time = "2025-10-08T09:15:31.022Z" }, + { url = "https://files.pythonhosted.org/packages/72/4e/9390aed5db983a2310818cd7d3ec0aecad45e1f7007e0cda79c79507bb0d/msgpack-1.1.2-cp314-cp314-win32.whl", hash = "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", size = 66391, upload-time = "2025-10-08T09:15:32.265Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", size = 73787, upload-time = "2025-10-08T09:15:33.219Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b0/9d9f667ab48b16ad4115c1935d94023b82b3198064cb84a123e97f7466c1/msgpack-1.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", size = 66453, upload-time = "2025-10-08T09:15:34.225Z" }, + { url = "https://files.pythonhosted.org/packages/16/67/93f80545eb1792b61a217fa7f06d5e5cb9e0055bed867f43e2b8e012e137/msgpack-1.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", size = 85264, upload-time = "2025-10-08T09:15:35.61Z" }, + { url = "https://files.pythonhosted.org/packages/87/1c/33c8a24959cf193966ef11a6f6a2995a65eb066bd681fd085afd519a57ce/msgpack-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", size = 89076, upload-time = "2025-10-08T09:15:36.619Z" }, + { url = "https://files.pythonhosted.org/packages/fc/6b/62e85ff7193663fbea5c0254ef32f0c77134b4059f8da89b958beb7696f3/msgpack-1.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", size = 435242, upload-time = "2025-10-08T09:15:37.647Z" }, + { url = "https://files.pythonhosted.org/packages/c1/47/5c74ecb4cc277cf09f64e913947871682ffa82b3b93c8dad68083112f412/msgpack-1.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", size = 432509, upload-time = "2025-10-08T09:15:38.794Z" }, + { url = "https://files.pythonhosted.org/packages/24/a4/e98ccdb56dc4e98c929a3f150de1799831c0a800583cde9fa022fa90602d/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", size = 415957, upload-time = "2025-10-08T09:15:40.238Z" }, + { url = "https://files.pythonhosted.org/packages/da/28/6951f7fb67bc0a4e184a6b38ab71a92d9ba58080b27a77d3e2fb0be5998f/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", size = 422910, upload-time = "2025-10-08T09:15:41.505Z" }, + { url = "https://files.pythonhosted.org/packages/f0/03/42106dcded51f0a0b5284d3ce30a671e7bd3f7318d122b2ead66ad289fed/msgpack-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", size = 75197, upload-time = "2025-10-08T09:15:42.954Z" }, + { url = "https://files.pythonhosted.org/packages/15/86/d0071e94987f8db59d4eeb386ddc64d0bb9b10820a8d82bcd3e53eeb2da6/msgpack-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", size = 85772, upload-time = "2025-10-08T09:15:43.954Z" }, + { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" }, +] + [[package]] name = "packaging" version = "25.0" @@ -288,6 +560,42 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e3/5f/947b4b4e51d67c4c9e97626c815caa9b241a62fd66ddd0d00a4a572013f5/psycopg_pool-3.2.8-py3-none-any.whl", hash = "sha256:5474137f3a58e697e0141d0311e70ec067fc4466031496d7f9ef3e2c28a1dc09", size = 38507, upload-time = "2025-11-21T22:34:31Z" }, ] +[[package]] +name = "py-ubjson" +version = "0.16.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/c7/28220d37e041fe1df03e857fe48f768dcd30cd151480bf6f00da8713214a/py-ubjson-0.16.1.tar.gz", hash = "sha256:b9bfb8695a1c7e3632e800fb83c943bf67ed45ddd87cd0344851610c69a5a482", size = 50316, upload-time = "2020-04-18T15:05:57.698Z" } + +[[package]] +name = "pyasn1" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + [[package]] name = "pygments" version = "2.19.2" @@ -306,6 +614,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, ] +[[package]] +name = "pyopenssl" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/be/97b83a464498a79103036bc74d1038df4a7ef0e402cfaf4d5e113fb14759/pyopenssl-25.3.0.tar.gz", hash = "sha256:c981cb0a3fd84e8602d7afc209522773b94c1c2446a3c710a75b06fe1beae329", size = 184073, upload-time = "2025-09-17T00:32:21.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/81/ef2b1dfd1862567d573a4fdbc9f969067621764fbb74338496840a1d2977/pyopenssl-25.3.0-py3-none-any.whl", hash = "sha256:1fda6fc034d5e3d179d39e59c1895c9faeaf40a79de5fc4cbbfbe0d36f4a77b6", size = 57268, upload-time = "2025-09-17T00:32:19.474Z" }, +] + [[package]] name = "pytest" version = "8.4.2" @@ -362,6 +682,8 @@ name = "server" version = "0.1.0" source = { virtual = "." } dependencies = [ + { name = "channels" }, + { name = "daphne" }, { name = "django" }, { name = "django-cors-headers" }, { name = "djangorestframework" }, @@ -381,6 +703,8 @@ dev = [ [package.metadata] requires-dist = [ + { name = "channels", specifier = ">=4.3.2" }, + { name = "daphne", specifier = ">=4.2.1" }, { name = "django", specifier = "~=5.2" }, { name = "django-cors-headers", specifier = "~=4.9" }, { name = "djangorestframework", specifier = "~=3.16" }, @@ -398,6 +722,21 @@ dev = [ { name = "ruff", specifier = ">=0.14" }, ] +[[package]] +name = "service-identity" +version = "24.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "cryptography" }, + { name = "pyasn1" }, + { name = "pyasn1-modules" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/a5/dfc752b979067947261dbbf2543470c58efe735c3c1301dd870ef27830ee/service_identity-24.2.0.tar.gz", hash = "sha256:b8683ba13f0d39c6cd5d625d2c5f65421d6d707b013b375c355751557cbe8e09", size = 39245, upload-time = "2024-10-26T07:21:57.736Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/2c/ca6dd598b384bc1ce581e24aaae0f2bed4ccac57749d5c3befbb5e742081/service_identity-24.2.0-py3-none-any.whl", hash = "sha256:6b047fbd8a84fd0bb0d55ebce4031e400562b9196e1e0d3e0fe2b8a59f6d4a85", size = 11364, upload-time = "2024-10-26T07:21:56.302Z" }, +] + [[package]] name = "sqlparse" version = "0.5.3" @@ -407,6 +746,40 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca", size = 44415, upload-time = "2024-12-10T12:05:27.824Z" }, ] +[[package]] +name = "twisted" +version = "25.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "automat" }, + { name = "constantly" }, + { name = "hyperlink" }, + { name = "incremental" }, + { name = "typing-extensions" }, + { name = "zope-interface" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/0f/82716ed849bf7ea4984c21385597c949944f0f9b428b5710f79d0afc084d/twisted-25.5.0.tar.gz", hash = "sha256:1deb272358cb6be1e3e8fc6f9c8b36f78eb0fa7c2233d2dbe11ec6fee04ea316", size = 3545725, upload-time = "2025-06-07T09:52:24.858Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/66/ab7efd8941f0bc7b2bd555b0f0471bff77df4c88e0cc31120c82737fec77/twisted-25.5.0-py3-none-any.whl", hash = "sha256:8559f654d01a54a8c3efe66d533d43f383531ebf8d81d9f9ab4769d91ca15df7", size = 3204767, upload-time = "2025-06-07T09:52:21.428Z" }, +] + +[package.optional-dependencies] +tls = [ + { name = "idna" }, + { name = "pyopenssl" }, + { name = "service-identity" }, +] + +[[package]] +name = "txaio" +version = "25.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/67/ea9c9ddbaa3e0b4d53c91f8778a33e42045be352dc7200ed2b9aaa7dc229/txaio-25.12.2.tar.gz", hash = "sha256:9f232c21e12aa1ff52690e365b5a0ecfd42cc27a6ec86e1b92ece88f763f4b78", size = 117393, upload-time = "2025-12-09T15:03:26.527Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/05/bdb6318120cac9bf97779674f49035e0595d894b42d4c43b60637bafdb1f/txaio-25.12.2-py3-none-any.whl", hash = "sha256:5f6cd6c6b397fc3305790d15efd46a2d5b91cdbefa96543b4f8666aeb56ba026", size = 31208, upload-time = "2025-12-09T04:30:27.811Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0" @@ -424,3 +797,73 @@ sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be76 wheels = [ { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, ] + +[[package]] +name = "u-msgpack-python" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/36/9d/a40411a475e7d4838994b7f6bcc6bfca9acc5b119ce3a7503608c4428b49/u-msgpack-python-2.8.0.tar.gz", hash = "sha256:b801a83d6ed75e6df41e44518b4f2a9c221dc2da4bcd5380e3a0feda520bc61a", size = 18167, upload-time = "2023-05-18T09:28:12.187Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/5e/512aeb40fd819f4660d00f96f5c7371ee36fc8c6b605128c5ee59e0b28c6/u_msgpack_python-2.8.0-py2.py3-none-any.whl", hash = "sha256:1d853d33e78b72c4228a2025b4db28cda81214076e5b0422ed0ae1b1b2bb586a", size = 10590, upload-time = "2023-05-18T09:28:10.323Z" }, +] + +[[package]] +name = "ujson" +version = "5.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/d9/3f17e3c5773fb4941c68d9a37a47b1a79c9649d6c56aefbed87cc409d18a/ujson-5.11.0.tar.gz", hash = "sha256:e204ae6f909f099ba6b6b942131cee359ddda2b6e4ea39c12eb8b991fe2010e0", size = 7156583, upload-time = "2025-08-20T11:57:02.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/ec/2de9dd371d52c377abc05d2b725645326c4562fc87296a8907c7bcdf2db7/ujson-5.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:109f59885041b14ee9569bf0bb3f98579c3fa0652317b355669939e5fc5ede53", size = 55435, upload-time = "2025-08-20T11:55:50.243Z" }, + { url = "https://files.pythonhosted.org/packages/5b/a4/f611f816eac3a581d8a4372f6967c3ed41eddbae4008d1d77f223f1a4e0a/ujson-5.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a31c6b8004438e8c20fc55ac1c0e07dad42941db24176fe9acf2815971f8e752", size = 53193, upload-time = "2025-08-20T11:55:51.373Z" }, + { url = "https://files.pythonhosted.org/packages/e9/c5/c161940967184de96f5cbbbcce45b562a4bf851d60f4c677704b1770136d/ujson-5.11.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78c684fb21255b9b90320ba7e199780f653e03f6c2528663768965f4126a5b50", size = 57603, upload-time = "2025-08-20T11:55:52.583Z" }, + { url = "https://files.pythonhosted.org/packages/2b/d6/c7b2444238f5b2e2d0e3dab300b9ddc3606e4b1f0e4bed5a48157cebc792/ujson-5.11.0-cp313-cp313-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:4c9f5d6a27d035dd90a146f7761c2272cf7103de5127c9ab9c4cd39ea61e878a", size = 59794, upload-time = "2025-08-20T11:55:53.69Z" }, + { url = "https://files.pythonhosted.org/packages/fe/a3/292551f936d3d02d9af148f53e1bc04306b00a7cf1fcbb86fa0d1c887242/ujson-5.11.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:837da4d27fed5fdc1b630bd18f519744b23a0b5ada1bbde1a36ba463f2900c03", size = 57363, upload-time = "2025-08-20T11:55:54.843Z" }, + { url = "https://files.pythonhosted.org/packages/90/a6/82cfa70448831b1a9e73f882225980b5c689bf539ec6400b31656a60ea46/ujson-5.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:787aff4a84da301b7f3bac09bc696e2e5670df829c6f8ecf39916b4e7e24e701", size = 1036311, upload-time = "2025-08-20T11:55:56.197Z" }, + { url = "https://files.pythonhosted.org/packages/84/5c/96e2266be50f21e9b27acaee8ca8f23ea0b85cb998c33d4f53147687839b/ujson-5.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6dd703c3e86dc6f7044c5ac0b3ae079ed96bf297974598116aa5fb7f655c3a60", size = 1195783, upload-time = "2025-08-20T11:55:58.081Z" }, + { url = "https://files.pythonhosted.org/packages/8d/20/78abe3d808cf3bb3e76f71fca46cd208317bf461c905d79f0d26b9df20f1/ujson-5.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3772e4fe6b0c1e025ba3c50841a0ca4786825a4894c8411bf8d3afe3a8061328", size = 1088822, upload-time = "2025-08-20T11:55:59.469Z" }, + { url = "https://files.pythonhosted.org/packages/d8/50/8856e24bec5e2fc7f775d867aeb7a3f137359356200ac44658f1f2c834b2/ujson-5.11.0-cp313-cp313-win32.whl", hash = "sha256:8fa2af7c1459204b7a42e98263b069bd535ea0cd978b4d6982f35af5a04a4241", size = 39753, upload-time = "2025-08-20T11:56:01.345Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d8/1baee0f4179a4d0f5ce086832147b6cc9b7731c24ca08e14a3fdb8d39c32/ujson-5.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:34032aeca4510a7c7102bd5933f59a37f63891f30a0706fb46487ab6f0edf8f0", size = 43866, upload-time = "2025-08-20T11:56:02.552Z" }, + { url = "https://files.pythonhosted.org/packages/a9/8c/6d85ef5be82c6d66adced3ec5ef23353ed710a11f70b0b6a836878396334/ujson-5.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:ce076f2df2e1aa62b685086fbad67f2b1d3048369664b4cdccc50707325401f9", size = 38363, upload-time = "2025-08-20T11:56:03.688Z" }, + { url = "https://files.pythonhosted.org/packages/28/08/4518146f4984d112764b1dfa6fb7bad691c44a401adadaa5e23ccd930053/ujson-5.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:65724738c73645db88f70ba1f2e6fb678f913281804d5da2fd02c8c5839af302", size = 55462, upload-time = "2025-08-20T11:56:04.873Z" }, + { url = "https://files.pythonhosted.org/packages/29/37/2107b9a62168867a692654d8766b81bd2fd1e1ba13e2ec90555861e02b0c/ujson-5.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29113c003ca33ab71b1b480bde952fbab2a0b6b03a4ee4c3d71687cdcbd1a29d", size = 53246, upload-time = "2025-08-20T11:56:06.054Z" }, + { url = "https://files.pythonhosted.org/packages/9b/f8/25583c70f83788edbe3ca62ce6c1b79eff465d78dec5eb2b2b56b3e98b33/ujson-5.11.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c44c703842024d796b4c78542a6fcd5c3cb948b9fc2a73ee65b9c86a22ee3638", size = 57631, upload-time = "2025-08-20T11:56:07.374Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ca/19b3a632933a09d696f10dc1b0dfa1d692e65ad507d12340116ce4f67967/ujson-5.11.0-cp314-cp314-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:e750c436fb90edf85585f5c62a35b35082502383840962c6983403d1bd96a02c", size = 59877, upload-time = "2025-08-20T11:56:08.534Z" }, + { url = "https://files.pythonhosted.org/packages/55/7a/4572af5324ad4b2bfdd2321e898a527050290147b4ea337a79a0e4e87ec7/ujson-5.11.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f278b31a7c52eb0947b2db55a5133fbc46b6f0ef49972cd1a80843b72e135aba", size = 57363, upload-time = "2025-08-20T11:56:09.758Z" }, + { url = "https://files.pythonhosted.org/packages/7b/71/a2b8c19cf4e1efe53cf439cdf7198ac60ae15471d2f1040b490c1f0f831f/ujson-5.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ab2cb8351d976e788669c8281465d44d4e94413718af497b4e7342d7b2f78018", size = 1036394, upload-time = "2025-08-20T11:56:11.168Z" }, + { url = "https://files.pythonhosted.org/packages/7a/3e/7b98668cba3bb3735929c31b999b374ebc02c19dfa98dfebaeeb5c8597ca/ujson-5.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:090b4d11b380ae25453100b722d0609d5051ffe98f80ec52853ccf8249dfd840", size = 1195837, upload-time = "2025-08-20T11:56:12.6Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ea/8870f208c20b43571a5c409ebb2fe9b9dba5f494e9e60f9314ac01ea8f78/ujson-5.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:80017e870d882d5517d28995b62e4e518a894f932f1e242cbc802a2fd64d365c", size = 1088837, upload-time = "2025-08-20T11:56:14.15Z" }, + { url = "https://files.pythonhosted.org/packages/63/b6/c0e6607e37fa47929920a685a968c6b990a802dec65e9c5181e97845985d/ujson-5.11.0-cp314-cp314-win32.whl", hash = "sha256:1d663b96eb34c93392e9caae19c099ec4133ba21654b081956613327f0e973ac", size = 41022, upload-time = "2025-08-20T11:56:15.509Z" }, + { url = "https://files.pythonhosted.org/packages/4e/56/f4fe86b4c9000affd63e9219e59b222dc48b01c534533093e798bf617a7e/ujson-5.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:849e65b696f0d242833f1df4182096cedc50d414215d1371fca85c541fbff629", size = 45111, upload-time = "2025-08-20T11:56:16.597Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f3/669437f0280308db4783b12a6d88c00730b394327d8334cc7a32ef218e64/ujson-5.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:e73df8648c9470af2b6a6bf5250d4744ad2cf3d774dcf8c6e31f018bdd04d764", size = 39682, upload-time = "2025-08-20T11:56:17.763Z" }, + { url = "https://files.pythonhosted.org/packages/6e/cd/e9809b064a89fe5c4184649adeb13c1b98652db3f8518980b04227358574/ujson-5.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:de6e88f62796372fba1de973c11138f197d3e0e1d80bcb2b8aae1e826096d433", size = 55759, upload-time = "2025-08-20T11:56:18.882Z" }, + { url = "https://files.pythonhosted.org/packages/1b/be/ae26a6321179ebbb3a2e2685b9007c71bcda41ad7a77bbbe164005e956fc/ujson-5.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:49e56ef8066f11b80d620985ae36869a3ff7e4b74c3b6129182ec5d1df0255f3", size = 53634, upload-time = "2025-08-20T11:56:20.012Z" }, + { url = "https://files.pythonhosted.org/packages/ae/e9/fb4a220ee6939db099f4cfeeae796ecb91e7584ad4d445d4ca7f994a9135/ujson-5.11.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1a325fd2c3a056cf6c8e023f74a0c478dd282a93141356ae7f16d5309f5ff823", size = 58547, upload-time = "2025-08-20T11:56:21.175Z" }, + { url = "https://files.pythonhosted.org/packages/bd/f8/fc4b952b8f5fea09ea3397a0bd0ad019e474b204cabcb947cead5d4d1ffc/ujson-5.11.0-cp314-cp314t-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:a0af6574fc1d9d53f4ff371f58c96673e6d988ed2b5bf666a6143c782fa007e9", size = 60489, upload-time = "2025-08-20T11:56:22.342Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e5/af5491dfda4f8b77e24cf3da68ee0d1552f99a13e5c622f4cef1380925c3/ujson-5.11.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10f29e71ecf4ecd93a6610bd8efa8e7b6467454a363c3d6416db65de883eb076", size = 58035, upload-time = "2025-08-20T11:56:23.92Z" }, + { url = "https://files.pythonhosted.org/packages/c4/09/0945349dd41f25cc8c38d78ace49f14c5052c5bbb7257d2f466fa7bdb533/ujson-5.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1a0a9b76a89827a592656fe12e000cf4f12da9692f51a841a4a07aa4c7ecc41c", size = 1037212, upload-time = "2025-08-20T11:56:25.274Z" }, + { url = "https://files.pythonhosted.org/packages/49/44/8e04496acb3d5a1cbee3a54828d9652f67a37523efa3d3b18a347339680a/ujson-5.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b16930f6a0753cdc7d637b33b4e8f10d5e351e1fb83872ba6375f1e87be39746", size = 1196500, upload-time = "2025-08-20T11:56:27.517Z" }, + { url = "https://files.pythonhosted.org/packages/64/ae/4bc825860d679a0f208a19af2f39206dfd804ace2403330fdc3170334a2f/ujson-5.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:04c41afc195fd477a59db3a84d5b83a871bd648ef371cf8c6f43072d89144eef", size = 1089487, upload-time = "2025-08-20T11:56:29.07Z" }, + { url = "https://files.pythonhosted.org/packages/30/ed/5a057199fb0a5deabe0957073a1c1c1c02a3e99476cd03daee98ea21fa57/ujson-5.11.0-cp314-cp314t-win32.whl", hash = "sha256:aa6d7a5e09217ff93234e050e3e380da62b084e26b9f2e277d2606406a2fc2e5", size = 41859, upload-time = "2025-08-20T11:56:30.495Z" }, + { url = "https://files.pythonhosted.org/packages/aa/03/b19c6176bdf1dc13ed84b886e99677a52764861b6cc023d5e7b6ebda249d/ujson-5.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:48055e1061c1bb1f79e75b4ac39e821f3f35a9b82de17fce92c3140149009bec", size = 46183, upload-time = "2025-08-20T11:56:31.574Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ca/a0413a3874b2dc1708b8796ca895bf363292f9c70b2e8ca482b7dbc0259d/ujson-5.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1194b943e951092db611011cb8dbdb6cf94a3b816ed07906e14d3bc6ce0e90ab", size = 40264, upload-time = "2025-08-20T11:56:32.773Z" }, +] + +[[package]] +name = "zope-interface" +version = "8.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/86/a4/77daa5ba398996d16bb43fc721599d27d03eae68fe3c799de1963c72e228/zope_interface-8.2.tar.gz", hash = "sha256:afb20c371a601d261b4f6edb53c3c418c249db1a9717b0baafc9a9bb39ba1224", size = 254019, upload-time = "2026-01-09T07:51:07.253Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/47/45188fb101fa060b20e6090e500682398ab415e516a0c228fbb22bc7def2/zope_interface-8.2-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:6068322004a0158c80dfd4708dfb103a899635408c67c3b10e9acec4dbacefec", size = 209170, upload-time = "2026-01-09T08:05:26.616Z" }, + { url = "https://files.pythonhosted.org/packages/09/03/f6b9336c03c2b48403c4eb73a1ec961d94dc2fb5354c583dfb5fa05fd41f/zope_interface-8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2499de92e8275d0dd68f84425b3e19e9268cd1fa8507997900fa4175f157733c", size = 209229, upload-time = "2026-01-09T08:05:28.521Z" }, + { url = "https://files.pythonhosted.org/packages/07/b1/65fe1dca708569f302ade02e6cdca309eab6752bc9f80105514f5b708651/zope_interface-8.2-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f777e68c76208503609c83ca021a6864902b646530a1a39abb9ed310d1100664", size = 259393, upload-time = "2026-01-09T08:05:29.897Z" }, + { url = "https://files.pythonhosted.org/packages/eb/a5/97b49cfceb6ed53d3dcfb3f3ebf24d83b5553194f0337fbbb3a9fec6cf78/zope_interface-8.2-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b05a919fdb0ed6ea942e5a7800e09a8b6cdae6f98fee1bef1c9d1a3fc43aaa0", size = 264863, upload-time = "2026-01-09T08:05:31.501Z" }, + { url = "https://files.pythonhosted.org/packages/cb/02/0b7a77292810efe3a0586a505b077ebafd5114e10c6e6e659f0c8e387e1f/zope_interface-8.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ccc62b5712dd7bd64cfba3ee63089fb11e840f5914b990033beeae3b2180b6cb", size = 264369, upload-time = "2026-01-09T08:05:32.941Z" }, + { url = "https://files.pythonhosted.org/packages/fb/1d/0d1ff3846302ed1b5bbf659316d8084b30106770a5f346b7ff4e9f540f80/zope_interface-8.2-cp313-cp313-win_amd64.whl", hash = "sha256:34f877d1d3bb7565c494ed93828fa6417641ca26faf6e8f044e0d0d500807028", size = 212447, upload-time = "2026-01-09T08:05:35.064Z" }, + { url = "https://files.pythonhosted.org/packages/1a/da/3c89de3917751446728b8898b4d53318bc2f8f6bf8196e150a063c59905e/zope_interface-8.2-cp314-cp314-macosx_10_9_x86_64.whl", hash = "sha256:46c7e4e8cbc698398a67e56ca985d19cb92365b4aafbeb6a712e8c101090f4cb", size = 209223, upload-time = "2026-01-09T08:05:36.449Z" }, + { url = "https://files.pythonhosted.org/packages/00/7f/62d00ec53f0a6e5df0c984781e6f3999ed265129c4c3413df8128d1e0207/zope_interface-8.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a87fc7517f825a97ff4a4ca4c8a950593c59e0f8e7bfe1b6f898a38d5ba9f9cf", size = 209366, upload-time = "2026-01-09T08:05:38.197Z" }, + { url = "https://files.pythonhosted.org/packages/ef/a2/f241986315174be8e00aabecfc2153cf8029c1327cab8ed53a9d979d7e08/zope_interface-8.2-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:ccf52f7d44d669203c2096c1a0c2c15d52e36b2e7a9413df50f48392c7d4d080", size = 261037, upload-time = "2026-01-09T08:05:39.568Z" }, + { url = "https://files.pythonhosted.org/packages/02/cc/b321c51d6936ede296a1b8860cf173bee2928357fe1fff7f97234899173f/zope_interface-8.2-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:aae807efc7bd26302eb2fea05cd6de7d59269ed6ae23a6de1ee47add6de99b8c", size = 264219, upload-time = "2026-01-09T08:05:41.624Z" }, + { url = "https://files.pythonhosted.org/packages/ab/fb/5f5e7b40a2f4efd873fe173624795ca47eaa22e29051270c981361b45209/zope_interface-8.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:05a0e42d6d830f547e114de2e7cd15750dc6c0c78f8138e6c5035e51ddfff37c", size = 264390, upload-time = "2026-01-09T08:05:42.936Z" }, + { url = "https://files.pythonhosted.org/packages/f9/82/3f2bc594370bc3abd58e5f9085d263bf682a222f059ed46275cde0570810/zope_interface-8.2-cp314-cp314-win_amd64.whl", hash = "sha256:561ce42390bee90bae51cf1c012902a8033b2aaefbd0deed81e877562a116d48", size = 212585, upload-time = "2026-01-09T08:05:44.419Z" }, +] From 6be0fa5ccdd02f8abcec3156b0f18ce89e7152b1 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Sat, 10 Jan 2026 13:07:15 +0800 Subject: [PATCH 90/94] bug fix[index]: fixed quick flash to login, routes correctly to home page after login from index --- client/src/context/AuthContext.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/src/context/AuthContext.tsx b/client/src/context/AuthContext.tsx index 0582607..075f943 100644 --- a/client/src/context/AuthContext.tsx +++ b/client/src/context/AuthContext.tsx @@ -1,4 +1,3 @@ -import { useRouter } from "next/router"; import { createContext, ReactNode, @@ -22,7 +21,6 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { const [accessToken, setAccessToken] = useState(null); const [refreshToken, setRefreshToken] = useState(null); const [isLoading, setIsLoading] = useState(true); - const router = useRouter(); useEffect(() => { const storedAccess = localStorage.getItem("accessToken"); @@ -44,7 +42,6 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => { setRefreshToken(null); localStorage.removeItem("accessToken"); localStorage.removeItem("refreshToken"); - router.push("/login"); }; const isLoggedIn = !!accessToken; From 7f6d5309a968c80f67fb5a47476bcd062953613e Mon Sep 17 00:00:00 2001 From: Coffee <153749000+CoffeeFolf@users.noreply.github.com> Date: Sat, 10 Jan 2026 13:09:54 +0800 Subject: [PATCH 91/94] linked Create account button to register tsx --- client/src/pages/index.tsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/client/src/pages/index.tsx b/client/src/pages/index.tsx index 377757b..d6989c9 100644 --- a/client/src/pages/index.tsx +++ b/client/src/pages/index.tsx @@ -14,6 +14,7 @@ import { Users, Workflow, } from "lucide-react"; +import Link from "next/link"; import { useRouter } from "next/router"; import React, { useState } from "react"; import { toast } from "sonner"; @@ -665,13 +666,15 @@ export default function AboutPage() {
- + + + {/* Placeholder, there is no link rn */}

From d8cf8c41e1b61582e7936958718a946319cefe2f Mon Sep 17 00:00:00 2001 From: Coffee <153749000+CoffeeFolf@users.noreply.github.com> Date: Sat, 10 Jan 2026 14:10:54 +0800 Subject: [PATCH 92/94] Adjusted background color to seperate sections on index.tsx --- client/src/pages/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/pages/index.tsx b/client/src/pages/index.tsx index d6989c9..a49aa9f 100644 --- a/client/src/pages/index.tsx +++ b/client/src/pages/index.tsx @@ -237,7 +237,7 @@ export default function AboutPage() { {/* about section */}

@@ -384,7 +384,7 @@ export default function AboutPage() { {/* why this app section */}

Date: Wed, 14 Jan 2026 20:02:06 +0800 Subject: [PATCH 93/94] updated Event card UI --- client/src/components/ui/event-card.tsx | 132 ++++++++++++++++++------ client/src/hooks/events.ts | 1 + client/src/pages/index.tsx | 2 +- 3 files changed, 102 insertions(+), 33 deletions(-) diff --git a/client/src/components/ui/event-card.tsx b/client/src/components/ui/event-card.tsx index f9ab342..511c7e1 100644 --- a/client/src/components/ui/event-card.tsx +++ b/client/src/components/ui/event-card.tsx @@ -1,45 +1,113 @@ +// import Link from "next/link"; +// import Image from "next/image"; + +// import { +// Card, +// CardContent, +// CardDescription, +// CardFooter, +// CardHeader, +// CardTitle, +// } from "@/components/ui/card"; + +// import type { Event } from "../../hooks/events"; +// import { Button } from "./button"; +// import TagList from "./tag-list"; + +// interface EventCardProps { +// event: Event; +// } + +// export default function EventCard({ event }: EventCardProps) { +// return ( +// +// +// {event.event_name} +// {event.event_location} +// + +// +// +//

+// {event.event_description} +//

+//
+ +// +// +// +// +// +// +// +// +//
+// ); +// } + +import Image from "next/image"; import Link from "next/link"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card"; +import { Card } from "@/components/ui/card"; import type { Event } from "../../hooks/events"; -import { Button } from "./button"; -import TagList from "./tag-list"; interface EventCardProps { event: Event; } export default function EventCard({ event }: EventCardProps) { + const image = event.images?.[0]?.image; + return ( - - - {event.event_name} - {event.event_location} - - - - -

- {event.event_description} -

-
- - - - - - - - - -
+
+ + +
+
+

+ {new Date(event.event_date).toLocaleDateString("en-AU", { + day: "2-digit", + month: "2-digit", + year: "numeric", + })} +

+ +

+ {event.event_name} +

+ +

{event.event_location}

+ +
+ {event.tags.map((tag) => ( + + {tag.name} + + ))} +
+ +

+ {event.event_description} +

+
+
+ +
+ {image && ( + {event.event_name} + )} +
+
+ +
); } diff --git a/client/src/hooks/events.ts b/client/src/hooks/events.ts index aa27118..af3021a 100644 --- a/client/src/hooks/events.ts +++ b/client/src/hooks/events.ts @@ -13,6 +13,7 @@ export interface Tag { } export interface EventImage { + url: string; id: number; image: string; } diff --git a/client/src/pages/index.tsx b/client/src/pages/index.tsx index a49aa9f..2186f36 100644 --- a/client/src/pages/index.tsx +++ b/client/src/pages/index.tsx @@ -670,7 +670,7 @@ export default function AboutPage() { From edfb0cde3fdffee677ea1002cad7ad7cbcde4d88 Mon Sep 17 00:00:00 2001 From: "phillip.nguyen" Date: Tue, 20 Jan 2026 00:17:53 +0800 Subject: [PATCH 94/94] Add HubDisplay component to manage event participant display and update ParticipantsPage logic --- client/src/components/ui/hub-display.tsx | 56 +++++++++++++++++++++++ client/src/pages/events/[id]/hub.tsx | 58 ++++-------------------- 2 files changed, 66 insertions(+), 48 deletions(-) create mode 100644 client/src/components/ui/hub-display.tsx diff --git a/client/src/components/ui/hub-display.tsx b/client/src/components/ui/hub-display.tsx new file mode 100644 index 0000000..640eb65 --- /dev/null +++ b/client/src/components/ui/hub-display.tsx @@ -0,0 +1,56 @@ +import Image from "next/image"; +import { useRouter } from "next/router"; + +import { useEvent } from "@/hooks/events"; + +import { Avatar, AvatarFallback } from "./avatar"; +import { Button } from "./button"; +import { Card, CardContent } from "./card"; + +export default function HubDisplay() { + const router = useRouter(); + const { id } = router.query; + const eventId = Number(id); + + const { data: event, isLoading } = useEvent(eventId); + return ( +
+
+ {event?.images?.[0]?.image && ( + {event.event_name} + )} +
+ {!isLoading && event?.participants && event.participants.length > 0 && ( +
+ {event.participants.map((p) => ( + + + + + {p.username.slice(0, 2).toUpperCase()} + + + +
+

{p.username}

+

+ Attending this event +

+
+ + +
+
+ ))} +
+ )} +
+ ); +} diff --git a/client/src/pages/events/[id]/hub.tsx b/client/src/pages/events/[id]/hub.tsx index 5ffc553..70ec6a7 100644 --- a/client/src/pages/events/[id]/hub.tsx +++ b/client/src/pages/events/[id]/hub.tsx @@ -1,11 +1,9 @@ -import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/router"; import Confetti from "react-confetti"; -import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; +import HubDisplay from "@/components/ui/hub-display"; import { useEvent } from "@/hooks/events"; import ActionLayout from "@/pages/layouts/actionlayout"; @@ -13,8 +11,15 @@ export default function ParticipantsPage() { const router = useRouter(); const { id } = router.query; const eventId = Number(id); + const { data: event } = useEvent(eventId); - const { data: event, isLoading } = useEvent(eventId); + if (!event) { + return

Event not found

; + } + + const eventDate = new Date(event.event_date); + const now = new Date(); + const hasEnded = eventDate < now; return ( <> @@ -35,50 +40,7 @@ export default function ParticipantsPage() { } > -
-
- {event?.images?.[0]?.image && ( - {event.event_name} - )} -
- {!isLoading && - event?.participants && - event.participants.length > 0 && ( -
- {event.participants.map((p) => ( - - - - - {p.username.slice(0, 2).toUpperCase()} - - - -
-

{p.username}

-

- Attending this event -

-
- - -
-
- ))} -
- )} -
- - {!isLoading && event?.participants?.length === 0 && ( -

No participants yet.

- )} + {hasEnded ? : } );