From 41f157cbe7b65511e5232991f93f83f4e414b9eb Mon Sep 17 00:00:00 2001 From: lijianguo Date: Wed, 8 May 2024 12:47:23 +0800 Subject: [PATCH 01/39] chore(chart): job upgrade add passportLocation condition --- charts/passport/templates/passport-job-upgrade.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/charts/passport/templates/passport-job-upgrade.yaml b/charts/passport/templates/passport-job-upgrade.yaml index 414cb4e..bcb9dd2 100644 --- a/charts/passport/templates/passport-job-upgrade.yaml +++ b/charts/passport/templates/passport-job-upgrade.yaml @@ -1,3 +1,4 @@ +{{- if eq .Values.global.passportLocation "on-cluster" }} apiVersion: batch/v1 kind: Job metadata: @@ -51,3 +52,4 @@ spec: restartPolicy: Never backoffLimit: 0 ttlSecondsAfterFinished: 3600 +{{- end }} From 630bbd6d31579c1cfe7dcd3034f05ca199b6443c Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Tue, 9 Jul 2024 15:32:17 +0800 Subject: [PATCH 02/39] chore(migrate): use helm hook replace cluster lock --- .../templates/passport-deployment.yaml | 12 ------ .../templates/passport-job-upgrade.yaml | 13 ++---- .../api/management/commands/cluster_lock.py | 41 ------------------- 3 files changed, 3 insertions(+), 63 deletions(-) delete mode 100644 rootfs/api/management/commands/cluster_lock.py diff --git a/charts/passport/templates/passport-deployment.yaml b/charts/passport/templates/passport-deployment.yaml index ad65b5b..8017c06 100644 --- a/charts/passport/templates/passport-deployment.yaml +++ b/charts/passport/templates/passport-deployment.yaml @@ -37,18 +37,6 @@ spec: - -u - $(DRYCC_DATABASE_URL),$(DRYCC_DATABASE_REPLICA_URL) {{- include "passport.envs" . | indent 8 }} - - name: drycc-passport-waitting - image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/passport:{{.Values.imageTag}} - imagePullPolicy: {{.Values.imagePullPolicy}} - args: - - /usr/bin/env - - bash - - -ec - - | - python -u /workspace/manage.py cluster_lock waitting - {{- include "passport.limits" . | indent 8 }} - {{- include "passport.envs" . | indent 8 }} - {{- include "passport.volumeMounts" . | indent 8 }} containers: - name: drycc-passport image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/passport:{{.Values.imageTag}} diff --git a/charts/passport/templates/passport-job-upgrade.yaml b/charts/passport/templates/passport-job-upgrade.yaml index bcb9dd2..1af08ea 100644 --- a/charts/passport/templates/passport-job-upgrade.yaml +++ b/charts/passport/templates/passport-job-upgrade.yaml @@ -2,16 +2,13 @@ apiVersion: batch/v1 kind: Job metadata: - name: drycc-passport-job-upgrade-{{ now | date "20060102150405" }} - labels: - heritage: drycc + name: drycc-passport-job-upgrade annotations: component.drycc.cc/version: {{ .Values.imageTag }} + helm.sh/hook: post-install,pre-upgrade,pre-rollback + helm.sh/hook-delete-policy: before-hook-creation spec: template: - metadata: - labels: {{- include "common.labels.standard" . | nindent 8 }} - app: drycc-passport-job-upgrade spec: initContainers: - name: drycc-passport-init @@ -36,20 +33,16 @@ spec: - bash - -ec - | - python -u /workspace/manage.py cluster_lock lock python -u /workspace/manage.py migrate --noinput if [ "${ADMIN_USERNAME}" ] && [ "${ADMIN_PASSWORD}" ] && [ "${ADMIN_EMAIL}" ]; then echo "Create administrator" python /workspace/manage.py createadminuser --username "${ADMIN_USERNAME}" --password "${ADMIN_PASSWORD}" --noinput --email "${ADMIN_EMAIL}" fi python /workspace/manage.py create_oauth2_application --path /etc/drycc/passport/init-applications.json - python -u /workspace/manage.py cluster_lock unlock {{- end }} {{- include "passport.limits" . | indent 8 }} {{- include "passport.envs" . | indent 8 }} {{- include "passport.volumeMounts" . | indent 8 }} {{- include "passport.volumes" . | indent 6 }} restartPolicy: Never - backoffLimit: 0 - ttlSecondsAfterFinished: 3600 {{- end }} diff --git a/rootfs/api/management/commands/cluster_lock.py b/rootfs/api/management/commands/cluster_lock.py deleted file mode 100644 index e4a9ded..0000000 --- a/rootfs/api/management/commands/cluster_lock.py +++ /dev/null @@ -1,41 +0,0 @@ -import time -from django.core.management.base import BaseCommand -from django.core.cache import cache -from django.conf import settings - -lock_key = "drycc:passport:version" -waitting_init_msg = "version inconsistency %s!=%s, waiting for initialization to complete..." - - -class Command(BaseCommand): - - def add_arguments(self, parser): - parser.add_argument( - "args", - metavar="action", - nargs="+", - choices=["lock", "unlock", "waitting"], - help="an action that needs to be executed.", - ) - - def lock(self): - cache.delete(lock_key) - print("lock completed!") - - def unlock(self): - cache.set(lock_key, settings.VERSION, timeout=None) - print("unlock completed!") - - def waitting(self): - while True: - version = cache.get(lock_key, None) - if version != settings.VERSION: - print(waitting_init_msg % (version, settings.VERSION)) - else: - break - time.sleep(10) - print("waiting completed!") - - def handle(self, *args, **options): - action = args[0] - getattr(self, action)() From 9910b91a1a5a3bb380701ca672454483d215ee09 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Tue, 6 Aug 2024 10:19:19 +0800 Subject: [PATCH 03/39] chore(passport): use latest codecov cli version --- Makefile | 2 +- rootfs/Dockerfile.test | 2 ++ rootfs/bin/test-unit | 1 - rootfs/bin/upload-coverage | 6 +++++- rootfs/dev_requirements.txt | 9 +++------ 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index dc1a494..b070b54 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,6 @@ test-integration: upload-coverage: $(eval CI_ENV := $(shell curl -s https://codecov.io/env | bash)) - podman run ${CI_ENV} -v ${CURDIR}:/test -w /test/rootfs ${IMAGE}.test /test/rootfs/bin/upload-coverage + podman run ${CI_ENV} -v ${CURDIR}:/test -w /test/rootfs -e CODECOV_TOKEN=${CODECOV_TOKEN} ${IMAGE}.test /test/rootfs/bin/upload-coverage .PHONY: check-kubectl check-podman build podman-build podman-build-test deploy clean commit-hook full-clean test test-style test-unit test-functional test-integration upload-coverage diff --git a/rootfs/Dockerfile.test b/rootfs/Dockerfile.test index 2b6d7d7..3e0230f 100644 --- a/rootfs/Dockerfile.test +++ b/rootfs/Dockerfile.test @@ -12,6 +12,8 @@ COPY dev_requirements.txt ${DRYCC_HOME_DIR}/dev_requirements.txt RUN buildDeps='gcc rustc cargo libffi-dev musl-dev libldap2-dev libsasl2-dev'; \ install-packages ldap-utils mercurial ca-certificates openssl git $buildDeps \ + && curl -SsL https://cli.codecov.io/latest/$([ $(dpkg --print-architecture) == "arm64" ] && echo linux-arm64 || echo linux)/codecov -o /usr/local/bin/codecov \ + && chmod +x /usr/local/bin/codecov \ && install-stack python $PYTHON_VERSION \ && install-stack postgresql $POSTGRES_VERSION \ && install-stack gosu $GOSU_VERSION && . init-stack \ diff --git a/rootfs/bin/test-unit b/rootfs/bin/test-unit index b586069..b1f9263 100755 --- a/rootfs/bin/test-unit +++ b/rootfs/bin/test-unit @@ -15,4 +15,3 @@ gosu postgres pg_ctl -D "$PGDATA" start && ln -s /tmp/.s.PGSQL.5432 /var/run/pos creating_rsa_key python3 manage.py check coverage run manage.py test --settings=api.settings.testing --noinput api -coverage report -m diff --git a/rootfs/bin/upload-coverage b/rootfs/bin/upload-coverage index 53433f3..492452b 100755 --- a/rootfs/bin/upload-coverage +++ b/rootfs/bin/upload-coverage @@ -6,4 +6,8 @@ # fail hard and fast even on pipelines set -eou pipefail -codecov --required +coverage report -m > coverage.txt + +if [[ -n $CODECOV_TOKEN ]]; then + codecov upload-process --plugin=noop -t "$CODECOV_TOKEN" +fi diff --git a/rootfs/dev_requirements.txt b/rootfs/dev_requirements.txt index 6c42313..ca19f67 100644 --- a/rootfs/dev_requirements.txt +++ b/rootfs/dev_requirements.txt @@ -1,13 +1,10 @@ # test module # test # Run "make test-unit" for the % of code exercised during tests -coverage==7.4.4 +coverage==7.6.1 # Run "make test-style" to check python syntax and style -flake8==7.0.0 - -# code coverage report at https://codecov.io/github/drycc/passport -codecov==2.1.13 +flake8==7.1.1 # mock out python-requests, mostly k8s -requests-mock==1.11.0 +requests-mock==1.12.1 From c2656fc3d86f4de24fe219591927f1751482bc31 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Thu, 14 Nov 2024 09:21:16 +0800 Subject: [PATCH 04/39] chore(python): upgrade requirements version --- ...03_application_allowed_origins_and_more.py | 28 +++++++++++++++++++ rootfs/api/routers.py | 4 +++ rootfs/requirements.txt | 26 ++++++++--------- 3 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 rootfs/api/migrations/0003_application_allowed_origins_and_more.py diff --git a/rootfs/api/migrations/0003_application_allowed_origins_and_more.py b/rootfs/api/migrations/0003_application_allowed_origins_and_more.py new file mode 100644 index 0000000..4e30289 --- /dev/null +++ b/rootfs/api/migrations/0003_application_allowed_origins_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.16 on 2024-11-14 05:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0002_application'), + ] + + operations = [ + migrations.AddField( + model_name='application', + name='allowed_origins', + field=models.TextField(blank=True, default='', help_text='Allowed origins list to enable CORS, space separated'), + ), + migrations.AddField( + model_name='application', + name='hash_client_secret', + field=models.BooleanField(default=True), + ), + migrations.AlterField( + model_name='application', + name='post_logout_redirect_uris', + field=models.TextField(blank=True, default='', help_text='Allowed Post Logout URIs list, space separated'), + ), + ] diff --git a/rootfs/api/routers.py b/rootfs/api/routers.py index 801d6c9..3e5e981 100644 --- a/rootfs/api/routers.py +++ b/rootfs/api/routers.py @@ -32,4 +32,8 @@ def allow_relation(self, obj1, obj2, **hints): return True def allow_migrate(self, db, app_label, model_name=None, **hints): + if 'replica' in settings.DATABASES and 'model' in hints: + model = hints['model'] + tracker_key = ".".join([model.__module__, model.__name__]) + setattr(self._tracker, tracker_key, 'default') return True diff --git a/rootfs/requirements.txt b/rootfs/requirements.txt index 482fd7f..f8cf2f9 100644 --- a/rootfs/requirements.txt +++ b/rootfs/requirements.txt @@ -1,16 +1,16 @@ # Drycc passport requirements -django==4.2.11 -pytz==2024.1 -django-auth-ldap==4.6.0 -django-cors-headers==4.3.1 -djangorestframework==3.15.1 -gunicorn==22.0.0 -uvicorn==0.29.0 -asgiref==3.8.0 -psycopg[binary]==3.1.18 -requests==2.31.0 +django==4.2.16 +pytz==2024.2 +django-auth-ldap==5.1.0 +django-cors-headers==4.6.0 +djangorestframework==3.15.2 +gunicorn==23.0.0 +uvicorn==0.32.0 +asgiref==3.8.1 +psycopg[binary]==3.2.3 +requests==2.32.3 requests-toolbelt==1.0.0 django_redis==5.4.0 -dj-database-url==2.1.0 -django-oauth-toolkit==2.3.0 -whitenoise==6.6.0 +dj-database-url==2.3.0 +django-oauth-toolkit==3.0.1 +whitenoise==6.8.2 From 3340323df8b958e56cc20a116acd5933cafcd783 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Mon, 18 Nov 2024 16:36:43 +0800 Subject: [PATCH 05/39] chore(charts): change drycc-monitor-grafana to drycc-grafana --- charts/passport/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/passport/values.yaml b/charts/passport/values.yaml index 89fcbcf..7249aa0 100644 --- a/charts/passport/values.yaml +++ b/charts/passport/values.yaml @@ -94,7 +94,7 @@ initApplications: - name: "grafana" key: "" secret: "" - prefix: "drycc-monitor-grafana" + prefix: "drycc-grafana" grant_type: "authorization-code" redirect_uri: "/login/generic_oauth" From fd13351f021247560d72e3655bcd92f6af6290fc Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Tue, 19 Nov 2024 13:54:32 +0800 Subject: [PATCH 06/39] chore(passport): use valkey replace redis --- charts/passport/templates/_helpers.tpl | 25 +++++++++++-------- .../templates/passport-secret-creds.yaml | 3 +++ charts/passport/values.yaml | 6 ++--- rootfs/api/settings/production.py | 21 ++++++++++++---- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/charts/passport/templates/_helpers.tpl b/charts/passport/templates/_helpers.tpl index 0cd32cc..eb50418 100644 --- a/charts/passport/templates/_helpers.tpl +++ b/charts/passport/templates/_helpers.tpl @@ -28,6 +28,21 @@ env: value: {{ .Values.global.platformDomain }} - name: CERT_MANAGER_ENABLED value: "{{ .Values.global.certManagerEnabled }}" +{{- if (.Values.valkeyUrl) }} +- name: DRYCC_VALKEY_URL + valueFrom: + secretKeyRef: + name: passport-creds + key: valkey-url +{{- else if eq .Values.global.valkeyLocation "on-cluster" }} +- name: VALKEY_PASSWORD + valueFrom: + secretKeyRef: + name: valkey-creds + key: password +- name: DRYCC_VALKEY_URL + value: "redis://:$(VALKEY_PASSWORD)@drycc-valkey.{{.Release.Namespace}}.svc.{{.Values.global.clusterDomain}}:16379/1" +{{- end }} {{- if (.Values.databaseUrl) }} - name: DRYCC_DATABASE_URL valueFrom: @@ -57,16 +72,6 @@ env: - name: DRYCC_DATABASE_REPLICA_URL value: "postgres://$(DRYCC_DATABASE_USER):$(DRYCC_DATABASE_PASSWORD)@drycc-database-replica.{{.Release.Namespace}}.svc.{{.Values.global.clusterDomain}}:5432/passport" {{- end }} -- name: DRYCC_REDIS_ADDRS - valueFrom: - secretKeyRef: - name: redis-creds - key: addrs -- name: DRYCC_REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: redis-creds - key: password {{- range $key, $value := .Values.environment }} - name: {{ $key }} value: {{ $value | quote }} diff --git a/charts/passport/templates/passport-secret-creds.yaml b/charts/passport/templates/passport-secret-creds.yaml index 11dba27..d43e344 100644 --- a/charts/passport/templates/passport-secret-creds.yaml +++ b/charts/passport/templates/passport-secret-creds.yaml @@ -6,6 +6,9 @@ metadata: labels: heritage: drycc data: + {{- if (.Values.valkeyUrl) }} + valkey-url: {{ .Values.valkeyUrl | b64enc }} + {{- end }} {{- if (.Values.databaseUrl) }} database-url: {{ .Values.databaseUrl | b64enc }} {{- end }} diff --git a/charts/passport/values.yaml b/charts/passport/values.yaml index 7249aa0..8e845c7 100644 --- a/charts/passport/values.yaml +++ b/charts/passport/values.yaml @@ -38,6 +38,9 @@ podAntiAffinityPreset: replicas: 1 # limitsCpu: "100m" # limitsMemory: "50Mi" + +## valkeyUrl is will no longer use the built-in valkey component +valkeyUrl: "" ## databaseUrl and databaseReplicaUrl are will no longer use the built-in database component databaseUrl: "" databaseReplicaUrl: "" @@ -103,9 +106,6 @@ service: # Provide any additional service annotations annotations: {} -redis: - replicas: 1 - global: # Set the location of Workflow's grafana instance # diff --git a/rootfs/api/settings/production.py b/rootfs/api/settings/production.py index fa0063e..9d73673 100644 --- a/rootfs/api/settings/production.py +++ b/rootfs/api/settings/production.py @@ -324,22 +324,33 @@ "DEFAULT_CODE_CHALLENGE_METHOD": 'S256', } OAUTH2_PROVIDER_APPLICATION_MODEL = 'api.Application' -# Redis Configuration -DRYCC_REDIS_ADDRS = os.environ.get('DRYCC_REDIS_ADDRS', '127.0.0.1:6379').split(",") -DRYCC_REDIS_PASSWORD = os.environ.get('DRYCC_REDIS_PASSWORD', '') +# Valkey Configuration +DRYCC_VALKEY_ADDRS = os.environ.get('DRYCC_VALKEY_ADDRS', '127.0.0.1:6379').split(",") +DRYCC_VALKEY_PASSWORD = os.environ.get('DRYCC_VALKEY_PASSWORD', '') # Cache Configuration CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": ['redis://:{}@{}'.format(DRYCC_REDIS_PASSWORD, DRYCC_REDIS_ADDR) \ - for DRYCC_REDIS_ADDR in DRYCC_REDIS_ADDRS], # noqa + "LOCATION": ['redis://:{}@{}'.format(DRYCC_VALKEY_PASSWORD, DRYCC_VALKEY_ADDR) \ + for DRYCC_VALKEY_ADDR in DRYCC_VALKEY_ADDRS], # noqa "OPTIONS": { "CLIENT_CLASS": "django_redis.client.ShardClient", } } } +# Cache Valkey Configuration +CACHES = { + "default": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": os.environ.get('DRYCC_VALKEY_URL', 'redis://:@127.0.0.1:6379'), + "OPTIONS": { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + } + } +} + # LDAP settings taken from environment variables. LDAP_ENDPOINT = os.environ.get('LDAP_ENDPOINT', '') LDAP_BIND_DN = os.environ.get('LDAP_BIND_DN', '') From bf17dd9275be89f7802f71416afcad02baf19c52 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Mon, 23 Dec 2024 14:07:38 +0800 Subject: [PATCH 07/39] fix(wooddpecker): secsets are deprecated --- .woodpecker/build-linux.yml | 17 +++++++++++------ .woodpecker/chart.yaml | 14 +++++++++----- .woodpecker/manifest.yml | 13 ++++++++----- .woodpecker/test-linux.yml | 11 +++++++---- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/.woodpecker/build-linux.yml b/.woodpecker/build-linux.yml index 782d2f5..3424a97 100644 --- a/.woodpecker/build-linux.yml +++ b/.woodpecker/build-linux.yml @@ -14,12 +14,17 @@ steps: - export VERSION=$([ -z $CI_COMMIT_TAG ] && echo latest || echo $CI_COMMIT_TAG)-$(sed 's#/#-#g' <<< $CI_SYSTEM_PLATFORM) - echo $CONTAINER_PASSWORD | podman login $DRYCC_REGISTRY --username $CONTAINER_USERNAME --password-stdin > /dev/null 2>&1 - make podman-build podman-immutable-push - secrets: - - codename - - dev_registry - - drycc_registry - - container_username - - container_password + environment: + CODENAME: + from_secret: codename + DEV_REGISTRY: + from_secret: dev_registry + DRYCC_REGISTRY: + from_secret: drycc_registry + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password when: event: - push diff --git a/.woodpecker/chart.yaml b/.woodpecker/chart.yaml index 5aa7eb3..40397e0 100644 --- a/.woodpecker/chart.yaml +++ b/.woodpecker/chart.yaml @@ -14,11 +14,15 @@ steps: - helm package -u charts/$${CI_REPO_NAME} --version $CHART_VERSION --app-version $APP_VERSION - echo $CONTAINER_PASSWORD | helm registry login $DRYCC_REGISTRY -u $CONTAINER_USERNAME --password-stdin - helm push $${CI_REPO_NAME}-$CHART_VERSION.tgz oci://$DRYCC_REGISTRY/$([ -z $CI_COMMIT_TAG ] && echo charts-testing || echo charts) - secrets: - - dev_registry - - drycc_registry - - container_username - - container_password + environment: + DEV_REGISTRY: + from_secret: dev_registry + DRYCC_REGISTRY: + from_secret: drycc_registry + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password when: event: - push diff --git a/.woodpecker/manifest.yml b/.woodpecker/manifest.yml index b4735ee..6a91aa3 100644 --- a/.woodpecker/manifest.yml +++ b/.woodpecker/manifest.yml @@ -8,8 +8,9 @@ steps: commands: - sed -i "s/{{project}}/$${CI_REPO_NAME}/g" .woodpecker/manifest.tmpl - sed -i "s/registry.drycc.cc/$${DRYCC_REGISTRY}/g" .woodpecker/manifest.tmpl - secrets: - - drycc_registry + environment: + DRYCC_REGISTRY: + from_secret: drycc_registry when: event: - tag @@ -26,9 +27,11 @@ steps: -v $(pwd):$(pwd) -w $(pwd) docker.io/plugins/manifest - secrets: - - container_username - - container_password + environment: + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password when: event: - tag diff --git a/.woodpecker/test-linux.yml b/.woodpecker/test-linux.yml index 3738680..ded2712 100644 --- a/.woodpecker/test-linux.yml +++ b/.woodpecker/test-linux.yml @@ -12,10 +12,13 @@ steps: image: bash commands: - make test podman-build-test upload-coverage - secrets: - - codename - - dev_registry - - codecov_token + environment: + CODENAME: + from_secret: codename + DEV_REGISTRY: + from_secret: dev_registry + CODECOV_TOKEN: + from_secret: codecov_token when: event: - push From c8ea4aec414e5695562d4041e20f69206883ce26 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Tue, 25 Feb 2025 17:04:40 +0800 Subject: [PATCH 08/39] chore(charts): change upgrade helm hook --- charts/passport/templates/passport-job-upgrade.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/passport/templates/passport-job-upgrade.yaml b/charts/passport/templates/passport-job-upgrade.yaml index 1af08ea..710edfb 100644 --- a/charts/passport/templates/passport-job-upgrade.yaml +++ b/charts/passport/templates/passport-job-upgrade.yaml @@ -5,8 +5,8 @@ metadata: name: drycc-passport-job-upgrade annotations: component.drycc.cc/version: {{ .Values.imageTag }} - helm.sh/hook: post-install,pre-upgrade,pre-rollback - helm.sh/hook-delete-policy: before-hook-creation + helm.sh/hook: post-install,post-upgrade,post-rollback + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded spec: template: spec: From 2102861fcd1f9bcec50dbc065c7e22850328db64 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Thu, 3 Apr 2025 12:48:41 +0800 Subject: [PATCH 09/39] chore(passport): bump version --- rootfs/Dockerfile | 4 ++-- rootfs/Dockerfile.test | 4 ++-- rootfs/dev_requirements.txt | 4 ++-- rootfs/requirements.txt | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/rootfs/Dockerfile b/rootfs/Dockerfile index bb58da3..c45ec6b 100644 --- a/rootfs/Dockerfile +++ b/rootfs/Dockerfile @@ -4,7 +4,7 @@ FROM registry.drycc.cc/drycc/base:${CODENAME} as build-app ADD web /web WORKDIR /web -ENV NODE_VERSION="20" +ENV NODE_VERSION="22" RUN install-stack node $NODE_VERSION && . init-stack \ && npm install --global yarn \ @@ -16,7 +16,7 @@ FROM registry.drycc.cc/drycc/base:${CODENAME} ENV DRYCC_UID=1001 \ DRYCC_GID=1001 \ DRYCC_HOME_DIR=/workspace \ - PYTHON_VERSION="3.12" + PYTHON_VERSION="3.13" RUN groupadd drycc --gid ${DRYCC_GID} \ && useradd drycc -u ${DRYCC_UID} -g ${DRYCC_GID} -s /bin/bash -m -d ${DRYCC_HOME_DIR} diff --git a/rootfs/Dockerfile.test b/rootfs/Dockerfile.test index 3e0230f..5cb59f6 100644 --- a/rootfs/Dockerfile.test +++ b/rootfs/Dockerfile.test @@ -3,8 +3,8 @@ FROM registry.drycc.cc/drycc/base:${CODENAME} ENV DRYCC_HOME_DIR=/workspace \ PGDATA="/var/lib/postgresql/data" \ - PYTHON_VERSION="3.12" \ - POSTGRES_VERSION="15.5" \ + PYTHON_VERSION="3.13" \ + POSTGRES_VERSION="15.12" \ GOSU_VERSION="1.17" COPY requirements.txt ${DRYCC_HOME_DIR}/requirements.txt diff --git a/rootfs/dev_requirements.txt b/rootfs/dev_requirements.txt index ca19f67..9f542ed 100644 --- a/rootfs/dev_requirements.txt +++ b/rootfs/dev_requirements.txt @@ -1,10 +1,10 @@ # test module # test # Run "make test-unit" for the % of code exercised during tests -coverage==7.6.1 +coverage==7.8.0 # Run "make test-style" to check python syntax and style -flake8==7.1.1 +flake8==7.2.0 # mock out python-requests, mostly k8s requests-mock==1.12.1 diff --git a/rootfs/requirements.txt b/rootfs/requirements.txt index f8cf2f9..c70171d 100644 --- a/rootfs/requirements.txt +++ b/rootfs/requirements.txt @@ -1,16 +1,16 @@ # Drycc passport requirements -django==4.2.16 -pytz==2024.2 +django==4.2.20 +pytz==2025.2 django-auth-ldap==5.1.0 -django-cors-headers==4.6.0 -djangorestframework==3.15.2 +django-cors-headers==4.7.0 +djangorestframework==3.16.0 gunicorn==23.0.0 -uvicorn==0.32.0 +uvicorn==0.34.0 asgiref==3.8.1 -psycopg[binary]==3.2.3 +psycopg[binary]==3.2.6 requests==2.32.3 requests-toolbelt==1.0.0 django_redis==5.4.0 dj-database-url==2.3.0 django-oauth-toolkit==3.0.1 -whitenoise==6.8.2 +whitenoise==6.9.0 From a1aecb196caa047196e639a6aa4ca8809aa51f30 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Wed, 7 May 2025 18:02:19 +0800 Subject: [PATCH 10/39] chore(charts): use condition --- charts/passport/templates/_helpers.tpl | 4 +-- .../templates/passport-configmap.yaml | 2 -- .../templates/passport-deployment.yaml | 2 -- .../templates/passport-job-upgrade.yaml | 2 -- .../templates/passport-secret-creds.yaml | 2 -- .../templates/passport-service-account.yaml | 2 -- .../passport/templates/passport-service.yaml | 2 -- charts/passport/values.yaml | 25 +++++-------------- 8 files changed, 8 insertions(+), 33 deletions(-) diff --git a/charts/passport/templates/_helpers.tpl b/charts/passport/templates/_helpers.tpl index eb50418..95f84ac 100644 --- a/charts/passport/templates/_helpers.tpl +++ b/charts/passport/templates/_helpers.tpl @@ -34,7 +34,7 @@ env: secretKeyRef: name: passport-creds key: valkey-url -{{- else if eq .Values.global.valkeyLocation "on-cluster" }} +{{- else if .Values.valkey.enabled }} - name: VALKEY_PASSWORD valueFrom: secretKeyRef: @@ -56,7 +56,7 @@ env: name: passport-creds key: database-replica-url {{- end }} -{{- else if eq .Values.global.databaseLocation "on-cluster" }} +{{- else if .Values.database.enabled }} - name: DRYCC_DATABASE_USER valueFrom: secretKeyRef: diff --git a/charts/passport/templates/passport-configmap.yaml b/charts/passport/templates/passport-configmap.yaml index 858b6cb..71d582e 100644 --- a/charts/passport/templates/passport-configmap.yaml +++ b/charts/passport/templates/passport-configmap.yaml @@ -1,4 +1,3 @@ -{{- if eq .Values.global.passportLocation "on-cluster" }} apiVersion: v1 kind: ConfigMap metadata: @@ -9,4 +8,3 @@ data: data: init-applications.json: |- {{ toPrettyJson .Values.initApplications | indent 4 }} -{{- end }} diff --git a/charts/passport/templates/passport-deployment.yaml b/charts/passport/templates/passport-deployment.yaml index 8017c06..6e5c583 100644 --- a/charts/passport/templates/passport-deployment.yaml +++ b/charts/passport/templates/passport-deployment.yaml @@ -1,4 +1,3 @@ -{{- if eq .Values.global.passportLocation "on-cluster" }} apiVersion: apps/v1 kind: Deployment metadata: @@ -67,4 +66,3 @@ spec: {{- include "passport.envs" . | indent 8 }} {{- include "passport.volumeMounts" . | indent 8 }} {{- include "passport.volumes" . | indent 6 }} -{{- end }} diff --git a/charts/passport/templates/passport-job-upgrade.yaml b/charts/passport/templates/passport-job-upgrade.yaml index 710edfb..433215c 100644 --- a/charts/passport/templates/passport-job-upgrade.yaml +++ b/charts/passport/templates/passport-job-upgrade.yaml @@ -1,4 +1,3 @@ -{{- if eq .Values.global.passportLocation "on-cluster" }} apiVersion: batch/v1 kind: Job metadata: @@ -45,4 +44,3 @@ spec: {{- include "passport.volumeMounts" . | indent 8 }} {{- include "passport.volumes" . | indent 6 }} restartPolicy: Never -{{- end }} diff --git a/charts/passport/templates/passport-secret-creds.yaml b/charts/passport/templates/passport-secret-creds.yaml index d43e344..b5d0f90 100644 --- a/charts/passport/templates/passport-secret-creds.yaml +++ b/charts/passport/templates/passport-secret-creds.yaml @@ -1,4 +1,3 @@ -{{- if eq .Values.global.passportLocation "on-cluster" }} apiVersion: v1 kind: Secret metadata: @@ -24,4 +23,3 @@ data: drycc-passport-{{$name}}-secret: {{ (include "common.secrets.lookup" (dict "secret" "passport-creds" "key" "drycc-passport-($name)-secret" "defaultValue" ($item.secret | default (randAlphaNum 64)) "context" $)) }} {{- end }} {{- end }} -{{- end }} diff --git a/charts/passport/templates/passport-service-account.yaml b/charts/passport/templates/passport-service-account.yaml index 9952519..c5714ad 100644 --- a/charts/passport/templates/passport-service-account.yaml +++ b/charts/passport/templates/passport-service-account.yaml @@ -1,8 +1,6 @@ -{{- if eq .Values.global.passportLocation "on-cluster" }} apiVersion: v1 kind: ServiceAccount metadata: name: drycc-passport labels: heritage: drycc -{{- end }} diff --git a/charts/passport/templates/passport-service.yaml b/charts/passport/templates/passport-service.yaml index 1549301..1b47a57 100644 --- a/charts/passport/templates/passport-service.yaml +++ b/charts/passport/templates/passport-service.yaml @@ -1,4 +1,3 @@ -{{- if eq .Values.global.passportLocation "on-cluster" }} apiVersion: v1 kind: Service metadata: @@ -16,4 +15,3 @@ spec: targetPort: 8000 selector: app: drycc-passport -{{- end }} \ No newline at end of file diff --git a/charts/passport/values.yaml b/charts/passport/values.yaml index 8e845c7..03fbea2 100644 --- a/charts/passport/values.yaml +++ b/charts/passport/values.yaml @@ -106,27 +106,15 @@ service: # Provide any additional service annotations annotations: {} -global: - # Set the location of Workflow's grafana instance - # - # Valid values are: - # - on-cluster: Run Grafana within the Kubernetes cluster - # - off-cluster: Grafana is running outside of the cluster - grafanaLocation: "on-cluster" +valkey: + enabled: true + +database: + enabled: true +global: # Admin email, used for each component to send email to administrator email: "drycc@drycc.cc" - # Set the location of Workflow's PostgreSQL database - # - # Valid values are: - # - on-cluster: Run PostgreSQL within the Kubernetes cluster (credentials are generated - # automatically; backups are sent to object storage - # configured above) - # - off-cluster: Run PostgreSQL outside the Kubernetes cluster (configure in database section) - databaseLocation: "on-cluster" - - # Please check `kubernetes.io/ingress.class` - ingressClass: "" # A domain name consists of one or more parts. # Periods (.) are used to separate these parts. # Each part must be 1 to 63 characters in length and can contain lowercase letters, digits, and hyphens (-). @@ -138,4 +126,3 @@ global: platformDomain: "" # Whether cert_passport is enabled to automatically generate passport certificates certManagerEnabled: true - passportLocation: "on-cluster" From 63974ecc62c41dedf1e595b4e7efa78664cd8488 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Mon, 12 May 2025 09:49:12 +0800 Subject: [PATCH 11/39] chore(charts): change resources format --- charts/passport/templates/_helpers.tpl | 15 --------------- .../passport/templates/passport-deployment.yaml | 5 ++++- .../passport/templates/passport-job-upgrade.yaml | 5 ++++- charts/passport/values.yaml | 11 ++++++++--- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/charts/passport/templates/_helpers.tpl b/charts/passport/templates/_helpers.tpl index 95f84ac..8157a5d 100644 --- a/charts/passport/templates/_helpers.tpl +++ b/charts/passport/templates/_helpers.tpl @@ -79,21 +79,6 @@ env: {{- end }} -{{/* Generate passport deployment limits */}} -{{- define "passport.limits" -}} -{{- if or (.Values.limitsCpu) (.Values.limitsMemory) }} -resources: - limits: -{{- if (.Values.limitsCpu) }} - cpu: {{.Values.limitsCpu}} -{{- end }} -{{- if (.Values.limitsMemory) }} - memory: {{.Values.limitsMemory}} -{{- end }} -{{- end }} -{{- end }} - - {{/* Generate passport deployment volumeMounts */}} {{- define "passport.volumeMounts" }} volumeMounts: diff --git a/charts/passport/templates/passport-deployment.yaml b/charts/passport/templates/passport-deployment.yaml index 6e5c583..9d38074 100644 --- a/charts/passport/templates/passport-deployment.yaml +++ b/charts/passport/templates/passport-deployment.yaml @@ -62,7 +62,10 @@ spec: ports: - containerPort: 8000 name: http - {{- include "passport.limits" . | indent 8 }} + {{- with index .Values "resources" }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} {{- include "passport.envs" . | indent 8 }} {{- include "passport.volumeMounts" . | indent 8 }} {{- include "passport.volumes" . | indent 6 }} diff --git a/charts/passport/templates/passport-job-upgrade.yaml b/charts/passport/templates/passport-job-upgrade.yaml index 433215c..ec06d3b 100644 --- a/charts/passport/templates/passport-job-upgrade.yaml +++ b/charts/passport/templates/passport-job-upgrade.yaml @@ -39,7 +39,10 @@ spec: fi python /workspace/manage.py create_oauth2_application --path /etc/drycc/passport/init-applications.json {{- end }} - {{- include "passport.limits" . | indent 8 }} + {{- with index .Values "resources" }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} {{- include "passport.envs" . | indent 8 }} {{- include "passport.volumeMounts" . | indent 8 }} {{- include "passport.volumes" . | indent 6 }} diff --git a/charts/passport/values.yaml b/charts/passport/values.yaml index 03fbea2..59f8fa3 100644 --- a/charts/passport/values.yaml +++ b/charts/passport/values.yaml @@ -18,6 +18,14 @@ diagnosticMode: args: - infinity +resources: {} + # limits: + # cpu: 200m + # memory: 50Mi + # requests: + # cpu: 100m + # memory: 30Mi + nodeAffinityPreset: key: "drycc.cc/node" type: "soft" @@ -36,9 +44,6 @@ podAntiAffinityPreset: # Set passport deployment replicas replicas: 1 -# limitsCpu: "100m" -# limitsMemory: "50Mi" - ## valkeyUrl is will no longer use the built-in valkey component valkeyUrl: "" ## databaseUrl and databaseReplicaUrl are will no longer use the built-in database component From ff8f9db5f9b7c3673507303397803f8ea0f2f51d Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Tue, 27 May 2025 13:22:39 +0800 Subject: [PATCH 12/39] chore(passport): add user organizations --- rootfs/api/models.py | 11 +++++++++++ rootfs/api/oauth2_validators.py | 1 + rootfs/api/serializers.py | 4 ++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/rootfs/api/models.py b/rootfs/api/models.py index cd4a53c..327e8d8 100644 --- a/rootfs/api/models.py +++ b/rootfs/api/models.py @@ -8,6 +8,17 @@ class User(AbstractUser): email = models.EmailField(_('email address'), unique=True) + @property + def organizations(self) -> list[str]: + results = [] + if self.is_superuser: + results.append("admin") + if self.is_staff: + results.append("staff") + if self.is_active: + results.append(self.username) + return results + class Application(AbstractApplication): diff --git a/rootfs/api/oauth2_validators.py b/rootfs/api/oauth2_validators.py index ee6f654..9fc78ca 100644 --- a/rootfs/api/oauth2_validators.py +++ b/rootfs/api/oauth2_validators.py @@ -16,4 +16,5 @@ def get_additional_claims(self, request): claims["is_staff"] = request.user.is_staff claims["is_active"] = request.user.is_active claims["is_superuser"] = request.user.is_superuser + claims["organizations"] = request.user.organizations return claims diff --git a/rootfs/api/serializers.py b/rootfs/api/serializers.py index 9deb711..c1d8ac2 100644 --- a/rootfs/api/serializers.py +++ b/rootfs/api/serializers.py @@ -18,9 +18,9 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('id', 'username', 'email', 'first_name', 'last_name', - 'is_staff', 'is_active', 'is_superuser') + 'is_staff', 'is_active', 'is_superuser', "organizations") read_only_fields = ('id', 'username', 'is_staff', 'is_active', - 'is_superuser') + 'is_superuser', "organizations") class UserEmailSerializer(serializers.ModelSerializer): From 0ca83b54f2f5214dfac96e189283d8ed86088b67 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Thu, 29 May 2025 13:23:39 +0800 Subject: [PATCH 13/39] chore(passport): use django redis cache --- rootfs/api/settings/production.py | 17 +---------------- rootfs/requirements.txt | 3 ++- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/rootfs/api/settings/production.py b/rootfs/api/settings/production.py index 9d73673..c7c790c 100644 --- a/rootfs/api/settings/production.py +++ b/rootfs/api/settings/production.py @@ -328,26 +328,11 @@ DRYCC_VALKEY_ADDRS = os.environ.get('DRYCC_VALKEY_ADDRS', '127.0.0.1:6379').split(",") DRYCC_VALKEY_PASSWORD = os.environ.get('DRYCC_VALKEY_PASSWORD', '') -# Cache Configuration -CACHES = { - "default": { - "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": ['redis://:{}@{}'.format(DRYCC_VALKEY_PASSWORD, DRYCC_VALKEY_ADDR) \ - for DRYCC_VALKEY_ADDR in DRYCC_VALKEY_ADDRS], # noqa - "OPTIONS": { - "CLIENT_CLASS": "django_redis.client.ShardClient", - } - } -} - # Cache Valkey Configuration CACHES = { "default": { - "BACKEND": "django_redis.cache.RedisCache", + "BACKEND": "django.core.cache.backends.redis.RedisCache", "LOCATION": os.environ.get('DRYCC_VALKEY_URL', 'redis://:@127.0.0.1:6379'), - "OPTIONS": { - "CLIENT_CLASS": "django_redis.client.DefaultClient", - } } } diff --git a/rootfs/requirements.txt b/rootfs/requirements.txt index c70171d..ea92393 100644 --- a/rootfs/requirements.txt +++ b/rootfs/requirements.txt @@ -10,7 +10,8 @@ asgiref==3.8.1 psycopg[binary]==3.2.6 requests==2.32.3 requests-toolbelt==1.0.0 -django_redis==5.4.0 +redis==6.2.0 +hiredis==3.2.1 dj-database-url==2.3.0 django-oauth-toolkit==3.0.1 whitenoise==6.9.0 From 75ea4d7f4e2c4596b37c4679f09596fd36f557a7 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Mon, 9 Jun 2025 10:04:46 +0800 Subject: [PATCH 14/39] chore(passport): change user organizations to roles --- rootfs/api/models.py | 4 ++-- rootfs/api/oauth2_validators.py | 18 ++++++++++++++++-- rootfs/api/serializers.py | 8 ++++---- rootfs/api/settings/production.py | 3 ++- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/rootfs/api/models.py b/rootfs/api/models.py index 327e8d8..9b97bc0 100644 --- a/rootfs/api/models.py +++ b/rootfs/api/models.py @@ -9,14 +9,14 @@ class User(AbstractUser): email = models.EmailField(_('email address'), unique=True) @property - def organizations(self) -> list[str]: + def roles(self) -> list[str]: results = [] if self.is_superuser: results.append("admin") if self.is_staff: results.append("staff") if self.is_active: - results.append(self.username) + results.append("users") return results diff --git a/rootfs/api/oauth2_validators.py b/rootfs/api/oauth2_validators.py index 9fc78ca..c265583 100644 --- a/rootfs/api/oauth2_validators.py +++ b/rootfs/api/oauth2_validators.py @@ -3,7 +3,20 @@ class CustomOAuth2Validator(OAuth2Validator): - oidc_claim_scope = None + oidc_claim_scope = OAuth2Validator.oidc_claim_scope + oidc_claim_scope.update({ + "id": "profile", + "name": "profile", + "username": "profile", + "email": "email", + "roles": "profile", + "first_name": "profile", + "last_name": "profile", + "is_staff": "profile", + "is_active": "profile", + "is_superuser": "profile", + "preferred_username": "profile", + }) def get_additional_claims(self, request): claims = super().get_additional_claims(request) @@ -11,10 +24,11 @@ def get_additional_claims(self, request): claims["name"] = request.user.username claims["username"] = request.user.username claims["email"] = request.user.email + claims["roles"] = request.user.roles claims["first_name"] = request.user.first_name claims["last_name"] = request.user.last_name claims["is_staff"] = request.user.is_staff claims["is_active"] = request.user.is_active claims["is_superuser"] = request.user.is_superuser - claims["organizations"] = request.user.organizations + claims["preferred_username"] = request.user.username return claims diff --git a/rootfs/api/serializers.py b/rootfs/api/serializers.py index c1d8ac2..76d43cb 100644 --- a/rootfs/api/serializers.py +++ b/rootfs/api/serializers.py @@ -17,10 +17,10 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ('id', 'username', 'email', 'first_name', 'last_name', - 'is_staff', 'is_active', 'is_superuser', "organizations") - read_only_fields = ('id', 'username', 'is_staff', 'is_active', - 'is_superuser', "organizations") + fields = ('id', 'username', 'email', 'roles', 'first_name', 'last_name', + 'is_staff', 'is_active', 'is_superuser') + read_only_fields = ('id', 'username', 'roles', 'is_staff', 'is_active', + 'is_superuser') class UserEmailSerializer(serializers.ModelSerializer): diff --git a/rootfs/api/settings/production.py b/rootfs/api/settings/production.py index c7c790c..1c642ec 100644 --- a/rootfs/api/settings/production.py +++ b/rootfs/api/settings/production.py @@ -317,10 +317,11 @@ "REFRESH_TOKEN_EXPIRE_SECONDS": int(os.environ.get('REFRESH_TOKEN_EXPIRE_SECONDS', 60 * 86400)), # noqa "ROTATE_REFRESH_TOKEN": True, "SCOPES": { + "email": "Email", "profile": "Profile", "openid": "OpenID Connect scope", }, - "DEFAULT_SCOPES": ['openid', ], + "DEFAULT_SCOPES": ['openid', 'email', 'profile'], "DEFAULT_CODE_CHALLENGE_METHOD": 'S256', } OAUTH2_PROVIDER_APPLICATION_MODEL = 'api.Application' From 519f74839b0ece82a6bfaf441aa3983ad81c5688 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Mon, 16 Jun 2025 14:09:57 +0800 Subject: [PATCH 15/39] chore(auth): add username regex --- rootfs/api/models.py | 8 ++++++++ rootfs/api/settings/production.py | 3 +++ 2 files changed, 11 insertions(+) diff --git a/rootfs/api/models.py b/rootfs/api/models.py index 9b97bc0..787e7e2 100644 --- a/rootfs/api/models.py +++ b/rootfs/api/models.py @@ -1,4 +1,6 @@ from django.db import models +from django.conf import settings +from django.contrib.auth import validators from django.contrib.auth.models import AbstractUser from django.utils.translation import gettext_lazy as _ @@ -6,6 +8,12 @@ class User(AbstractUser): + username_validator = validators.UnicodeUsernameValidator( + regex=settings.USERNAME_REGEX, + message=_("Enter a valid username. This value may match the regex {}.".format( + settings.USERNAME_REGEX + )) + ) email = models.EmailField(_('email address'), unique=True) @property diff --git a/rootfs/api/settings/production.py b/rootfs/api/settings/production.py index 1c642ec..7091cc3 100644 --- a/rootfs/api/settings/production.py +++ b/rootfs/api/settings/production.py @@ -399,5 +399,8 @@ EMAIL_USE_TLS = os.environ.get('EMAIL_USE_TLS', 'false').lower() == "true" EMAIL_USE_SSL = os.environ.get('EMAIL_USE_SSL', 'false').lower() == "true" +# username regex +USERNAME_REGEX = os.environ.get('USERNAME_REGEX', '^[a-z][a-z0-9]{4,}$') +# hcaptcha config H_CAPTCHA_KEY = os.environ.get("H_CAPTCHA_KEY") H_CAPTCHA_SECRET = os.environ.get("H_CAPTCHA_SECRET") From e8580188d89fd9c52edc43177c64796d43f9dfae Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Thu, 19 Jun 2025 10:51:53 +0800 Subject: [PATCH 16/39] chore(passport): add username validators --- charts/passport/templates/_helpers.tpl | 75 ++++++++++++++++++- .../templates/passport-configmap.yaml | 7 +- charts/passport/values.yaml | 3 +- rootfs/api/models.py | 22 +----- rootfs/api/oauth2_validators.py | 2 - rootfs/api/serializers.py | 4 +- rootfs/api/settings/production.py | 10 +++ rootfs/api/validators.py | 20 +++++ 8 files changed, 116 insertions(+), 27 deletions(-) create mode 100644 rootfs/api/validators.py diff --git a/charts/passport/templates/_helpers.tpl b/charts/passport/templates/_helpers.tpl index 8157a5d..c19b5c2 100644 --- a/charts/passport/templates/_helpers.tpl +++ b/charts/passport/templates/_helpers.tpl @@ -90,7 +90,6 @@ volumeMounts: readOnly: true {{- end }} - {{/* Generate passport deployment volumes */}} {{- define "passport.volumes" }} volumes: @@ -101,3 +100,77 @@ volumes: configMap: name: passport-config {{- end }} + +{{/* Generate passport default reserved usernames */}} +{{- define "passport.defaultReservedUsernames" }} +admin +administrator +anonymous +asshole +bastard +billing +callback +cancer +cocaine +contact +coronavirus +cracker +database +developer +doopai +drycc +email +explore +faggot +feedback +hacker +helpdesk +hentai +heroin +hitler +homophobic +horny +idiot +killer +login +logout +moderator +murder +nigger +nigga +official +payment +pedophile +pornhub +profile +racist +rapist +recovery +register +retard +scammer +security +service +settings +sexist +signup +signin +slave +spammer +staff +suicide +support +system +terrorism +trending +undefined +update +username +verification +verify +webmaster +webhook +wetback +whore +xvideos +{{- end }} diff --git a/charts/passport/templates/passport-configmap.yaml b/charts/passport/templates/passport-configmap.yaml index 71d582e..62dab9b 100644 --- a/charts/passport/templates/passport-configmap.yaml +++ b/charts/passport/templates/passport-configmap.yaml @@ -5,6 +5,11 @@ metadata: labels: heritage: drycc data: -data: + reserved-usernames.txt: |- +{{- if .Values.reservedUsernames }} +{{- (tpl .Values.reservedUsernames $) | nindent 4 }} +{{- else}} +{{- include "passport.defaultReservedUsernames" . | nindent 4 }} +{{- end }} init-applications.json: |- {{ toPrettyJson .Values.initApplications | indent 4 }} diff --git a/charts/passport/values.yaml b/charts/passport/values.yaml index 59f8fa3..511b70c 100644 --- a/charts/passport/values.yaml +++ b/charts/passport/values.yaml @@ -86,7 +86,8 @@ environment: adminUsername: "admin" adminPassword: "admin" adminEmail: "admin@email.com" - +# Reserved usernames +reservedUsernames: "" # The following configurations to initialize oauth2 application # Names are all lowercase letters # The key and secret are generated automatically if they are empty diff --git a/rootfs/api/models.py b/rootfs/api/models.py index 787e7e2..397af2f 100644 --- a/rootfs/api/models.py +++ b/rootfs/api/models.py @@ -1,32 +1,14 @@ from django.db import models -from django.conf import settings -from django.contrib.auth import validators from django.contrib.auth.models import AbstractUser from django.utils.translation import gettext_lazy as _ - from oauth2_provider.models import AbstractApplication +from .validators import UsernameValidator class User(AbstractUser): - username_validator = validators.UnicodeUsernameValidator( - regex=settings.USERNAME_REGEX, - message=_("Enter a valid username. This value may match the regex {}.".format( - settings.USERNAME_REGEX - )) - ) + username_validator = UsernameValidator() email = models.EmailField(_('email address'), unique=True) - @property - def roles(self) -> list[str]: - results = [] - if self.is_superuser: - results.append("admin") - if self.is_staff: - results.append("staff") - if self.is_active: - results.append("users") - return results - class Application(AbstractApplication): diff --git a/rootfs/api/oauth2_validators.py b/rootfs/api/oauth2_validators.py index c265583..b91e976 100644 --- a/rootfs/api/oauth2_validators.py +++ b/rootfs/api/oauth2_validators.py @@ -9,7 +9,6 @@ class CustomOAuth2Validator(OAuth2Validator): "name": "profile", "username": "profile", "email": "email", - "roles": "profile", "first_name": "profile", "last_name": "profile", "is_staff": "profile", @@ -24,7 +23,6 @@ def get_additional_claims(self, request): claims["name"] = request.user.username claims["username"] = request.user.username claims["email"] = request.user.email - claims["roles"] = request.user.roles claims["first_name"] = request.user.first_name claims["last_name"] = request.user.last_name claims["is_staff"] = request.user.is_staff diff --git a/rootfs/api/serializers.py b/rootfs/api/serializers.py index 76d43cb..9deb711 100644 --- a/rootfs/api/serializers.py +++ b/rootfs/api/serializers.py @@ -17,9 +17,9 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ('id', 'username', 'email', 'roles', 'first_name', 'last_name', + fields = ('id', 'username', 'email', 'first_name', 'last_name', 'is_staff', 'is_active', 'is_superuser') - read_only_fields = ('id', 'username', 'roles', 'is_staff', 'is_active', + read_only_fields = ('id', 'username', 'is_staff', 'is_active', 'is_superuser') diff --git a/rootfs/api/settings/production.py b/rootfs/api/settings/production.py index 7091cc3..e2960c4 100644 --- a/rootfs/api/settings/production.py +++ b/rootfs/api/settings/production.py @@ -401,6 +401,16 @@ # username regex USERNAME_REGEX = os.environ.get('USERNAME_REGEX', '^[a-z][a-z0-9]{4,}$') + +# reserved username +RESERVED_USERNAMES_PATH = os.environ.get( + 'RESERVED_USERNAMES_PATH', '/etc/drycc/passport/reserved-usernames.txt') +if os.path.exists(RESERVED_USERNAMES_PATH): + with open(RESERVED_USERNAMES_PATH) as f: + RESERVED_USERNAMES = [line.strip() for line in f if line] +else: + RESERVED_USERNAMES = ["drycc", "admin", "doopai"] + # hcaptcha config H_CAPTCHA_KEY = os.environ.get("H_CAPTCHA_KEY") H_CAPTCHA_SECRET = os.environ.get("H_CAPTCHA_SECRET") diff --git a/rootfs/api/validators.py b/rootfs/api/validators.py new file mode 100644 index 0000000..e442287 --- /dev/null +++ b/rootfs/api/validators.py @@ -0,0 +1,20 @@ +from django.contrib.auth import validators +from django.utils.translation import gettext_lazy as _ +from django.conf import settings +from django.core.exceptions import ValidationError + + +class UsernameValidator(validators.UnicodeUsernameValidator): + regex = settings.USERNAME_REGEX + message = _( + f"Enter a valid username. This value may match the regex {regex}." + ) + + def __call__(self, value): + if value in settings.RESERVED_USERNAMES: + raise ValidationError( + _("The current username is on the blocklist."), + code=self.code, + params={"value": value} + ) + super().__call__(value) From 19bb429874605b46b2982c6addc63404014ee4aa Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Fri, 20 Jun 2025 08:38:52 +0800 Subject: [PATCH 17/39] chore(grafana): change grafana oauth2 url --- charts/passport/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/passport/values.yaml b/charts/passport/values.yaml index 511b70c..a8f5a6d 100644 --- a/charts/passport/values.yaml +++ b/charts/passport/values.yaml @@ -105,7 +105,7 @@ initApplications: secret: "" prefix: "drycc-grafana" grant_type: "authorization-code" - redirect_uri: "/login/generic_oauth" + redirect_uri: "/oauth2/callback" # Service service: From a8e2e8993a9a27f6b885572c7592d5a9813dd84b Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Tue, 15 Jul 2025 23:26:22 +0800 Subject: [PATCH 18/39] chore(charts): remove cluster domain --- charts/passport/templates/_helpers.tpl | 6 +++--- charts/passport/values.yaml | 7 ------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/charts/passport/templates/_helpers.tpl b/charts/passport/templates/_helpers.tpl index c19b5c2..4d429bb 100644 --- a/charts/passport/templates/_helpers.tpl +++ b/charts/passport/templates/_helpers.tpl @@ -41,7 +41,7 @@ env: name: valkey-creds key: password - name: DRYCC_VALKEY_URL - value: "redis://:$(VALKEY_PASSWORD)@drycc-valkey.{{.Release.Namespace}}.svc.{{.Values.global.clusterDomain}}:16379/1" + value: "redis://:$(VALKEY_PASSWORD)@drycc-valkey:16379/1" {{- end }} {{- if (.Values.databaseUrl) }} - name: DRYCC_DATABASE_URL @@ -68,9 +68,9 @@ env: name: database-creds key: password - name: DRYCC_DATABASE_URL - value: "postgres://$(DRYCC_DATABASE_USER):$(DRYCC_DATABASE_PASSWORD)@drycc-database.{{.Release.Namespace}}.svc.{{.Values.global.clusterDomain}}:5432/passport" + value: "postgres://$(DRYCC_DATABASE_USER):$(DRYCC_DATABASE_PASSWORD)@drycc-database:5432/passport" - name: DRYCC_DATABASE_REPLICA_URL - value: "postgres://$(DRYCC_DATABASE_USER):$(DRYCC_DATABASE_PASSWORD)@drycc-database-replica.{{.Release.Namespace}}.svc.{{.Values.global.clusterDomain}}:5432/passport" + value: "postgres://$(DRYCC_DATABASE_USER):$(DRYCC_DATABASE_PASSWORD)@drycc-database-replica:5432/passport" {{- end }} {{- range $key, $value := .Values.environment }} - name: {{ $key }} diff --git a/charts/passport/values.yaml b/charts/passport/values.yaml index a8f5a6d..8fd8778 100644 --- a/charts/passport/values.yaml +++ b/charts/passport/values.yaml @@ -119,13 +119,6 @@ database: enabled: true global: - # Admin email, used for each component to send email to administrator - email: "drycc@drycc.cc" - # A domain name consists of one or more parts. - # Periods (.) are used to separate these parts. - # Each part must be 1 to 63 characters in length and can contain lowercase letters, digits, and hyphens (-). - # It must start and end with a lowercase letter or digit. - clusterDomain: "cluster.local" # The public resolvable hostname to build your cluster with. # # This will be the hostname that is used to build endpoints such as "drycc.$HOSTNAME" From d8387ad0d2eae12f4eab45a18163712d8fecdee9 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Wed, 3 Sep 2025 09:57:44 +0800 Subject: [PATCH 19/39] fix(passport): token_checksum field is required --- rootfs/api/serializers.py | 1 + rootfs/api/urls.py | 5 ++--- rootfs/api/views.py | 11 +---------- rootfs/requirements.txt | 18 +++++++++--------- rootfs/web/src/services/tokens.js | 2 +- 5 files changed, 14 insertions(+), 23 deletions(-) diff --git a/rootfs/api/serializers.py b/rootfs/api/serializers.py index 9deb711..9c73ff3 100644 --- a/rootfs/api/serializers.py +++ b/rootfs/api/serializers.py @@ -56,6 +56,7 @@ class Meta: class UserTokensSerializer(serializers.ModelSerializer): """Serialize user status for a AccessToken model.""" application = serializers.ReadOnlyField(source='application.name') + token_checksum = serializers.ReadOnlyField(required=False) class Meta: model = AccessToken diff --git a/rootfs/api/urls.py b/rootfs/api/urls.py index c1c1aeb..eabd62d 100644 --- a/rootfs/api/urls.py +++ b/rootfs/api/urls.py @@ -38,14 +38,13 @@ re_path(r'logout/?$', views.UserLogoutView.as_view(), name='user_logout'), re_path(r'tokens/?$', - views.UserTokensTemplateView.as_view({'get': 'retrieve'}), + views.UserTokensView.as_view({'get': 'list'}), name='user_tokens'), re_path(r'tokens/(?P.+)/?$', - views.UserTokenDeleteView.as_view({'delete': 'destroy'}), + views.UserTokensView.as_view({'delete': 'destroy'}), name='user_grants'), re_path(r'email/?$', views.UserEmailView.as_view({'get': 'retrieve'})), re_path(r'password/?$', views.UserAccountPasswordView.as_view({'put': 'update'}), name='user_account_update_password'), - ] diff --git a/rootfs/api/views.py b/rootfs/api/views.py index 1f54de2..ac5ce61 100644 --- a/rootfs/api/views.py +++ b/rootfs/api/views.py @@ -261,20 +261,11 @@ def get_queryset(self, *args, **kwargs): q, **serializer.validated_data).order_by(self.order_by)[0:100] -class UserTokensTemplateView(ListViewSet): +class UserTokensView(ListViewSet): model = AccessToken serializer_class = serializers.UserTokensSerializer order_by = '-created' - def retrieve(self, request, *args, **kwargs): - tokens = self.get_queryset(*args, **kwargs) - serializer = self.get_serializer(tokens, many=True) - return Response(serializer.data) - - -class UserTokenDeleteView(ListViewSet): - model = AccessToken - def destroy(self, request, *args, **kwargs): token = get_object_or_404(self.model, id=self.kwargs['pk'], diff --git a/rootfs/requirements.txt b/rootfs/requirements.txt index ea92393..a387fa9 100644 --- a/rootfs/requirements.txt +++ b/rootfs/requirements.txt @@ -1,17 +1,17 @@ # Drycc passport requirements -django==4.2.20 +django==4.2.23 pytz==2025.2 -django-auth-ldap==5.1.0 +django-auth-ldap==5.2.0 django-cors-headers==4.7.0 -djangorestframework==3.16.0 +djangorestframework==3.16.1 gunicorn==23.0.0 -uvicorn==0.34.0 -asgiref==3.8.1 -psycopg[binary]==3.2.6 -requests==2.32.3 +uvicorn==0.35.0 +asgiref==3.9.1 +psycopg[binary]==3.2.9 +requests==2.32.5 requests-toolbelt==1.0.0 -redis==6.2.0 +redis==6.4.0 hiredis==3.2.1 -dj-database-url==2.3.0 +dj-database-url==3.0.1 django-oauth-toolkit==3.0.1 whitenoise==6.9.0 diff --git a/rootfs/web/src/services/tokens.js b/rootfs/web/src/services/tokens.js index 42a702a..e628add 100644 --- a/rootfs/web/src/services/tokens.js +++ b/rootfs/web/src/services/tokens.js @@ -5,7 +5,7 @@ export function getAccessTokenList() { } export function dealAccessTokenList(obj) { - return obj.data.map(item => { + return obj.data.results.map(item => { return { id: item.id, application: item.application, From 06ba34255ceadb05eb0181f870236cb7fbccc8db Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Thu, 4 Sep 2025 09:18:13 +0800 Subject: [PATCH 20/39] chore(charts): use randAlphaNum replace randAscii --- charts/passport/templates/passport-secret-creds.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/passport/templates/passport-secret-creds.yaml b/charts/passport/templates/passport-secret-creds.yaml index b5d0f90..c05e224 100644 --- a/charts/passport/templates/passport-secret-creds.yaml +++ b/charts/passport/templates/passport-secret-creds.yaml @@ -14,7 +14,7 @@ data: {{- if (.Values.databaseReplicaUrl) }} database-replica-url: {{ .Values.databaseReplicaUrl | b64enc }} {{- end }} - django-secret-key: {{ (include "common.secrets.lookup" (dict "secret" "passport-creds" "key" "django-secret-key" "defaultValue" (randAscii 64) "context" $)) }} + django-secret-key: {{ (include "common.secrets.lookup" (dict "secret" "passport-creds" "key" "django-secret-key" "defaultValue" (randAlphaNum 64) "context" $)) }} oidc-rsa-private-key: {{genPrivateKey "rsa" | b64enc}} {{- range $item := .Values.initApplications }} {{- if ($item.prefix) }} From 91ffae13b52253d6060783cbbd4a005e09cf566d Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Mon, 15 Sep 2025 23:11:26 +0800 Subject: [PATCH 21/39] chore(django): bump version to 5.2.6 --- rootfs/Dockerfile.test | 4 ++-- rootfs/dev_requirements.txt | 4 ++-- rootfs/requirements.txt | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/rootfs/Dockerfile.test b/rootfs/Dockerfile.test index 5cb59f6..e7e2134 100644 --- a/rootfs/Dockerfile.test +++ b/rootfs/Dockerfile.test @@ -4,8 +4,8 @@ FROM registry.drycc.cc/drycc/base:${CODENAME} ENV DRYCC_HOME_DIR=/workspace \ PGDATA="/var/lib/postgresql/data" \ PYTHON_VERSION="3.13" \ - POSTGRES_VERSION="15.12" \ - GOSU_VERSION="1.17" + POSTGRES_VERSION="17.6" \ + GOSU_VERSION="1.18" COPY requirements.txt ${DRYCC_HOME_DIR}/requirements.txt COPY dev_requirements.txt ${DRYCC_HOME_DIR}/dev_requirements.txt diff --git a/rootfs/dev_requirements.txt b/rootfs/dev_requirements.txt index 9f542ed..ef0abcb 100644 --- a/rootfs/dev_requirements.txt +++ b/rootfs/dev_requirements.txt @@ -1,10 +1,10 @@ # test module # test # Run "make test-unit" for the % of code exercised during tests -coverage==7.8.0 +coverage==7.10.6 # Run "make test-style" to check python syntax and style -flake8==7.2.0 +flake8==7.3.0 # mock out python-requests, mostly k8s requests-mock==1.12.1 diff --git a/rootfs/requirements.txt b/rootfs/requirements.txt index a387fa9..e007b6a 100644 --- a/rootfs/requirements.txt +++ b/rootfs/requirements.txt @@ -1,17 +1,17 @@ # Drycc passport requirements -django==4.2.23 +django==5.2.6 pytz==2025.2 django-auth-ldap==5.2.0 -django-cors-headers==4.7.0 +django-cors-headers==4.8.0 djangorestframework==3.16.1 gunicorn==23.0.0 uvicorn==0.35.0 asgiref==3.9.1 -psycopg[binary]==3.2.9 +psycopg[binary]==3.2.10 requests==2.32.5 requests-toolbelt==1.0.0 redis==6.4.0 hiredis==3.2.1 dj-database-url==3.0.1 django-oauth-toolkit==3.0.1 -whitenoise==6.9.0 +whitenoise==6.10.0 From c72ecfceacb02235fdfc90d260ef7dc8fe5b1b2d Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Tue, 16 Sep 2025 16:37:25 +0800 Subject: [PATCH 22/39] fix(charts): name variable reference error --- charts/passport/templates/passport-secret-creds.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/passport/templates/passport-secret-creds.yaml b/charts/passport/templates/passport-secret-creds.yaml index c05e224..1304712 100644 --- a/charts/passport/templates/passport-secret-creds.yaml +++ b/charts/passport/templates/passport-secret-creds.yaml @@ -19,7 +19,7 @@ data: {{- range $item := .Values.initApplications }} {{- if ($item.prefix) }} {{- $name := ($item.name | replace " " "-" | lower) }} - drycc-passport-{{$name}}-key: {{ (include "common.secrets.lookup" (dict "secret" "passport-creds" "key" "drycc-passport-($name)-key" "defaultValue" ($item.key | default (randAlphaNum 40)) "context" $)) }} - drycc-passport-{{$name}}-secret: {{ (include "common.secrets.lookup" (dict "secret" "passport-creds" "key" "drycc-passport-($name)-secret" "defaultValue" ($item.secret | default (randAlphaNum 64)) "context" $)) }} + drycc-passport-{{$name}}-key: {{ (include "common.secrets.lookup" (dict "secret" "passport-creds" "key" (printf "drycc-passport-%s-key" $name) "defaultValue" ($item.key | default (randAlphaNum 40)) "context" $)) }} + drycc-passport-{{$name}}-secret: {{ (include "common.secrets.lookup" (dict "secret" "passport-creds" "key" (printf "drycc-passport-%s-secret" $name) "defaultValue" ($item.secret | default (randAlphaNum 64)) "context" $)) }} {{- end }} {{- end }} From 53a91c4a6e56f00b71df4a57ff10b7f5d68c63f8 Mon Sep 17 00:00:00 2001 From: lijianguo Date: Wed, 24 Sep 2025 16:05:26 +0800 Subject: [PATCH 23/39] chore(passport): logout request method not allow (#10) --- rootfs/web/src/components/UserMenu.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootfs/web/src/components/UserMenu.vue b/rootfs/web/src/components/UserMenu.vue index b740305..cec87a6 100644 --- a/rootfs/web/src/components/UserMenu.vue +++ b/rootfs/web/src/components/UserMenu.vue @@ -28,7 +28,7 @@
  • - Sign out + Sign out
  • From f6ecde8f48ca8e3628c6cc8c749ced7becd12f3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 16:06:03 +0800 Subject: [PATCH 24/39] chore(deps): bump axios from 0.26.1 to 0.30.2 in /rootfs/web (#12) Bumps [axios](https://github.com/axios/axios) from 0.26.1 to 0.30.2. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.26.1...v0.30.2) --- updated-dependencies: - dependency-name: axios dependency-version: 0.30.2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- rootfs/web/package-lock.json | 424 +++++++++++++++++++++-- rootfs/web/package.json | 2 +- rootfs/web/yarn.lock | 653 ++++++++++++++++++++++------------- 3 files changed, 807 insertions(+), 272 deletions(-) diff --git a/rootfs/web/package-lock.json b/rootfs/web/package-lock.json index 798ffc0..c8ac336 100644 --- a/rootfs/web/package-lock.json +++ b/rootfs/web/package-lock.json @@ -7,9 +7,10 @@ "": { "name": "web", "version": "0.0.0", + "license": "Apache-2.0", "dependencies": { "@icon-park/vue-next": "^1.3.6", - "axios": "^0.26.1", + "axios": "^0.30.2", "vant": "^3.4.5", "vue": "^3.2.31", "vue-i18n": "^9.1.9", @@ -274,12 +275,42 @@ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.31.tgz", "integrity": "sha512-ymN2pj6zEjiKJZbrf98UM2pfDd6F2H7ksKw7NDt/ZZ1fh5Ei39X5tABugtT03ZRlWd9imccoK0hE8hpjpU7irQ==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "version": "0.30.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.30.2.tgz", + "integrity": "sha512-0pE4RQ4UQi1jKY6p7u6i1Tkzqmu+d+/tHS7Q7rKunWLB9WyilBTpHHpXzPNMDj5hTbK0B0PTLSz07yqMBiF6xg==", "dependencies": { - "follow-redirects": "^1.14.8" + "follow-redirects": "^1.15.4", + "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==", + "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==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, "node_modules/csstype": { @@ -287,6 +318,68 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "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==", + "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==", + "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==", + "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==", + "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/esbuild": { "version": "0.14.25", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.25.tgz", @@ -648,9 +741,9 @@ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" }, "node_modules/follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "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", @@ -666,6 +759,21 @@ } } }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "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/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -681,10 +789,58 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "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==", + "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==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/has": { "version": "1.0.3", @@ -698,6 +854,42 @@ "node": ">= 0.4.0" } }, + "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==", + "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==", + "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==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/is-core-module": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", @@ -718,6 +910,33 @@ "sourcemap-codec": "^1.4.8" } }, + "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==", + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/nanoid": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", @@ -757,6 +976,11 @@ "url": "https://opencollective.com/postcss/" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -1136,12 +1360,36 @@ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.31.tgz", "integrity": "sha512-ymN2pj6zEjiKJZbrf98UM2pfDd6F2H7ksKw7NDt/ZZ1fh5Ei39X5tABugtT03ZRlWd9imccoK0hE8hpjpU7irQ==" }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "version": "0.30.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.30.2.tgz", + "integrity": "sha512-0pE4RQ4UQi1jKY6p7u6i1Tkzqmu+d+/tHS7Q7rKunWLB9WyilBTpHHpXzPNMDj5hTbK0B0PTLSz07yqMBiF6xg==", "requires": { - "follow-redirects": "^1.14.8" + "follow-redirects": "^1.15.4", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "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==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" } }, "csstype": { @@ -1149,6 +1397,50 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, + "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==" + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "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==", + "requires": { + "es-errors": "^1.3.0" + } + }, + "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==", + "requires": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + } + }, "esbuild": { "version": "0.14.25", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.25.tgz", @@ -1323,9 +1615,21 @@ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" }, "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==" + }, + "form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + } }, "fsevents": { "version": "2.3.2", @@ -1335,10 +1639,40 @@ "optional": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "requires": { + "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" + } + }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + } + }, + "gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" }, "has": { "version": "1.0.3", @@ -1349,6 +1683,27 @@ "function-bind": "^1.1.1" } }, + "has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "requires": { + "has-symbols": "^1.0.3" + } + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, "is-core-module": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", @@ -1366,6 +1721,24 @@ "sourcemap-codec": "^1.4.8" } }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, "nanoid": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", @@ -1392,6 +1765,11 @@ "source-map-js": "^1.0.2" } }, + "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==" + }, "resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", diff --git a/rootfs/web/package.json b/rootfs/web/package.json index bd7d73b..178c079 100644 --- a/rootfs/web/package.json +++ b/rootfs/web/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@icon-park/vue-next": "^1.3.6", - "axios": "^0.26.1", + "axios": "^0.30.2", "vant": "^3.4.5", "vue": "^3.2.31", "vue-i18n": "^9.1.9", diff --git a/rootfs/web/yarn.lock b/rootfs/web/yarn.lock index 726bfe6..dfd0be5 100644 --- a/rootfs/web/yarn.lock +++ b/rootfs/web/yarn.lock @@ -3,19 +3,16 @@ "@babel/parser@^7.16.4": - "integrity" "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==" - "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz" - "version" "7.16.7" + version "7.16.7" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz" "@icon-park/vue-next@^1.3.6": - "integrity" "sha512-AZaCcjRPU9vTNVfcrG03CYJM+uv0SXx5lC4njanlRorFo+TV/x0ZTYGYGpTR/l6ek6QmFu9THmrgqKl7i/8yHg==" - "resolved" "https://registry.npmjs.org/@icon-park/vue-next/-/vue-next-1.3.6.tgz" - "version" "1.3.6" + version "1.3.6" + resolved "https://registry.npmjs.org/@icon-park/vue-next/-/vue-next-1.3.6.tgz" "@intlify/core-base@9.1.9": - "integrity" "sha512-x5T0p/Ja0S8hs5xs+ImKyYckVkL4CzcEXykVYYV6rcbXxJTe2o58IquSqX9bdncVKbRZP7GlBU1EcRaQEEJ+vw==" - "resolved" "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.9.tgz" - "version" "9.1.9" + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.9.tgz" dependencies: "@intlify/devtools-if" "9.1.9" "@intlify/message-compiler" "9.1.9" @@ -25,98 +22,84 @@ "@intlify/vue-devtools" "9.1.9" "@intlify/devtools-if@9.1.9": - "integrity" "sha512-oKSMKjttG3Ut/1UGEZjSdghuP3fwA15zpDPcjkf/1FjlOIm6uIBGMNS5jXzsZy593u+P/YcnrZD6cD3IVFz9vQ==" - "resolved" "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.9.tgz" - "version" "9.1.9" + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.9.tgz" dependencies: "@intlify/shared" "9.1.9" "@intlify/message-compiler@9.1.9": - "integrity" "sha512-6YgCMF46Xd0IH2hMRLCssZI3gFG4aywidoWQ3QP4RGYQXQYYfFC54DxhSgfIPpVoPLQ+4AD29eoYmhiHZ+qLFQ==" - "resolved" "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.9.tgz" - "version" "9.1.9" + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.9.tgz" dependencies: "@intlify/message-resolver" "9.1.9" "@intlify/shared" "9.1.9" - "source-map" "0.6.1" + source-map "0.6.1" "@intlify/message-resolver@9.1.9": - "integrity" "sha512-Lx/DBpigeK0sz2BBbzv5mu9/dAlt98HxwbG7xLawC3O2xMF9MNWU5FtOziwYG6TDIjNq0O/3ZbOJAxwITIWXEA==" - "resolved" "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.9.tgz" - "version" "9.1.9" + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.9.tgz" "@intlify/runtime@9.1.9": - "integrity" "sha512-XgPw8+UlHCiie3fI41HPVa/VDJb3/aSH7bLhY1hJvlvNV713PFtb4p4Jo+rlE0gAoMsMCGcsiT982fImolSltg==" - "resolved" "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.9.tgz" - "version" "9.1.9" + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.9.tgz" dependencies: "@intlify/message-compiler" "9.1.9" "@intlify/message-resolver" "9.1.9" "@intlify/shared" "9.1.9" "@intlify/shared@9.1.9": - "integrity" "sha512-xKGM1d0EAxdDFCWedcYXOm6V5Pfw/TMudd6/qCdEb4tv0hk9EKeg7lwQF1azE0dP2phvx0yXxrt7UQK+IZjNdw==" - "resolved" "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.9.tgz" - "version" "9.1.9" + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.9.tgz" "@intlify/vue-devtools@9.1.9": - "integrity" "sha512-YPehH9uL4vZcGXky4Ev5qQIITnHKIvsD2GKGXgqf+05osMUI6WSEQHaN9USRa318Rs8RyyPCiDfmA0hRu3k7og==" - "resolved" "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.9.tgz" - "version" "9.1.9" + version "9.1.9" + resolved "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.9.tgz" dependencies: "@intlify/message-resolver" "9.1.9" "@intlify/runtime" "9.1.9" "@intlify/shared" "9.1.9" "@popperjs/core@^2.9.2": - "integrity" "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==" - "resolved" "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz" - "version" "2.11.2" + version "2.11.2" + resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz" "@vant/icons@^1.7.1": - "integrity" "sha512-tW4EqzxN4kXw1rnlnQJQHofEifPbt/gECOWiibomht8QLyvoGuE4iUmDFS288dJ07ZjuTy0bhdABj0SENo2fmQ==" - "resolved" "https://registry.npmjs.org/@vant/icons/-/icons-1.7.3.tgz" - "version" "1.7.3" + version "1.7.3" + resolved "https://registry.npmjs.org/@vant/icons/-/icons-1.7.3.tgz" "@vant/popperjs@^1.1.0": - "integrity" "sha512-8MD1gz146awV/uPxYjz4pet22f7a9YVKqk7T+gFkWFwT9mEcrIUEg/xPrdOnWKLP9puXyYtm7oVfSDSefZ/p/w==" - "resolved" "https://registry.npmjs.org/@vant/popperjs/-/popperjs-1.1.0.tgz" - "version" "1.1.0" + version "1.1.0" + resolved "https://registry.npmjs.org/@vant/popperjs/-/popperjs-1.1.0.tgz" dependencies: "@popperjs/core" "^2.9.2" "@vant/use@^1.3.5": - "integrity" "sha512-3z+nywPaV2F5BdJO7RQxWlgfzJeEOmViD2yHMb7Tg+R4NR/7iQskqW8v2Cnv9FWSJgTOSHlcr7UzeLpiTAP4HA==" - "resolved" "https://registry.npmjs.org/@vant/use/-/use-1.3.6.tgz" - "version" "1.3.6" + version "1.3.6" + resolved "https://registry.npmjs.org/@vant/use/-/use-1.3.6.tgz" "@vitejs/plugin-vue@^2.2.4": - "integrity" "sha512-ev9AOlp0ljCaDkFZF3JwC/pD2N4Hh+r5srl5JHM6BKg5+99jiiK0rE/XaRs3pVm1wzyKkjUy/StBSoXX5fFzcw==" - "resolved" "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.2.4.tgz" - "version" "2.2.4" + version "2.2.4" + resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.2.4.tgz" "@vue/compiler-core@3.2.31": - "integrity" "sha512-aKno00qoA4o+V/kR6i/pE+aP+esng5siNAVQ422TkBNM6qA4veXiZbSe8OTXHXquEi/f6Akc+nLfB4JGfe4/WQ==" - "resolved" "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.31.tgz" - "version" "3.2.31" + version "3.2.31" + resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.31.tgz" dependencies: "@babel/parser" "^7.16.4" "@vue/shared" "3.2.31" - "estree-walker" "^2.0.2" - "source-map" "^0.6.1" + estree-walker "^2.0.2" + source-map "^0.6.1" "@vue/compiler-dom@3.2.31": - "integrity" "sha512-60zIlFfzIDf3u91cqfqy9KhCKIJgPeqxgveH2L+87RcGU/alT6BRrk5JtUso0OibH3O7NXuNOQ0cDc9beT0wrg==" - "resolved" "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.31.tgz" - "version" "3.2.31" + version "3.2.31" + resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.31.tgz" dependencies: "@vue/compiler-core" "3.2.31" "@vue/shared" "3.2.31" -"@vue/compiler-sfc@^3.2.31", "@vue/compiler-sfc@3.2.31": - "integrity" "sha512-748adc9msSPGzXgibHiO6T7RWgfnDcVQD+VVwYgSsyyY8Ans64tALHZANrKtOzvkwznV/F4H7OAod/jIlp/dkQ==" - "resolved" "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.31.tgz" - "version" "3.2.31" +"@vue/compiler-sfc@3.2.31", "@vue/compiler-sfc@^3.2.31": + version "3.2.31" + resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.31.tgz" dependencies: "@babel/parser" "^7.16.4" "@vue/compiler-core" "3.2.31" @@ -124,253 +107,428 @@ "@vue/compiler-ssr" "3.2.31" "@vue/reactivity-transform" "3.2.31" "@vue/shared" "3.2.31" - "estree-walker" "^2.0.2" - "magic-string" "^0.25.7" - "postcss" "^8.1.10" - "source-map" "^0.6.1" + estree-walker "^2.0.2" + magic-string "^0.25.7" + postcss "^8.1.10" + source-map "^0.6.1" "@vue/compiler-ssr@3.2.31": - "integrity" "sha512-mjN0rqig+A8TVDnsGPYJM5dpbjlXeHUm2oZHZwGyMYiGT/F4fhJf/cXy8QpjnLQK4Y9Et4GWzHn9PS8AHUnSkw==" - "resolved" "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.31.tgz" - "version" "3.2.31" + version "3.2.31" + resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.31.tgz" dependencies: "@vue/compiler-dom" "3.2.31" "@vue/shared" "3.2.31" "@vue/devtools-api@^6.0.0", "@vue/devtools-api@^6.0.0-beta.7": - "integrity" "sha512-T34EjcArVqzANedEZe2kXQ+AZsld2z1ptJlkOGm87+blk+s6udnP4ze/NYqV8lz1o9AIivimN0xxteLlWiWQdg==" - "resolved" "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.13.tgz" - "version" "6.0.13" + version "6.0.13" + resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.13.tgz" "@vue/reactivity-transform@3.2.31": - "integrity" "sha512-uS4l4z/W7wXdI+Va5pgVxBJ345wyGFKvpPYtdSgvfJfX/x2Ymm6ophQlXXB6acqGHtXuBqNyyO3zVp9b1r0MOA==" - "resolved" "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.31.tgz" - "version" "3.2.31" + version "3.2.31" + resolved "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.31.tgz" dependencies: "@babel/parser" "^7.16.4" "@vue/compiler-core" "3.2.31" "@vue/shared" "3.2.31" - "estree-walker" "^2.0.2" - "magic-string" "^0.25.7" + estree-walker "^2.0.2" + magic-string "^0.25.7" "@vue/reactivity@3.2.31": - "integrity" "sha512-HVr0l211gbhpEKYr2hYe7hRsV91uIVGFYNHj73njbARVGHQvIojkImKMaZNDdoDZOIkMsBc9a1sMqR+WZwfSCw==" - "resolved" "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.31.tgz" - "version" "3.2.31" + version "3.2.31" + resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.31.tgz" dependencies: "@vue/shared" "3.2.31" "@vue/runtime-core@3.2.31": - "integrity" "sha512-Kcog5XmSY7VHFEMuk4+Gap8gUssYMZ2+w+cmGI6OpZWYOEIcbE0TPzzPHi+8XTzAgx1w/ZxDFcXhZeXN5eKWsA==" - "resolved" "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.31.tgz" - "version" "3.2.31" + version "3.2.31" + resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.31.tgz" dependencies: "@vue/reactivity" "3.2.31" "@vue/shared" "3.2.31" "@vue/runtime-dom@3.2.31": - "integrity" "sha512-N+o0sICVLScUjfLG7u9u5XCjvmsexAiPt17GNnaWHJUfsKed5e85/A3SWgKxzlxx2SW/Hw7RQxzxbXez9PtY3g==" - "resolved" "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.31.tgz" - "version" "3.2.31" + version "3.2.31" + resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.31.tgz" dependencies: "@vue/runtime-core" "3.2.31" "@vue/shared" "3.2.31" - "csstype" "^2.6.8" + csstype "^2.6.8" "@vue/server-renderer@3.2.31": - "integrity" "sha512-8CN3Zj2HyR2LQQBHZ61HexF5NReqngLT3oahyiVRfSSvak+oAvVmu8iNLSu6XR77Ili2AOpnAt1y8ywjjqtmkg==" - "resolved" "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.31.tgz" - "version" "3.2.31" + version "3.2.31" + resolved "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.31.tgz" dependencies: "@vue/compiler-ssr" "3.2.31" "@vue/shared" "3.2.31" "@vue/shared@3.2.31": - "integrity" "sha512-ymN2pj6zEjiKJZbrf98UM2pfDd6F2H7ksKw7NDt/ZZ1fh5Ei39X5tABugtT03ZRlWd9imccoK0hE8hpjpU7irQ==" - "resolved" "https://registry.npmjs.org/@vue/shared/-/shared-3.2.31.tgz" - "version" "3.2.31" - -"axios@^0.26.1": - "integrity" "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==" - "resolved" "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz" - "version" "0.26.1" - dependencies: - "follow-redirects" "^1.14.8" - -"csstype@^2.6.8": - "integrity" "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" - "resolved" "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz" - "version" "2.6.20" - -"esbuild-linux-64@0.14.25": - "integrity" "sha512-+aKHdHZmX9qwVlQmu5xYXh7GsBFf4TWrePgeJTalhXHOG7NNuUwoHmketGiZEoNsWyyqwH9rE5BC+iwcLY30Ug==" - "resolved" "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.25.tgz" - "version" "0.14.25" - -"esbuild@^0.14.14": - "integrity" "sha512-4JHEIOMNFvK09ziiL+iVmldIhLbn49V4NAVo888tcGFKedEZY/Y8YapfStJ6zSE23tzYPKxqKwQBnQoIO0BI/Q==" - "resolved" "https://registry.npmjs.org/esbuild/-/esbuild-0.14.25.tgz" - "version" "0.14.25" + version "3.2.31" + resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.31.tgz" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +axios@^0.30.2: + version "0.30.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.30.2.tgz#256d3a8ee765cc27188d08b8b545a5f5a0c77dad" + dependencies: + follow-redirects "^1.15.4" + form-data "^4.0.4" + proxy-from-env "^1.1.0" + +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + dependencies: + delayed-stream "~1.0.0" + +csstype@^2.6.8: + version "2.6.20" + resolved "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +esbuild-android-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.25.tgz#d532d38cb5fe0ae45167ce35f4bbc784c636be40" + +esbuild-android-arm64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.25.tgz#9c5bb3366aabfd14a1c726d36978b79441dfcb6e" + +esbuild-darwin-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.25.tgz#05dcdb6d884f427039ffee5e92ff97527e56c26d" + +esbuild-darwin-arm64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.25.tgz#28e080da4ea0cfe9498071e7f8060498caee1a95" + +esbuild-freebsd-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.25.tgz#200d3664a3b945bc9fdcba73614b49a11ebd1cfa" + +esbuild-freebsd-arm64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.25.tgz#624b08c5da6013bdc312aaa23c4ff409580f5c3c" + +esbuild-linux-32@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.25.tgz#0238e597eb0b60aa06c7e98fccbbfd6bb9a0d6c5" + +esbuild-linux-64@0.14.25: + version "0.14.25" + resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.25.tgz" + +esbuild-linux-arm64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.25.tgz#7ac94371418a2640ba413bc1700aaedeb2794e52" + +esbuild-linux-arm@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.25.tgz#034bd18e9310b9f010c89f90ef7f05706689600b" + +esbuild-linux-mips64le@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.25.tgz#05f98a8cf6b578eab6b4e6b0ab094f37530934f4" + +esbuild-linux-ppc64le@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.25.tgz#46fd0add8d8535678439d7a9c2876ad20042d952" + +esbuild-linux-riscv64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.25.tgz#ea2e986f0f3e5df73c635135dd778051734fc605" + +esbuild-linux-s390x@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.25.tgz#efe89486e9a1b1508925048076e3f3a6698aa6a3" + +esbuild-netbsd-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.25.tgz#439fe27d8ee3b5887501ee63988e85f920107db6" + +esbuild-openbsd-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.25.tgz#31ebf616aadf6e60674469f2b92cec92280d9930" + +esbuild-sunos-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.25.tgz#815e4f936d74970292a63ccfd5791fe5e3569f5f" + +esbuild-windows-32@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.25.tgz#189e14df2478f2c193c86968ab1fb54e1ceaafd2" + +esbuild-windows-64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.25.tgz#3d5fbfdc3856850bb47439299e3b60dd18be111f" + +esbuild-windows-arm64@0.14.25: + version "0.14.25" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.25.tgz#8b243cbbad8a86cf98697da9ccb88c05df2ef458" + +esbuild@^0.14.14: + version "0.14.25" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.25.tgz" optionalDependencies: - "esbuild-android-64" "0.14.25" - "esbuild-android-arm64" "0.14.25" - "esbuild-darwin-64" "0.14.25" - "esbuild-darwin-arm64" "0.14.25" - "esbuild-freebsd-64" "0.14.25" - "esbuild-freebsd-arm64" "0.14.25" - "esbuild-linux-32" "0.14.25" - "esbuild-linux-64" "0.14.25" - "esbuild-linux-arm" "0.14.25" - "esbuild-linux-arm64" "0.14.25" - "esbuild-linux-mips64le" "0.14.25" - "esbuild-linux-ppc64le" "0.14.25" - "esbuild-linux-riscv64" "0.14.25" - "esbuild-linux-s390x" "0.14.25" - "esbuild-netbsd-64" "0.14.25" - "esbuild-openbsd-64" "0.14.25" - "esbuild-sunos-64" "0.14.25" - "esbuild-windows-32" "0.14.25" - "esbuild-windows-64" "0.14.25" - "esbuild-windows-arm64" "0.14.25" - -"estree-walker@^2.0.2": - "integrity" "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" - "resolved" "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz" - "version" "2.0.2" - -"follow-redirects@^1.14.8": - "integrity" "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" - "resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz" - "version" "1.14.9" - -"function-bind@^1.1.1": - "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" - "version" "1.1.1" - -"has@^1.0.3": - "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" - "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz" - "version" "1.0.3" - dependencies: - "function-bind" "^1.1.1" - -"is-core-module@^2.8.1": - "integrity" "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==" - "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz" - "version" "2.8.1" - dependencies: - "has" "^1.0.3" - -"magic-string@^0.25.7": - "integrity" "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==" - "resolved" "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz" - "version" "0.25.9" - dependencies: - "sourcemap-codec" "^1.4.8" - -"nanoid@^3.3.1": - "integrity" "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==" - "resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz" - "version" "3.3.1" - -"path-parse@^1.0.7": - "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - "version" "1.0.7" - -"picocolors@^1.0.0": - "integrity" "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - "resolved" "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - "version" "1.0.0" - -"postcss@^8.1.10", "postcss@^8.4.6": - "integrity" "sha512-2tXEqGxrjvAO6U+CJzDL2Fk2kPHTv1jQsYkSoMeOis2SsYaXRO2COxTdQp99cYvif9JTXaAk9lYGc3VhJt7JPQ==" - "resolved" "https://registry.npmjs.org/postcss/-/postcss-8.4.8.tgz" - "version" "8.4.8" - dependencies: - "nanoid" "^3.3.1" - "picocolors" "^1.0.0" - "source-map-js" "^1.0.2" - -"resolve@^1.22.0": - "integrity" "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==" - "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz" - "version" "1.22.0" - dependencies: - "is-core-module" "^2.8.1" - "path-parse" "^1.0.7" - "supports-preserve-symlinks-flag" "^1.0.0" - -"rollup@^2.59.0": - "integrity" "sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ==" - "resolved" "https://registry.npmjs.org/rollup/-/rollup-2.63.0.tgz" - "version" "2.63.0" + esbuild-android-64 "0.14.25" + esbuild-android-arm64 "0.14.25" + esbuild-darwin-64 "0.14.25" + esbuild-darwin-arm64 "0.14.25" + esbuild-freebsd-64 "0.14.25" + esbuild-freebsd-arm64 "0.14.25" + esbuild-linux-32 "0.14.25" + esbuild-linux-64 "0.14.25" + esbuild-linux-arm "0.14.25" + esbuild-linux-arm64 "0.14.25" + esbuild-linux-mips64le "0.14.25" + esbuild-linux-ppc64le "0.14.25" + esbuild-linux-riscv64 "0.14.25" + esbuild-linux-s390x "0.14.25" + esbuild-netbsd-64 "0.14.25" + esbuild-openbsd-64 "0.14.25" + esbuild-sunos-64 "0.14.25" + esbuild-windows-32 "0.14.25" + esbuild-windows-64 "0.14.25" + esbuild-windows-arm64 "0.14.25" + +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz" + +follow-redirects@^1.15.4: + version "1.15.11" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" + +form-data@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4" + 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" + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + 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" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + dependencies: + has-symbols "^1.0.3" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + dependencies: + function-bind "^1.1.1" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + dependencies: + function-bind "^1.1.2" + +is-core-module@^2.8.1: + version "2.8.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz" + dependencies: + has "^1.0.3" + +magic-string@^0.25.7: + version "0.25.9" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz" + dependencies: + sourcemap-codec "^1.4.8" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + dependencies: + mime-db "1.52.0" + +nanoid@^3.3.1: + version "3.3.1" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz" + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + +postcss@^8.1.10, postcss@^8.4.6: + version "8.4.8" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.8.tgz" + dependencies: + nanoid "^3.3.1" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + +resolve@^1.22.0: + version "1.22.0" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz" + dependencies: + is-core-module "^2.8.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rollup@^2.59.0: + version "2.63.0" + resolved "https://registry.npmjs.org/rollup/-/rollup-2.63.0.tgz" optionalDependencies: - "fsevents" "~2.3.2" + fsevents "~2.3.2" -"source-map-js@^1.0.2": - "integrity" "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - "resolved" "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" - "version" "1.0.2" +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" -"source-map@^0.6.1", "source-map@0.6.1": - "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" - "version" "0.6.1" +source-map@0.6.1, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" -"sourcemap-codec@^1.4.8": - "integrity" "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - "resolved" "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz" - "version" "1.4.8" +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz" -"supports-preserve-symlinks-flag@^1.0.0": - "integrity" "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - "resolved" "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" - "version" "1.0.0" +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" -"vant@^3.4.5": - "integrity" "sha512-3an2v6ejW9pijKmaDbSCW7Hs1R45tqtTIcedfI8hEAA5zC2Bp8cXU6Z4gUCK6/RAGOJsB+vcyLINLb1cGS/SzQ==" - "resolved" "https://registry.npmjs.org/vant/-/vant-3.4.5.tgz" - "version" "3.4.5" +vant@^3.4.5: + version "3.4.5" + resolved "https://registry.npmjs.org/vant/-/vant-3.4.5.tgz" dependencies: "@vant/icons" "^1.7.1" "@vant/popperjs" "^1.1.0" "@vant/use" "^1.3.5" -"vite@^2.5.10", "vite@^2.8.6": - "integrity" "sha512-e4H0QpludOVKkmOsRyqQ7LTcMUDF3mcgyNU4lmi0B5JUbe0ZxeBBl8VoZ8Y6Rfn9eFKYtdXNPcYK97ZwH+K2ug==" - "resolved" "https://registry.npmjs.org/vite/-/vite-2.8.6.tgz" - "version" "2.8.6" +vite@^2.8.6: + version "2.8.6" + resolved "https://registry.npmjs.org/vite/-/vite-2.8.6.tgz" dependencies: - "esbuild" "^0.14.14" - "postcss" "^8.4.6" - "resolve" "^1.22.0" - "rollup" "^2.59.0" + esbuild "^0.14.14" + postcss "^8.4.6" + resolve "^1.22.0" + rollup "^2.59.0" optionalDependencies: - "fsevents" "~2.3.2" + fsevents "~2.3.2" -"vue-i18n@^9.1.9": - "integrity" "sha512-JeRdNVxS2OGp1E+pye5XB6+M6BBkHwAv9C80Q7+kzoMdUDGRna06tjC0vCB/jDX9aWrl5swxOMFcyAr7or8XTA==" - "resolved" "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.9.tgz" - "version" "9.1.9" +vue-i18n@^9.1.9: + version "9.1.9" + resolved "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.9.tgz" dependencies: "@intlify/core-base" "9.1.9" "@intlify/shared" "9.1.9" "@intlify/vue-devtools" "9.1.9" "@vue/devtools-api" "^6.0.0-beta.7" -"vue-router@^4.0.14": - "integrity" "sha512-wAO6zF9zxA3u+7AkMPqw9LjoUCjSxfFvINQj3E/DceTt6uEz1XZLraDhdg2EYmvVwTBSGlLYsUw8bDmx0754Mw==" - "resolved" "https://registry.npmjs.org/vue-router/-/vue-router-4.0.14.tgz" - "version" "4.0.14" +vue-router@^4.0.14: + version "4.0.14" + resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.14.tgz" dependencies: "@vue/devtools-api" "^6.0.0" -"vue@^3.0.0", "vue@^3.2.0", "vue@^3.2.25", "vue@^3.2.31", "vue@3.2.31", "vue@3.x": - "integrity" "sha512-odT3W2tcffTiQCy57nOT93INw1auq5lYLLYtWpPYQQYQOOdHiqFct9Xhna6GJ+pJQaF67yZABraH47oywkJgFw==" - "resolved" "https://registry.npmjs.org/vue/-/vue-3.2.31.tgz" - "version" "3.2.31" +vue@^3.2.31: + version "3.2.31" + resolved "https://registry.npmjs.org/vue/-/vue-3.2.31.tgz" dependencies: "@vue/compiler-dom" "3.2.31" "@vue/compiler-sfc" "3.2.31" @@ -378,7 +536,6 @@ "@vue/server-renderer" "3.2.31" "@vue/shared" "3.2.31" -"yarn@^1.22.17": - "integrity" "sha512-H0p241BXaH0UN9IeH//RT82tl5PfNraVpSpEoW+ET7lmopNC61eZ+A+IDvU8FM6Go5vx162SncDL8J1ZjRBriQ==" - "resolved" "https://registry.npmjs.org/yarn/-/yarn-1.22.17.tgz" - "version" "1.22.17" +yarn@^1.22.17: + version "1.22.17" + resolved "https://registry.npmjs.org/yarn/-/yarn-1.22.17.tgz" From b0a41b5b30c91f4b1d2ac1caadb7a8a10e53266c Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Fri, 10 Oct 2025 16:38:42 +0800 Subject: [PATCH 25/39] chore(passport): bump python requirements version --- rootfs/requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rootfs/requirements.txt b/rootfs/requirements.txt index e007b6a..7f2b4a7 100644 --- a/rootfs/requirements.txt +++ b/rootfs/requirements.txt @@ -1,17 +1,17 @@ # Drycc passport requirements -django==5.2.6 +django==5.2.7 pytz==2025.2 django-auth-ldap==5.2.0 -django-cors-headers==4.8.0 +django-cors-headers==4.9.0 djangorestframework==3.16.1 gunicorn==23.0.0 -uvicorn==0.35.0 -asgiref==3.9.1 +uvicorn==0.37.0 +asgiref==3.10.0 psycopg[binary]==3.2.10 requests==2.32.5 requests-toolbelt==1.0.0 redis==6.4.0 hiredis==3.2.1 dj-database-url==3.0.1 -django-oauth-toolkit==3.0.1 -whitenoise==6.10.0 +django-oauth-toolkit==3.1.0 +whitenoise==6.11.0 From b2d4609424d95d52297281206b2f9207c4eca13c Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Fri, 10 Oct 2025 16:39:52 +0800 Subject: [PATCH 26/39] chore(git): add .venv to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6dd6722..124efaf 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ lib lib64 .env .vscode +.venv # coverage reports .coverage From 15bdb83808588475850be402e0e350582278540c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:33:29 +0800 Subject: [PATCH 27/39] chore(deps): bump django in /rootfs in the pip group across 1 directory (#16) Bumps the pip group with 1 update in the /rootfs directory: [django](https://github.com/django/django). Updates `django` from 5.2.7 to 5.2.8 - [Commits](https://github.com/django/django/compare/5.2.7...5.2.8) --- updated-dependencies: - dependency-name: django dependency-version: 5.2.8 dependency-type: direct:production dependency-group: pip ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- rootfs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootfs/requirements.txt b/rootfs/requirements.txt index 7f2b4a7..a8d7f47 100644 --- a/rootfs/requirements.txt +++ b/rootfs/requirements.txt @@ -1,5 +1,5 @@ # Drycc passport requirements -django==5.2.7 +django==5.2.8 pytz==2025.2 django-auth-ldap==5.2.0 django-cors-headers==4.9.0 From cefaa2cfd131d07b702469014bb5f34296147da0 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Thu, 6 Nov 2025 15:36:02 +0800 Subject: [PATCH 28/39] chore(passport): change env to build arg --- rootfs/Dockerfile | 2 +- rootfs/Dockerfile.test | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rootfs/Dockerfile b/rootfs/Dockerfile index c45ec6b..ee5bced 100644 --- a/rootfs/Dockerfile +++ b/rootfs/Dockerfile @@ -13,7 +13,7 @@ RUN install-stack node $NODE_VERSION && . init-stack \ FROM registry.drycc.cc/drycc/base:${CODENAME} -ENV DRYCC_UID=1001 \ +ARG DRYCC_UID=1001 \ DRYCC_GID=1001 \ DRYCC_HOME_DIR=/workspace \ PYTHON_VERSION="3.13" diff --git a/rootfs/Dockerfile.test b/rootfs/Dockerfile.test index e7e2134..6ed5c60 100644 --- a/rootfs/Dockerfile.test +++ b/rootfs/Dockerfile.test @@ -1,12 +1,13 @@ ARG CODENAME FROM registry.drycc.cc/drycc/base:${CODENAME} -ENV DRYCC_HOME_DIR=/workspace \ - PGDATA="/var/lib/postgresql/data" \ +ARG DRYCC_HOME_DIR=/workspace \ PYTHON_VERSION="3.13" \ POSTGRES_VERSION="17.6" \ GOSU_VERSION="1.18" +ENV PGDATA="/var/lib/postgresql/data" + COPY requirements.txt ${DRYCC_HOME_DIR}/requirements.txt COPY dev_requirements.txt ${DRYCC_HOME_DIR}/dev_requirements.txt From 8beae9e6d0d4f8f97d145f4c35a0df5dde4b5352 Mon Sep 17 00:00:00 2001 From: duanhongyi Date: Wed, 17 Dec 2025 13:05:45 +0800 Subject: [PATCH 29/39] feat(organization): add oauth2 login support --- .../passport/files/reserved-name-patterns.txt | 13 + .../templates/passport-configmap.yaml | 12 +- rootfs/Dockerfile | 4 +- rootfs/Dockerfile.test | 33 +- rootfs/api/apps.py | 10 + rootfs/api/apps_extra/__init__.py | 0 rootfs/api/apps_extra/social_core/__init__.py | 0 rootfs/api/apps_extra/social_core/backends.py | 82 + .../apps_extra/social_core/icons/feishu.svg | 12 + .../apps_extra/social_core/icons/github.svg | 3 + .../apps_extra/social_core/icons/google.svg | 8 + .../apps_extra/social_core/icons/weixin.svg | 14 + .../api/apps_extra/social_core/pipelines.py | 59 + rootfs/api/exceptions.py | 1 - rootfs/api/settings/production.py | 61 +- rootfs/api/signals.py | 0 rootfs/api/static/css/main.css | 243 +- rootfs/api/static/icons/logo.svg | 14 + rootfs/api/templates/user/login.html | 56 +- rootfs/api/templates/user/oauth_callback.html | 91 + rootfs/api/tests/__init__.py | 0 rootfs/api/tests/test_views.py | 163 + rootfs/api/urls.py | 77 +- rootfs/api/utils.py | 44 + rootfs/api/validators.py | 17 +- rootfs/api/views.py | 295 -- rootfs/api/views/__init__.py | 2 + rootfs/api/views/api.py | 278 ++ rootfs/api/views/web.py | 259 ++ rootfs/api/viewset.py | 12 - rootfs/bin/test-unit | 7 + rootfs/passport/urls.py | 5 +- rootfs/requirements.txt | 27 +- rootfs/web/README.md | 83 + rootfs/web/index.html | 6 - rootfs/web/package-lock.json | 2996 +++++++++-------- rootfs/web/package.json | 21 +- rootfs/web/src/.env | 1 - rootfs/web/src/assets/icons/drycc.svg | 13 + rootfs/web/src/assets/icons/github.svg | 8 + rootfs/web/src/assets/icons/google.svg | 3 + .../web/src/components/AccessTokenDelete.js | 4 +- .../web/src/components/AccessTokenDelete.vue | 170 +- rootfs/web/src/components/Dropdown.vue | 357 ++ rootfs/web/src/components/MainFooter.vue | 203 +- rootfs/web/src/components/MainNav.js | 1 - rootfs/web/src/components/MainNav.vue | 97 +- rootfs/web/src/components/NavBar.js | 6 + rootfs/web/src/components/NavBar.vue | 119 +- rootfs/web/src/components/NavBox.vue | 32 +- rootfs/web/src/components/NavMenu.js | 44 +- rootfs/web/src/components/NavMenu.vue | 95 +- rootfs/web/src/components/UserMenu.js | 101 +- rootfs/web/src/components/UserMenu.vue | 64 +- rootfs/web/src/lang/index.js | 7 +- rootfs/web/src/main.js | 13 +- rootfs/web/src/services/identities.js | 21 + rootfs/web/src/styles/unified.css | 230 ++ rootfs/web/src/utils/axios.js | 32 +- rootfs/web/src/views/AccessTokenList.vue | 169 +- rootfs/web/src/views/AccountSetting.js | 96 +- rootfs/web/src/views/AccountSetting.vue | 623 +++- rootfs/web/vite.config.js | 65 +- rootfs/web/yarn.lock | 541 --- 64 files changed, 5390 insertions(+), 2733 deletions(-) create mode 100644 charts/passport/files/reserved-name-patterns.txt create mode 100644 rootfs/api/apps.py create mode 100644 rootfs/api/apps_extra/__init__.py create mode 100644 rootfs/api/apps_extra/social_core/__init__.py create mode 100644 rootfs/api/apps_extra/social_core/backends.py create mode 100644 rootfs/api/apps_extra/social_core/icons/feishu.svg create mode 100644 rootfs/api/apps_extra/social_core/icons/github.svg create mode 100644 rootfs/api/apps_extra/social_core/icons/google.svg create mode 100644 rootfs/api/apps_extra/social_core/icons/weixin.svg create mode 100644 rootfs/api/apps_extra/social_core/pipelines.py create mode 100644 rootfs/api/signals.py create mode 100644 rootfs/api/static/icons/logo.svg create mode 100644 rootfs/api/templates/user/oauth_callback.html create mode 100644 rootfs/api/tests/__init__.py create mode 100644 rootfs/api/tests/test_views.py delete mode 100644 rootfs/api/views.py create mode 100644 rootfs/api/views/__init__.py create mode 100644 rootfs/api/views/api.py create mode 100644 rootfs/api/views/web.py delete mode 100644 rootfs/api/viewset.py create mode 100644 rootfs/web/README.md delete mode 100644 rootfs/web/src/.env create mode 100644 rootfs/web/src/assets/icons/drycc.svg create mode 100644 rootfs/web/src/assets/icons/github.svg create mode 100644 rootfs/web/src/assets/icons/google.svg create mode 100644 rootfs/web/src/components/Dropdown.vue create mode 100644 rootfs/web/src/services/identities.js create mode 100644 rootfs/web/src/styles/unified.css delete mode 100644 rootfs/web/yarn.lock diff --git a/charts/passport/files/reserved-name-patterns.txt b/charts/passport/files/reserved-name-patterns.txt new file mode 100644 index 0000000..1b6ca23 --- /dev/null +++ b/charts/passport/files/reserved-name-patterns.txt @@ -0,0 +1,13 @@ +^backup$ +^catalog$ +^cert-manager$ +^default$ +^drycc(?:-[\w-]+)?$ +^istio(?:-[\w-]+)?$ +^kube(?:-[\w-]+)?$ +^longhorn-system$ +^metallb$ +^mount-s3$ +^topolvm$ +^rook-ceph$ +^personal$ \ No newline at end of file diff --git a/charts/passport/templates/passport-configmap.yaml b/charts/passport/templates/passport-configmap.yaml index 62dab9b..804a95e 100644 --- a/charts/passport/templates/passport-configmap.yaml +++ b/charts/passport/templates/passport-configmap.yaml @@ -5,11 +5,11 @@ metadata: labels: heritage: drycc data: - reserved-usernames.txt: |- -{{- if .Values.reservedUsernames }} -{{- (tpl .Values.reservedUsernames $) | nindent 4 }} -{{- else}} -{{- include "passport.defaultReservedUsernames" . | nindent 4 }} -{{- end }} init-applications.json: |- {{ toPrettyJson .Values.initApplications | indent 4 }} + reserved-name-patterns.txt: |- + {{- if .Values.config.reservedNames }} + {{- (tpl .Values.config.reservedNames $) | nindent 4 }} + {{- else}} + {{- .Files.Get "files/reserved-name-patterns.txt" | nindent 4 }} + {{- end }} \ No newline at end of file diff --git a/rootfs/Dockerfile b/rootfs/Dockerfile index ee5bced..c08620f 100644 --- a/rootfs/Dockerfile +++ b/rootfs/Dockerfile @@ -4,7 +4,7 @@ FROM registry.drycc.cc/drycc/base:${CODENAME} as build-app ADD web /web WORKDIR /web -ENV NODE_VERSION="22" +ENV NODE_VERSION="24" RUN install-stack node $NODE_VERSION && . init-stack \ && npm install --global yarn \ @@ -16,7 +16,7 @@ FROM registry.drycc.cc/drycc/base:${CODENAME} ARG DRYCC_UID=1001 \ DRYCC_GID=1001 \ DRYCC_HOME_DIR=/workspace \ - PYTHON_VERSION="3.13" + PYTHON_VERSION="3.14" RUN groupadd drycc --gid ${DRYCC_GID} \ && useradd drycc -u ${DRYCC_UID} -g ${DRYCC_GID} -s /bin/bash -m -d ${DRYCC_HOME_DIR} diff --git a/rootfs/Dockerfile.test b/rootfs/Dockerfile.test index 6ed5c60..ea284df 100644 --- a/rootfs/Dockerfile.test +++ b/rootfs/Dockerfile.test @@ -1,10 +1,31 @@ +ARG CODENAME +FROM registry.drycc.cc/drycc/base:${CODENAME} as build-app + +ADD web /web +WORKDIR /web + +ENV NODE_VERSION="24" + +RUN install-stack node $NODE_VERSION && . init-stack \ + && npm install --global yarn \ + && yarn install \ + && yarn build + + ARG CODENAME FROM registry.drycc.cc/drycc/base:${CODENAME} -ARG DRYCC_HOME_DIR=/workspace \ - PYTHON_VERSION="3.13" \ - POSTGRES_VERSION="17.6" \ - GOSU_VERSION="1.18" +ARG DRYCC_UID=1001 \ + DRYCC_GID=1001 \ + DRYCC_HOME_DIR=/workspace \ + PYTHON_VERSION="3.14" \ + VALKEY_VERSION="9.0.1" \ + POSTGRES_VERSION="18.1" \ + GOSU_VERSION="1.19" + + +RUN groupadd drycc --gid ${DRYCC_GID} \ + && useradd drycc -u ${DRYCC_UID} -g ${DRYCC_GID} -s /bin/bash -m -d ${DRYCC_HOME_DIR} ENV PGDATA="/var/lib/postgresql/data" @@ -16,6 +37,7 @@ RUN buildDeps='gcc rustc cargo libffi-dev musl-dev libldap2-dev libsasl2-dev'; \ && curl -SsL https://cli.codecov.io/latest/$([ $(dpkg --print-architecture) == "arm64" ] && echo linux-arm64 || echo linux)/codecov -o /usr/local/bin/codecov \ && chmod +x /usr/local/bin/codecov \ && install-stack python $PYTHON_VERSION \ + && install-stack valkey $VALKEY_VERSION \ && install-stack postgresql $POSTGRES_VERSION \ && install-stack gosu $GOSU_VERSION && . init-stack \ && python3 -m venv ${DRYCC_HOME_DIR}/.venv \ @@ -50,6 +72,9 @@ RUN buildDeps='gcc rustc cargo libffi-dev musl-dev libldap2-dev libsasl2-dev'; \ && gosu postgres initdb -D $PGDATA COPY . ${DRYCC_HOME_DIR} +COPY --chown=${DRYCC_UID}:${DRYCC_GID} . ${DRYCC_HOME_DIR} +COPY --chown=${DRYCC_UID}:${DRYCC_GID} --from=build-app /web/dist ${DRYCC_HOME_DIR}/web/dist + WORKDIR ${DRYCC_HOME_DIR} CMD ["bin/boot"] EXPOSE 8000 diff --git a/rootfs/api/apps.py b/rootfs/api/apps.py new file mode 100644 index 0000000..85e1f47 --- /dev/null +++ b/rootfs/api/apps.py @@ -0,0 +1,10 @@ +from django import apps + + +class AppConfig(apps.AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'api' + + def ready(self): + super(AppConfig, self).ready() + __import__("api.signals") diff --git a/rootfs/api/apps_extra/__init__.py b/rootfs/api/apps_extra/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rootfs/api/apps_extra/social_core/__init__.py b/rootfs/api/apps_extra/social_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rootfs/api/apps_extra/social_core/backends.py b/rootfs/api/apps_extra/social_core/backends.py new file mode 100644 index 0000000..34f8ab6 --- /dev/null +++ b/rootfs/api/apps_extra/social_core/backends.py @@ -0,0 +1,82 @@ +import json +from os.path import join, dirname +from pathlib import Path +from social_core.backends.oauth import BaseOAuth2 +from social_core.backends.github import GithubOAuth2 as BaseGithubOAuth2 +from social_core.backends.google import GoogleOAuth2 as BaseGoogleOAuth2 +from social_core.backends.weixin import WeixinOAuth2 as BaseWeixinOAuth2 + + +def icon_path(name): + return Path(join(dirname(__file__), "icons", f"{name}.svg")) + + +class GithubOAuth2(BaseGithubOAuth2): + icon = icon_path("github").read_text(encoding="utf-8") + + +class GoogleOAuth2(BaseGoogleOAuth2): + name = "google" + icon = icon_path("google").read_text(encoding="utf-8") + + +class WeixinOAuth2(BaseWeixinOAuth2): + icon = icon_path("weixin").read_text(encoding="utf-8") + + +class FeiShuOAuth2(BaseOAuth2): + """FeiShu OAuth2 authentication backend""" + name = 'feishu' + icon = icon_path("feishu").read_text(encoding="utf-8") + + AUTHORIZATION_URL = 'https://accounts.feishu.cn/open-apis/authen/v1/authorize' + ACCESS_TOKEN_URL = 'https://open.feishu.cn/open-apis/authen/v2/oauth/token' + USER_INFO_URL = 'https://open.feishu.cn/open-apis/authen/v1/user_info' + + DEFAULT_SCOPE = [''] + REDIRECT_STATE = False + ACCESS_TOKEN_METHOD = 'POST' + EXTRA_DATA = [ + ('refresh_token', 'refresh_token'), + ('expires_in', 'expires'), + ('union_id', 'union_id'), + ('access_token', 'access_token'), + ] + + def request_access_token(self, *args, **kwargs): + """Override to send JSON request provided by FeiShu""" + if 'data' in kwargs: + kwargs['data']['app_id'] = self.setting('KEY') + kwargs['data']['app_secret'] = self.setting('SECRET') + kwargs['data'] = json.dumps(kwargs['data']) + if 'headers' not in kwargs: + kwargs['headers'] = {} + kwargs['headers']['Content-Type'] = 'application/json; charset=utf-8' + return super().request_access_token(*args, **kwargs) + + def get_user_details(self, response): + """Return user details from FeiShu account""" + return { + 'username': response.get('name', ''), + 'email': response.get('email', ''), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + headers = { + 'Authorization': f'Bearer {access_token}', + 'Content-Type': 'application/json; charset=utf-8' + } + response = self.get_json( + self.USER_INFO_URL, + headers=headers + ) + # FeiShu returns data wrapped in 'data' field + if 'data' in response: + response.update(response['data']) + + response['union_id'] = response.get('union_id', '') + return response + + +__all__ = [GithubOAuth2, GoogleOAuth2, WeixinOAuth2, FeiShuOAuth2] diff --git a/rootfs/api/apps_extra/social_core/icons/feishu.svg b/rootfs/api/apps_extra/social_core/icons/feishu.svg new file mode 100644 index 0000000..7afdb94 --- /dev/null +++ b/rootfs/api/apps_extra/social_core/icons/feishu.svg @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/rootfs/api/apps_extra/social_core/icons/github.svg b/rootfs/api/apps_extra/social_core/icons/github.svg new file mode 100644 index 0000000..c5858b0 --- /dev/null +++ b/rootfs/api/apps_extra/social_core/icons/github.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/rootfs/api/apps_extra/social_core/icons/google.svg b/rootfs/api/apps_extra/social_core/icons/google.svg new file mode 100644 index 0000000..c2fd469 --- /dev/null +++ b/rootfs/api/apps_extra/social_core/icons/google.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/rootfs/api/apps_extra/social_core/icons/weixin.svg b/rootfs/api/apps_extra/social_core/icons/weixin.svg new file mode 100644 index 0000000..fe20def --- /dev/null +++ b/rootfs/api/apps_extra/social_core/icons/weixin.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rootfs/api/apps_extra/social_core/pipelines.py b/rootfs/api/apps_extra/social_core/pipelines.py new file mode 100644 index 0000000..d8f24b2 --- /dev/null +++ b/rootfs/api/apps_extra/social_core/pipelines.py @@ -0,0 +1,59 @@ +""" +Custom social auth pipeline for OAuth2 binding and creation guidance. +""" + +import logging + +from django.shortcuts import redirect +from social_django.models import UserSocialAuth + +from api.utils import get_oauth_callback + +logger = logging.getLogger(__name__) + + +def handle_authenticated_binding(backend, uid, details, response, *args, **kwargs): + request = backend.strategy.request + if not request or not request.user.is_authenticated: + return None + + current_user = request.user + try: + existing_social = UserSocialAuth.objects.filter( + provider=backend.name, uid=uid + ).select_related('user').first() + if existing_social and existing_social.user_id != current_user.id: + return redirect(get_oauth_callback(request, 'conflict', backend.name)) + if existing_social and existing_social.user_id == current_user.id: + return redirect(get_oauth_callback(request, 'already_linked', backend.name)) + + UserSocialAuth.objects.create( + user=current_user, + provider=backend.name, + uid=uid, + extra_data=response or {} + ) + return redirect(get_oauth_callback(request, 'linked', backend.name)) + except Exception as exc: + logger.exception(exc) + return redirect(get_oauth_callback(request, 'error', backend.name)) + + +def require_username_password(backend, uid, details, response, user=None, *args, **kwargs): + request = backend.strategy.request + if request and request.user.is_authenticated: + return None + if user: + return None + + email = details.get('email') + if not email: + return redirect(get_oauth_callback(request, 'missing_email', backend.name)) + + backend.strategy.session_set('oauth_pending', { + 'provider': backend.name, + 'uid': uid, + 'email': email, + 'extra_data': response or {}, + }) + return redirect(get_oauth_callback(request, 'pending', backend.name)) diff --git a/rootfs/api/exceptions.py b/rootfs/api/exceptions.py index d409c39..dfd7d2e 100644 --- a/rootfs/api/exceptions.py +++ b/rootfs/api/exceptions.py @@ -43,7 +43,6 @@ def custom_exception_handler(exc, context): # No response means DRF couldn't handle it # Output a generic 500 in a JSON format - print(response) if response is None: logging.exception('Uncaught Exception', exc_info=exc) set_rollback() diff --git a/rootfs/api/settings/production.py b/rootfs/api/settings/production.py index e2960c4..c3536dc 100644 --- a/rootfs/api/settings/production.py +++ b/rootfs/api/settings/production.py @@ -116,6 +116,7 @@ 'gunicorn', 'rest_framework', 'oauth2_provider', + 'social_django', # passport apps 'api' ) @@ -124,6 +125,10 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" AUTHENTICATION_BACKENDS = ( + "api.apps_extra.social_core.backends.FeiShuOAuth2", + "api.apps_extra.social_core.backends.WeixinOAuth2", + "api.apps_extra.social_core.backends.GithubOAuth2", + "api.apps_extra.social_core.backends.GoogleOAuth2", "django.contrib.auth.backends.AllowAllUsersModelBackend", ) @@ -168,6 +173,7 @@ SECURE_BROWSER_XSS_FILTER = True CSRF_COOKIE_SECURE = os.environ.get('CSRF_COOKIE_SECURE', 'false').lower() == "true" SESSION_COOKIE_SECURE = os.environ.get('SESSION_COOKIE_SECURE', 'false').lower() == "true" +CSRF_TRUSTED_ORIGINS = [r for r in os.environ.get('CSRF_TRUSTED_ORIGINS', '').split(',') if r] # Honor HTTPS from a trusted proxy # see https://docs.djangoproject.com/en/2.2/ref/settings/#secure-proxy-ssl-header @@ -274,7 +280,7 @@ SECRET_KEY = os.environ.get('DRYCC_SECRET_KEY', random_secret) # database default setting -DRYCC_DATABASE_URL = os.environ.get('DRYCC_DATABASE_URL', 'postgres://postgres:123456@49.232.207.93:5432/drycc_passport') # noqa +DRYCC_DATABASE_URL = os.environ.get('DRYCC_DATABASE_URL', 'postgres://postgres:@:5432/passport') DATABASES = { 'default': dj_database_url.config(default=DRYCC_DATABASE_URL) } @@ -325,9 +331,6 @@ "DEFAULT_CODE_CHALLENGE_METHOD": 'S256', } OAUTH2_PROVIDER_APPLICATION_MODEL = 'api.Application' -# Valkey Configuration -DRYCC_VALKEY_ADDRS = os.environ.get('DRYCC_VALKEY_ADDRS', '127.0.0.1:6379').split(",") -DRYCC_VALKEY_PASSWORD = os.environ.get('DRYCC_VALKEY_PASSWORD', '') # Cache Valkey Configuration CACHES = { @@ -349,6 +352,42 @@ LDAP_STAFF_GROUP = os.environ.get('LDAP_STAFF_GROUP', '') LDAP_SUPERUSER_GROUP = os.environ.get('LDAP_SUPERUSER_GROUP', '') +# Social Auth settings for OAuth2 providers +SOCIAL_AUTH_FEISHU_KEY = os.environ.get('SOCIAL_AUTH_FEISHU_KEY', '') +SOCIAL_AUTH_FEISHU_SECRET = os.environ.get('SOCIAL_AUTH_FEISHU_SECRET', '') + +SOCIAL_AUTH_WEIXIN_KEY = os.environ.get('SOCIAL_AUTH_WEIXIN_KEY', '') +SOCIAL_AUTH_WEIXIN_SECRET = os.environ.get('SOCIAL_AUTH_WEIXIN_SECRET', '') + +SOCIAL_AUTH_GITHUB_KEY = os.environ.get('SOCIAL_AUTH_GITHUB_KEY', '') +SOCIAL_AUTH_GITHUB_SECRET = os.environ.get('SOCIAL_AUTH_GITHUB_SECRET', '') + +SOCIAL_AUTH_GOOGLE_KEY = os.environ.get('SOCIAL_AUTH_GOOGLE_KEY', '') +SOCIAL_AUTH_GOOGLE_SECRET = os.environ.get('SOCIAL_AUTH_GOOGLE_SECRET', '') + +# Social Auth Pipeline +SOCIAL_AUTH_PIPELINE = ( + 'social_core.pipeline.social_auth.social_details', + 'social_core.pipeline.social_auth.social_uid', + 'social_core.pipeline.social_auth.auth_allowed', + 'api.apps_extra.social_core.pipelines.handle_authenticated_binding', + 'social_core.pipeline.social_auth.social_user', + 'api.apps_extra.social_core.pipelines.require_username_password', + 'social_core.pipeline.social_auth.associate_user', + 'social_core.pipeline.social_auth.load_extra_data', + 'social_core.pipeline.user.user_details', +) + +# Social Auth settings +SOCIAL_AUTH_URL_NAMESPACE = 'social' +SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/access-tokens' +SOCIAL_AUTH_LOGIN_CALLBACK_URL = '/oauth/callback' +SOCIAL_AUTH_LOGIN_ERROR_URL = f'{SOCIAL_AUTH_LOGIN_CALLBACK_URL}?status=error' +SOCIAL_AUTH_NEW_USER_REDIRECT_URL = f'{SOCIAL_AUTH_LOGIN_CALLBACK_URL}?status=pending' +SOCIAL_AUTH_USER_MODEL = 'api.User' +SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True +SOCIAL_AUTH_PROTECTED_USER_FIELDS = ['email',] + # Django LDAP backend configuration. # See https://pythonhosted.org/django-auth-ldap/reference.html # for variables' details. @@ -402,14 +441,14 @@ # username regex USERNAME_REGEX = os.environ.get('USERNAME_REGEX', '^[a-z][a-z0-9]{4,}$') -# reserved username -RESERVED_USERNAMES_PATH = os.environ.get( - 'RESERVED_USERNAMES_PATH', '/etc/drycc/passport/reserved-usernames.txt') -if os.path.exists(RESERVED_USERNAMES_PATH): - with open(RESERVED_USERNAMES_PATH) as f: - RESERVED_USERNAMES = [line.strip() for line in f if line] +# names which apps cannot reserve for routing +RESERVED_NAME_PATTERNS_PATH = os.environ.get( + 'RESERVED_NAME_PATTERNS_PATH', '/etc/controller/reserved-name-patterns.txt') +if os.path.exists(RESERVED_NAME_PATTERNS_PATH): + with open(RESERVED_NAME_PATTERNS_PATH) as f: + RESERVED_NAME_PATTERNS = [line.strip() for line in f if line.strip()] else: - RESERVED_USERNAMES = ["drycc", "admin", "doopai"] + RESERVED_NAME_PATTERNS = [r"^drycc(?:-[\w-]+)?$", r"^kube(?:-[\w-]+)?$", r"^default$"] # hcaptcha config H_CAPTCHA_KEY = os.environ.get("H_CAPTCHA_KEY") diff --git a/rootfs/api/signals.py b/rootfs/api/signals.py new file mode 100644 index 0000000..e69de29 diff --git a/rootfs/api/static/css/main.css b/rootfs/api/static/css/main.css index 432e6bb..43cd30d 100644 --- a/rootfs/api/static/css/main.css +++ b/rootfs/api/static/css/main.css @@ -1,13 +1,51 @@ +:root { + --ui-color-bg: #ffffff; + --ui-color-surface: #ffffff; + --ui-color-text: #3f3f44; + --ui-color-text-secondary: #62748e; + --ui-color-primary: #409eff; + --ui-color-primary-hover: #337ecc; + --ui-color-border: #e2e8f0; + --ui-color-muted-bg: #f1f5f9; + --ui-color-danger: #c20707; + + --ui-font-family-base: benton-sans, 'Helvetica Neue', helvetica, arial, sans-serif; + --ui-font-size-base: 14px; + --ui-line-height-base: 1.42857; + + --ui-radius-sm: 6px; + --ui-radius-md: 8px; + --ui-radius-lg: 12px; + + --ui-shadow-sm: 0 2px 4px rgba(64, 158, 255, 0.3); + --ui-shadow-md: 0 4px 8px rgba(64, 158, 255, 0.4); + --ui-shadow-card: 0 4px 6px rgba(0, 0, 0, 0.1); + + --ui-space-1: 4px; + --ui-space-2: 8px; + --ui-space-3: 12px; + --ui-space-4: 16px; + --ui-space-5: 20px; + --ui-space-6: 24px; + --ui-space-7: 32px; + + --ui-breakpoint-xs: 320px; + --ui-breakpoint-sm: 576px; + --ui-breakpoint-md: 768px; + --ui-breakpoint-lg: 992px; + --ui-breakpoint-xl: 1200px; +} + html,body { height: 100%; } body { - font-family: benton-sans,'Helvetica Neue',helvetica,arial,sans-serif; - font-size: 14px; - line-height: 1.42857; - color: #3f3f44; - background-color: #fff; + font-family: var(--ui-font-family-base); + font-size: var(--ui-font-size-base); + line-height: var(--ui-line-height-base); + color: var(--ui-color-text); + background-color: var(--ui-color-bg); margin: 0; } @@ -16,22 +54,26 @@ body { } .page-wrap { - min-height: 100%; + min-height: 100vh; display: flex; flex-direction: column; - justify-content: space-between } .gradient-primary { - background-image: linear-gradient(to bottom,#409EFF, #337ecc); - background-color: #337ecc + background-image: linear-gradient(to bottom, var(--ui-color-primary), var(--ui-color-primary-hover)); + background-color: var(--ui-color-primary-hover) } .container { position: relative; - height: 100%; - text-align: center; - padding-top: 2%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 20px; + box-sizing: border-box; + flex: 1; + width: 100%; } h1.logo { @@ -55,31 +97,29 @@ h1.logo a:before { } .panel { - max-width: 430px; - margin: 0 auto 20px; - border-radius: 8px; - background-color: rgb(255, 255, 255); - box-shadow: rgba(0, 0, 0, 0.05) 0px 1px 1px; - border-width: 1px; - border-style: solid; - border-color: transparent; - border-image: initial; + min-width: 490px; + max-width: 520px; + margin: 0 auto; + border-radius: var(--ui-radius-lg); + background-color: var(--ui-color-surface); + box-shadow: var(--ui-shadow-card); + border: none; } .panel .h3 { - margin: 40px 20px 0; + margin: 40px 30px 20px; line-height: 1.5; font-size: 24px; - color: #409EFF; + color: var(--ui-color-primary); } h2 { font-family: inherit; font-weight: 200; - color: #409EFF; + color: var(--ui-color-primary); } .panel form { - padding: 30px + padding: 0px 30px 30px 30px } form { @@ -102,7 +142,7 @@ label { form label { text-align: left; width: 100%; - color: rgb(98, 116, 142); + color: var(--ui-color-text-secondary); font-size: 12px; font-weight: bold; } @@ -125,12 +165,20 @@ input:-webkit-autofill { .form-control { display: block; width: 100%; - padding: 6px 12px; + padding: 10px 16px; font-size: 14px; line-height: 1.42857; - border: 1px solid #cbcbd2; - border-radius: 4px; + border: 1px solid var(--ui-color-border); + border-radius: var(--ui-radius-sm); transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s; + background-color: var(--ui-color-surface); + box-sizing: border-box; +} + +.form-control:focus { + outline: none; + border-color: var(--ui-color-primary); + box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1); } input, button, select, textarea { @@ -146,7 +194,7 @@ button, input, optgroup, select, textarea { } input { - -webkit-writing-mode: horizontal-tb !important; + writing-mode: horizontal-tb !important; text-rendering: auto; letter-spacing: normal; word-spacing: normal; @@ -154,12 +202,17 @@ input { text-indent: 0px; text-shadow: none; text-align: start; - -webkit-appearance: textfield; + appearance: textfield; background-color: white; -webkit-rtl-ordering: logical; cursor: text; } +input[disabled], input[readonly] { + background: var(--ui-color-muted-bg); + cursor: not-allowed; +} + form .btn { border: 1px solid transparent; } @@ -173,16 +226,54 @@ form .btn { .btn-primary { color: #fff; - background-color: #337ecc; - background-image: -webkit-linear-gradient(left bottom,rgba(159,88,150,0) 0,rgba(121,187,255,0.6) 100%); + background-color: var(--ui-color-primary); + background-image: none; + border: none; + box-shadow: var(--ui-shadow-sm); + transition: all 0.2s ease; +} + +.btn-primary:hover { + background-color: var(--ui-color-primary-hover); + box-shadow: var(--ui-shadow-md); + transform: translateY(-1px); +} + +.btn-primary:active { + transform: translateY(0); + box-shadow: 0 1px 2px rgba(64, 158, 255, 0.3); } .btn { - border-radius: 5px; + border-radius: var(--ui-radius-sm); padding-left: 18px; padding-right: 18px; } +@media (max-width: 576px) { + .panel { + min-width: auto; + width: 100%; + max-width: 520px; + } + + .panel .h3 { + margin: 30px 20px 16px; + font-size: 22px; + } + + .panel form, + .oauth2-container { + padding-left: 20px; + padding-right: 20px; + } + + .oauth2-btn { + flex: 1 0 100%; + width: 100%; + } +} + .btn-block { display: block; width: 100%; @@ -199,6 +290,89 @@ form .btn { user-select: none; } +/* OAuth2 buttons styles */ +.oauth2-container { + padding: 30px 30px 10px; +} + +.oauth2-buttons { + display: flex; + flex-wrap: wrap; + gap: 15px; + margin-bottom: 24px; + justify-content: space-between; +} + +.oauth2-btn { + display: flex; + align-items: center; + gap: 8px; + padding: 12px 16px; + border: 1px solid #e2e8f0; + border-radius: 6px; + background-color: #ffffff; + color: #4a5568; + text-decoration: none; + font-size: 14px; + font-weight: 500; + transition: all 0.2s ease; + flex: 1 0 calc(50% - 10px); + width: calc(50% - 10px); + min-width: 140px; + max-width: none; + justify-content: center; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); + box-sizing: border-box; +} + +.oauth2-btn:hover { + border-color: #cbd5e0; + background-color: #f7fafc; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08); + transform: translateY(-1px); +} + +.oauth2-btn:focus { + outline: none; + box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1); +} + +.oauth2-icon { + width: 20px; + height: 20px; + display: inline-block; + flex-shrink: 0; +} + +.oauth2-icon svg { + width: 100%; + height: 100%; + fill: currentColor; +} + +.oauth2-email { + background: #f1f5f9; +} + +.oauth2-divider { + display: flex; + align-items: center; + text-align: center; +} + +.oauth2-divider .divider-line { + flex: 1; + height: 1px; + background-color: #e2e8f0; +} + +.oauth2-divider .divider-text { + padding: 0 16px; + color: #a0aec0; + font-size: 14px; + font-weight: 500; +} + .panel-footer { background-color: #f5f5f5; border-top: 1px solid #ddd; @@ -211,6 +385,7 @@ form .btn { display: block; font-size: 17px; color: #4a5568; + text-align: center; } a.panel-footer { diff --git a/rootfs/api/static/icons/logo.svg b/rootfs/api/static/icons/logo.svg new file mode 100644 index 0000000..d970da0 --- /dev/null +++ b/rootfs/api/static/icons/logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rootfs/api/templates/user/login.html b/rootfs/api/templates/user/login.html index 2f81e5f..e2793ed 100644 --- a/rootfs/api/templates/user/login.html +++ b/rootfs/api/templates/user/login.html @@ -2,16 +2,34 @@ - Login + {% if identity_linking %}Identity Linking{% else %}Login{% endif %} -
    +
    -

    Log in to your account

    +

    {% if identity_linking %}Identity Linking{% else %}Log in to your account{% endif %}

    + + {% if not identity_linking %} +
    +
    +
    +
    + + or + +
    +
    + {% endif %} +
    {% csrf_token %} {% if form.errors %} - {% for error in form.non_field_errors %} + {% if identity_linking_error %} +
    + {{ identity_linking_error|escape }} +
    + {% endif %} + {% for error in form.non_field_errors %}
    {{ error|escape }}
    @@ -27,6 +45,9 @@

    Log in to your account

    + {% if identity_linking %} + + {% endif %} {% if registration_enabled %} New to Drycc? Sign Up @@ -39,4 +60,29 @@

    Log in to your account

    {% endif %}
    {% include "base/footer.html" %} -
    \ No newline at end of file +
    + diff --git a/rootfs/api/templates/user/oauth_callback.html b/rootfs/api/templates/user/oauth_callback.html new file mode 100644 index 0000000..39df210 --- /dev/null +++ b/rootfs/api/templates/user/oauth_callback.html @@ -0,0 +1,91 @@ +{% load static %} + + + + + Identity Linking + + +
    +
    +
    +

    Identity Linking

    + + {% if status == 'pending' %} +
    + {% csrf_token %} +
    +

    + This {{ display_name|default:'OAuth' }} identity is not linked yet. Create a new account to continue. +

    +
    + {% if error %} +
    +
    {{ error }}
    +
    + {% endif %} +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    + +
    + I already have an account + + {% elif status == 'linked' %} +
    +
    +

    Identity linked successfully.

    +
    + +
    + + {% elif status == 'already_linked' %} +
    +
    +

    This identity is already linked to your account.

    +
    + +
    + + {% elif status == 'conflict' %} +
    +
    +
    This identity is linked to another account.
    +
    + +
    + + {% elif status == 'missing_email' %} +
    +
    +
    The provider did not supply an email address.
    +
    + +
    + + {% else %} +
    +
    +
    OAuth flow error. Please try again.
    +
    + +
    + {% endif %} +
    +
    + {% include "base/footer.html" %} +
    \ No newline at end of file diff --git a/rootfs/api/tests/__init__.py b/rootfs/api/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rootfs/api/tests/test_views.py b/rootfs/api/tests/test_views.py new file mode 100644 index 0000000..91fe633 --- /dev/null +++ b/rootfs/api/tests/test_views.py @@ -0,0 +1,163 @@ +""" +Test cases for API views +""" +from django.test import TestCase, RequestFactory +from django.contrib.auth import get_user_model +from django.urls import reverse +from rest_framework.test import APITestCase +from rest_framework import status +from oauth2_provider.models import AccessToken + +from api.views import ( + ReadinessCheckView, LivenessCheckView, ActivateAccount +) +from api.forms import RegistrationForm + +User = get_user_model() + + +class TestReadinessCheckView(TestCase): + """Test readiness check view""" + + def test_readiness_check_get(self): + request = RequestFactory().get('/readiness/') + response = ReadinessCheckView.as_view()(request) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content.decode(), 'OK') + + def test_readiness_check_head(self): + request = RequestFactory().head('/readiness/') + response = ReadinessCheckView.as_view()(request) + self.assertEqual(response.status_code, 200) + + +class TestLivenessCheckView(TestCase): + """Test liveness check view""" + + def test_liveness_check_get(self): + request = RequestFactory().get('/liveness/') + response = LivenessCheckView.as_view()(request) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content.decode(), 'OK') + + def test_liveness_check_head(self): + request = RequestFactory().head('/liveness/') + response = LivenessCheckView.as_view()(request) + self.assertEqual(response.status_code, 200) + + +class TestRegistrationView(TestCase): + """Test registration view""" + + def setUp(self): + self.factory = RequestFactory() + + def test_registration_form_valid(self): + form_data = { + 'username': 'testuser', + 'email': 'test@example.com', + 'password1': 'testpassword123', + 'password2': 'testpassword123' + } + form = RegistrationForm(data=form_data) + self.assertTrue(form.is_valid()) + + +class TestActivateAccount(TestCase): + """Test account activation view""" + + def setUp(self): + self.user = User.objects.create_user( + username='testuser', + email='test@example.com', + password='testpass123', + is_active=False + ) + self.factory = RequestFactory() + + def test_activate_account_invalid_token(self): + from django.utils.http import urlsafe_base64_encode + from django.utils.encoding import force_bytes + from django.contrib.messages.storage.fallback import FallbackStorage + + uid = urlsafe_base64_encode(force_bytes(self.user.pk)) + request = self.factory.get(f'/activate/{uid}/invalid-token/') + setattr(request, 'session', 'session') + messages = FallbackStorage(request) + setattr(request, '_messages', messages) + response = ActivateAccount.as_view()(request, uidb64=uid, token='invalid-token') + + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, '/user/activate/fail/') + + +class TestUserDetailView(APITestCase): + """Test user detail viewset""" + + def setUp(self): + self.user = User.objects.create_user( + username='testuser', + email='test@example.com', + password='testpass123' + ) + self.client.force_authenticate(user=self.user) + + def test_get_user_detail(self): + url = '/user/info' + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['username'], 'testuser') + + +class TestUserTokensView(APITestCase): + """Test user tokens viewset""" + + def setUp(self): + self.user = User.objects.create_user( + username='testuser', + email='test@example.com', + password='testpass123' + ) + self.client.force_authenticate(user=self.user) + self.token = AccessToken.objects.create( + user=self.user, + token='tokentest', + application=None, + expires='9999-01-01T00:00:00Z', + scope='read write' + ) + + def test_list_user_tokens(self): + url = reverse('user_tokens') + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_delete_user_token(self): + url = reverse('user_grants', args=[self.token.id]) + response = self.client.delete(url) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + self.assertFalse(AccessToken.objects.filter(id=self.token.id).exists()) + + +class TestUserAccountPasswordView(APITestCase): + """Test user account password view""" + + def setUp(self): + self.user = User.objects.create_user( + username='testuser', + email='test@example.com', + password='oldpassword123' + ) + self.client.force_authenticate(user=self.user) + + def test_update_password_valid(self): + url = '/user/password' + data = { + 'password': 'oldpassword123', + 'new_password': 'newpassword123' + } + response = self.client.put(url, data) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + + self.user.refresh_from_db() + self.assertTrue(self.user.check_password('newpassword123')) diff --git a/rootfs/api/urls.py b/rootfs/api/urls.py index eabd62d..5f1b21b 100644 --- a/rootfs/api/urls.py +++ b/rootfs/api/urls.py @@ -1,50 +1,65 @@ from django.urls import re_path, include from rest_framework.routers import DefaultRouter -from api import views +from api.views import web, api +from passport.views import SettingsViewSet router = DefaultRouter(trailing_slash=False) urlpatterns = [ re_path(r'^', include(router.urls)), - re_path(r'^info/?$', - views.UserDetailView.as_view({'get': 'retrieve', 'put': 'update'})), - re_path(r'update/(?P.+)/(?P.+)/?$', - views.UpdateAccount.as_view(), name='user_update_account'), - re_path(r'^avatar/(?P[-_\w]+)/?$', - views.UserAvatarViewSet.as_view({'get': 'avatar'})), - re_path(r'registration/?$', views.RegistrationView.as_view(), name='registration'), - re_path(r'activate/(?P.+)/(?P.+)/?$', - views.ActivateAccount.as_view(), name='user_activate_account'), - re_path(r'registration/done/?$', views.RegistrationDoneView.as_view(), + # Settings URL (moved from main urls.py) + re_path(r'^settings/?$', SettingsViewSet.as_view({'get': 'retrieve'})), + # User URLs (add user prefix) + re_path(r'^user/info/?$', + api.UserDetailView.as_view({'get': 'retrieve', 'put': 'update'})), + re_path(r'^user/update/(?P.+)/(?P.+)/?$', + web.UpdateAccount.as_view(), name='user_update_account'), + re_path(r'^user/avatar/(?P[-_\w]+)/?$', + api.UserAvatarViewSet.as_view({'get': 'avatar'})), + re_path(r'^user/registration/?$', web.RegistrationView.as_view(), name='registration'), + re_path(r'^user/activate/(?P.+)/(?P.+)/?$', + web.ActivateAccount.as_view(), name='user_activate_account'), + re_path(r'^user/registration/done/?$', web.RegistrationDoneView.as_view(), name='user_registration_done'), - re_path(r'activate/done/?$', views.ActivateAccountDoneView.as_view(), + re_path(r'^user/activate/done/?$', web.ActivateAccountDoneView.as_view(), name='user_activate_account_done'), - re_path(r'activate/fail/?$', views.ActivateAccountFailView.as_view(), + re_path(r'^user/activate/fail/?$', web.ActivateAccountFailView.as_view(), name='user_activate_account_done'), - re_path(r'password_reset/?$', views.UserPasswordResetView.as_view(), + re_path(r'^oauth/callback/?$', web.OAuthCallbackTemplateView.as_view(), + name='oauth_callback'), + re_path(r'^user/password_reset/?$', web.UserPasswordResetView.as_view(), name='user_password_reset'), - re_path(r'password_reset/done/?$', - views.UserPasswordResetDoneView.as_view(), + re_path(r'^user/password_reset/done/?$', + web.UserPasswordResetDoneView.as_view(), name='user_password_reset_done'), - re_path(r'reset/(?P.+)/(?P.+)/?$', - views.UserPasswordResetConfirmView.as_view(), + re_path(r'^user/reset/(?P.+)/(?P.+)/?$', + web.UserPasswordResetConfirmView.as_view(), name='user_password_reset_confirm'), - re_path(r'reset/done/?$', - views.UserPasswordResetCompleteView.as_view(), + re_path(r'^user/reset/done/?$', + web.UserPasswordResetCompleteView.as_view(), name='user_password_reset_complete'), - re_path(r'login/?$', views.UserLoginView.as_view(), name='user_login'), - re_path(r'login/done/?$', views.LoginDoneView.as_view(), name='login_done'), - re_path(r'logout/?$', views.UserLogoutView.as_view(), name='user_logout'), - - re_path(r'tokens/?$', - views.UserTokensView.as_view({'get': 'list'}), + re_path(r'^user/login/?$', web.UserLoginView.as_view(), name='user_login'), + re_path(r'^user/login/done/?$', web.LoginDoneView.as_view(), name='login_done'), + re_path(r'^user/logout/?$', web.UserLogoutView.as_view(), name='user_logout'), + re_path(r'^user/tokens/?$', + api.UserTokensView.as_view({'get': 'list'}), name='user_tokens'), - re_path(r'tokens/(?P.+)/?$', - views.UserTokensView.as_view({'delete': 'destroy'}), + re_path(r'^user/tokens/(?P.+)/?$', + api.UserTokensView.as_view({'delete': 'destroy'}), name='user_grants'), - re_path(r'email/?$', views.UserEmailView.as_view({'get': 'retrieve'})), - re_path(r'password/?$', - views.UserAccountPasswordView.as_view({'put': 'update'}), + re_path(r'^user/email/?$', api.UserEmailView.as_view({'get': 'retrieve'})), + re_path(r'^user/password/?$', + api.UserAccountPasswordView.as_view({'put': 'update'}), name='user_account_update_password'), + re_path(r'^user/identity-providers/?$', + api.IdentityProviderView.as_view(), name='user_identity_providers'), + re_path(r'^user/identities/?$', + api.UserIdentityView.as_view(), name='user_identities'), + re_path(r'^user/identities/(?P\d+)/?$', + api.UserIdentityView.as_view(), name='user_identity_detail'), + re_path(r'^user/oauth/pending/?$', + api.OAuthPendingView.as_view(), name='user_oauth_pending'), + re_path(r'^user/oauth/create/?$', + api.OAuthCreateUserView.as_view(), name='user_oauth_create'), ] diff --git a/rootfs/api/utils.py b/rootfs/api/utils.py index b76040c..26b2a98 100644 --- a/rootfs/api/utils.py +++ b/rootfs/api/utils.py @@ -1,15 +1,21 @@ """ Helper functions used by the Drycc Passport server. """ +import re import logging import datetime +from urllib.parse import urlencode +from django.conf import settings + from django.utils.encoding import force_bytes from django.template.loader import render_to_string from django.utils.http import urlsafe_base64_encode from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.shortcuts import render +from rest_framework.exceptions import ValidationError + logger = logging.getLogger(__name__) @@ -47,6 +53,44 @@ def get_local_host(request): return uri[0:uri.find(request.path)] +def get_user_socials(user): + from api.apps_extra.social_core import backends + provider_map = { + backend_cls.name: backend_cls + for backend_cls in backends.__all__ + } + results = [] + for social in user.social_auth.all(): + backend_cls = provider_map.get(social.provider) + email = None + if social.extra_data: + email = social.extra_data.get('email') or social.extra_data.get('user_email') + results.append({ + 'id': social.id, + 'provider': social.provider, + 'display_name': social.provider.title(), + 'uid': social.uid, + 'icon': backend_cls.icon if backend_cls else '', + 'email': email or user.email, + }) + return results + + +def get_oauth_callback(request, status, provider=None): + query = {'status': status} + domain = get_local_host(request) + if provider: + query['provider'] = provider + return f"{domain}{settings.SOCIAL_AUTH_LOGIN_CALLBACK_URL}?{urlencode(query)}" + + +def validate_reserved_names(value): + """A value cannot use some reserved names.""" + for reserved_name_pattern in settings.RESERVED_NAME_PATTERNS: + if re.match(reserved_name_pattern, value): + raise ValidationError('{} is a reserved name.'.format(value)) + + def send_activation_email(request, user): domain = get_local_host(request) mail_subject = 'Activate your account.' diff --git a/rootfs/api/validators.py b/rootfs/api/validators.py index e442287..b05be8a 100644 --- a/rootfs/api/validators.py +++ b/rootfs/api/validators.py @@ -1,20 +1,19 @@ -from django.contrib.auth import validators + +from django.contrib.auth.validators import UnicodeUsernameValidator from django.utils.translation import gettext_lazy as _ from django.conf import settings -from django.core.exceptions import ValidationError +from django.utils.deconstruct import deconstructible + +from api.utils import validate_reserved_names -class UsernameValidator(validators.UnicodeUsernameValidator): +@deconstructible +class UsernameValidator(UnicodeUsernameValidator): regex = settings.USERNAME_REGEX message = _( f"Enter a valid username. This value may match the regex {regex}." ) def __call__(self, value): - if value in settings.RESERVED_USERNAMES: - raise ValidationError( - _("The current username is on the blocklist."), - code=self.code, - params={"value": value} - ) super().__call__(value) + validate_reserved_names(value) diff --git a/rootfs/api/views.py b/rootfs/api/views.py deleted file mode 100644 index ac5ce61..0000000 --- a/rootfs/api/views.py +++ /dev/null @@ -1,295 +0,0 @@ -import logging -import hashlib -from django.conf import settings -from django.core.cache import cache -from django.utils.decorators import method_decorator -from django.views.decorators.cache import cache_page -from django.contrib import messages, auth -from django.contrib.auth import login -from django.contrib.auth import views -from django.contrib.auth import get_user_model -from django.db.models import Q -from django.shortcuts import redirect, get_object_or_404, render -from django.template.loader import render_to_string -from django.http import HttpResponse, HttpResponseRedirect -from django.utils.encoding import force_bytes, force_str -from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode -from django.views.generic import View -from django.views.generic.edit import CreateView -from django.utils.translation import gettext_lazy as _ -from django.views.generic.base import TemplateView -from django.urls import reverse_lazy -from rest_framework import status -from rest_framework.exceptions import AuthenticationFailed -from rest_framework.response import Response -from rest_framework.viewsets import ModelViewSet -from oauth2_provider.models import AccessToken - -from api import serializers -from api.forms import AuthenticationForm, RegistrationForm -from api.exceptions import ServiceUnavailable, DryccException -from api.utils import token_generator, get_local_host, send_activation_email -from api.viewset import NormalUserViewSet - -User = get_user_model() -logger = logging.getLogger(__name__) - - -class ReadinessCheckView(View): - """ - Simple readiness check view to determine DB connection / query. - """ - - def get(self, request): - try: - import django.db - with django.db.connection.cursor() as c: - c.execute("SELECT 0") - except django.db.Error as e: - raise ServiceUnavailable("Database health check failed") from e - - return HttpResponse("OK") - - head = get - - -class LivenessCheckView(View): - """ - Simple liveness check view to determine if the server - is responding to HTTP requests. - """ - - def get(self, request): - return HttpResponse("OK") - - head = get - - -class RegistrationView(CreateView): - form_class = RegistrationForm - template_name = 'user/registration.html' - success_url = reverse_lazy('user_registration_done') - - def get(self, request, *args, **kwargs): - if settings.LDAP_ENDPOINT or not settings.REGISTRATION_ENABLED: - return render(request, template_name='user/registration_disable.html') - return super().get(self, request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - if settings.LDAP_ENDPOINT or not settings.REGISTRATION_ENABLED: - return render(request, template_name='user/registration_disable.html') - form = self.form_class(request.POST) - self.object = None - if form.is_valid(): - user = form.save(commit=False) - if settings.EMAIL_HOST: - user.is_active = False - user.save() - send_activation_email(request, user) - messages.success(request, ( - 'Please Confirm your email to complete registration.')) - else: - user.is_active = True - user.save() - return self.form_valid(form) - else: - return self.form_invalid(form) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["h_captcha_key"] = settings.H_CAPTCHA_KEY - return context - - -class RegistrationDoneView(TemplateView): - template_name = 'user/registration_done.html' - title = _('Activate email sent') - - -class ActivateAccount(View): - - def get(self, request, uidb64, token, *args, **kwargs): - try: - uid = force_str(urlsafe_base64_decode(uidb64)) - user = User.objects.get(pk=uid) - except (TypeError, ValueError, OverflowError, User.DoesNotExist): - user = None - if user is not None and token_generator.check_token( - user, token): - user.is_active = True - user.save() - login(request, user, backend='django.contrib.auth.backends.ModelBackend') - messages.success(request, 'Your account have been confirmed.') - return redirect('/user/activate/done/') - else: - messages.warning(request, ( - 'The confirmation link was invalid, possibly because it has already been used.')) # noqa - return redirect('/user/activate/fail/') - - -class ActivateAccountDoneView(TemplateView): - template_name = 'user/account_activation_done.html' - title = _('Activate account done') - - -class ActivateAccountFailView(TemplateView): - template_name = 'user/account_activation_fail.html' - title = _('Activate account fail') - - -class UserLoginView(views.LoginView): - form_class = AuthenticationForm - extra_context = { - "registration_enabled": settings.REGISTRATION_ENABLED, - "password_reset_enabled": True if settings.EMAIL_HOST else False, - } - template_name = 'user/login.html' - - -class UserDetailView(NormalUserViewSet): - serializer_class = serializers.UserSerializer - required_scopes = ['openid'] - - def get_object(self): - return self.request.user - - def update(self, request, *args, **kwargs): - user_serializer = self.serializer_class( - data=request.data, - instance=request.user, - partial=True - ) - if user_serializer.is_valid(): - if settings.EMAIL_HOST: - user = self.get_object() - mail_subject = 'Update your account.' - uid = urlsafe_base64_encode(force_bytes(user.pk)) - token = token_generator.make_token(user) - message = render_to_string( - 'user/account_update_email.html', { - 'uid': uid, - 'user': user, - 'token': token, - 'domain': get_local_host(request) - }) - cache_key = "user:serializer:%s" % user.pk - cache.set(cache_key, request.data, 60 * 30) - user.email_user(mail_subject, message, fail_silently=True) - else: - user_serializer.save() - return Response(status=status.HTTP_204_NO_CONTENT) - - -class UpdateAccount(View): - - def get(self, request, uidb64, token, *args, **kwargs): - user = get_object_or_404(User, pk=force_str(urlsafe_base64_decode(uidb64))) - if user is not None and token_generator.check_token(user, token): - cache_key = "user:serializer:%s" % user.pk - data = cache.get(cache_key, None) - if data: - user_serializer = serializers.UserSerializer( - data=data, instance=user, partial=True) - if user_serializer.is_valid(): - user_serializer.save() - login(request, user, backend='django.contrib.auth.backends.ModelBackend') - cache.delete(cache_key) - return render(request, template_name='user/account_update_done.html') - return render(request, template_name='user/account_update_fail.html') - - -class UserAvatarViewSet(NormalUserViewSet): - - @method_decorator(cache_page(60 * 5)) - def avatar(self, request, *args, **kwargs): - user = User.objects.filter(username=kwargs["username"]).first() - size = request.GET.get("s", "80") - md5 = hashlib.md5() - if user: - md5.update(user.email.encode("utf8")) - return HttpResponseRedirect(settings.AVATAR_URL + md5.hexdigest() + "?s=" + size) - - -class UserEmailView(NormalUserViewSet): - serializer_class = serializers.UserEmailSerializer - required_scopes = ['openid'] - - def get_object(self): - return self.request.user - - -class LoginDoneView(TemplateView): - template_name = 'user/login_done.html' - - -class UserPasswordResetView(views.PasswordResetView): - email_template_name = 'user/password_reset_email.html' - success_url = reverse_lazy('user_password_reset_done') - template_name = 'user/password_reset_form.html' - - -class UserPasswordResetDoneView(views.PasswordResetDoneView): - template_name = 'user/password_reset_done.html' - - -class UserPasswordResetConfirmView(views.PasswordResetConfirmView): - success_url = reverse_lazy('user_password_reset_complete') - template_name = 'user/password_reset_confirm.html' - - -class UserPasswordResetCompleteView(views.PasswordResetCompleteView): - template_name = 'user/password_reset_complete.html' - - -class UserLogoutView(views.LogoutView): - template_name = 'user/logout.html' - - -class ListViewSet(ModelViewSet): - - def get_queryset(self, *args, **kwargs): - serializer = self.serializer_class(data=self.request.query_params) - serializer.is_valid(raise_exception=True) - - serializerlist = serializers.ListSerializer( - data=self.request.query_params) - serializerlist.is_valid(raise_exception=True) - q = Q(user=self.request.user) - if serializerlist.validated_data.get('section'): - q &= Q(created__range=serializerlist.validated_data.get('section')) - return self.model.objects.filter( - q, **serializer.validated_data).order_by(self.order_by)[0:100] - - -class UserTokensView(ListViewSet): - model = AccessToken - serializer_class = serializers.UserTokensSerializer - order_by = '-created' - - def destroy(self, request, *args, **kwargs): - token = get_object_or_404(self.model, - id=self.kwargs['pk'], - user=request.user) - - token.delete() - return Response(status=status.HTTP_204_NO_CONTENT) - - -class UserAccountPasswordView(ListViewSet): - - def update(self, request, *args, **kwargs): - if settings.LDAP_ENDPOINT: - raise DryccException( - "You cannot change user info when ldap is enabled.") - if not request.data.get('new_password'): - raise DryccException("new_password is a required field") - if not request.data.get('password'): - raise DryccException("password is a required field") - if len(request.data.get('new_password')) < 8: - raise DryccException("password must be 8 or more characters. ") - if not request.user.check_password(request.data['password']): - raise AuthenticationFailed('Current password does not match') - request.user.set_password(request.data['new_password']) - request.user.save() - auth.logout(request) - return HttpResponse(status=204) diff --git a/rootfs/api/views/__init__.py b/rootfs/api/views/__init__.py new file mode 100644 index 0000000..5d77f0a --- /dev/null +++ b/rootfs/api/views/__init__.py @@ -0,0 +1,2 @@ +from .api import * # noqa +from .web import * # noqa diff --git a/rootfs/api/views/api.py b/rootfs/api/views/api.py new file mode 100644 index 0000000..dd84dca --- /dev/null +++ b/rootfs/api/views/api.py @@ -0,0 +1,278 @@ +import hashlib + +from django.conf import settings +from django.core.cache import cache +from django.utils.decorators import method_decorator +from django.views.decorators.cache import cache_page +from django.contrib import auth +from django.contrib.auth import get_user_model +from django.db import IntegrityError +from django.db.models import Q +from django.shortcuts import get_object_or_404 +from django.template.loader import render_to_string +from django.http import HttpResponse, HttpResponseRedirect +from django.utils.encoding import force_bytes +from django.utils.http import urlsafe_base64_encode +from django.urls import reverse_lazy +from django.views.generic import View + +from rest_framework import status, viewsets +from rest_framework.exceptions import AuthenticationFailed, ValidationError +from rest_framework.permissions import AllowAny, IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework.viewsets import ModelViewSet + +from oauth2_provider.models import AccessToken +from social_django.models import UserSocialAuth + +from api import serializers +from api.exceptions import ServiceUnavailable, DryccException +from api.utils import get_local_host, get_user_socials, token_generator + + +User = get_user_model() + + +class NormalUserViewSet(viewsets.ModelViewSet): + permission_classes = [IsAuthenticated] + + +class ReadinessCheckView(View): + """Simple readiness check view to determine DB connection / query.""" + + def get(self, request): + try: + import django.db + with django.db.connection.cursor() as c: + c.execute("SELECT 0") + except django.db.Error as e: + raise ServiceUnavailable("Database health check failed") from e + + return HttpResponse("OK") + + head = get + + +class LivenessCheckView(View): + """Simple liveness check view to determine if the server is alive.""" + + def get(self, request): + return HttpResponse("OK") + + head = get + + +class IdentityProviderView(APIView): + permission_classes = (AllowAny, ) + + def get(self, request, *args, **kwargs): + from api.apps_extra.social_core import backends + + results = [] + for backend_cls in backends.__all__: + key_setting = f'SOCIAL_AUTH_{backend_cls.name.upper()}_KEY' + secret_setting = f'SOCIAL_AUTH_{backend_cls.name.upper()}_SECRET' + if getattr(settings, key_setting, None) and getattr(settings, secret_setting, None): + results.append({ + 'name': backend_cls.name, + 'icon': backend_cls.icon, + 'login_url': reverse_lazy('social:begin', args=(backend_cls.name,)), + }) + + return Response({'count': len(results), 'results': results}) + + +class UserIdentityView(APIView): + + def get(self, request, *args, **kwargs): + results = get_user_socials(request.user) + return Response({'count': len(results), 'results': results}) + + def delete(self, request, identity_id, *args, **kwargs): + identity = get_object_or_404(UserSocialAuth, id=identity_id, user=request.user) + identity.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + + +class OAuthPendingView(APIView): + permission_classes = (AllowAny, ) + + def get(self, request, *args, **kwargs): + pending = request.session.get('oauth_pending') + if not pending: + return Response( + {'detail': 'No pending OAuth request'}, status=status.HTTP_404_NOT_FOUND + ) + + from api.apps_extra.social_core import backends + + backend_map = {backend_cls.name: backend_cls for backend_cls in backends.__all__} + backend_cls = backend_map.get(pending.get('provider')) + return Response({ + 'provider': pending.get('provider'), + 'email': pending.get('email'), + 'icon': backend_cls.icon if backend_cls else '', + 'display_name': pending.get('provider', '').title(), + }) + + +class OAuthCreateUserView(APIView): + permission_classes = (AllowAny, ) + + def _create_oauth_user(self, request, username, password): + pending = request.session.get('oauth_pending') + if not pending: + raise ValidationError('No pending OAuth request') + + if not username: + raise ValidationError('username is a required field') + if not password: + raise ValidationError('password is a required field') + if len(password) < 8: + raise ValidationError('password must be 8 or more characters') + + email = pending.get('email') + if not email: + raise ValidationError('email is missing from oauth provider') + if User.objects.filter(email=email).exists(): + raise ValidationError('email is already registered') + + provider = pending.get('provider') + uid = pending.get('uid') + extra_data = pending.get('extra_data') or {} + + if not provider or not uid: + request.session.pop('oauth_pending', None) + raise ValidationError('invalid oauth pending data') + + existing = UserSocialAuth.objects.filter(provider=provider, uid=uid).first() + if existing: + request.session.pop('oauth_pending', None) + raise ValidationError('identity is already linked to another account') + + try: + user = User.objects.create_user(username=username, email=email, password=password) + except IntegrityError: + raise ValidationError('username is already taken') + + UserSocialAuth.objects.create( + user=user, + provider=provider, + uid=uid, + extra_data=extra_data, + ) + + auth.login(request, user, backend='django.contrib.auth.backends.ModelBackend') + request.session.pop('oauth_pending', None) + return user + + def post(self, request, *args, **kwargs): + username = request.data.get('username') + password = request.data.get('password') + self._create_oauth_user(request, username, password) + return Response({'status': 'created'}, status=status.HTTP_201_CREATED) + + +class UserDetailView(NormalUserViewSet): + serializer_class = serializers.UserSerializer + required_scopes = ['openid'] + email_template_name = 'user/account_update_email.html' + + def get_object(self): + return self.request.user + + def update(self, request, *args, **kwargs): + user_serializer = self.serializer_class( + data=request.data, + instance=request.user, + partial=True, + ) + if user_serializer.is_valid(): + if settings.EMAIL_HOST: + user = self.get_object() + mail_subject = 'Update your account.' + uid = urlsafe_base64_encode(force_bytes(user.pk)) + token = token_generator.make_token(user) + message = render_to_string( + self.email_template_name, + { + 'uid': uid, + 'user': user, + 'token': token, + 'domain': get_local_host(request), + }, + ) + cache_key = "user:serializer:%s" % user.pk + cache.set(cache_key, request.data, 60 * 30) + user.email_user(mail_subject, message, fail_silently=True) + else: + user_serializer.save() + return Response(status=status.HTTP_204_NO_CONTENT) + + +class UserAvatarViewSet(NormalUserViewSet): + + @method_decorator(cache_page(60 * 5)) + def avatar(self, request, *args, **kwargs): + user = User.objects.filter(username=kwargs["username"]).first() + size = request.GET.get("s", "80") + md5 = hashlib.md5() + if user: + md5.update(user.email.encode("utf8")) + return HttpResponseRedirect(settings.AVATAR_URL + md5.hexdigest() + "?s=" + size) + + +class UserEmailView(NormalUserViewSet): + serializer_class = serializers.UserEmailSerializer + required_scopes = ['openid'] + + def get_object(self): + return self.request.user + + +class ListViewSet(ModelViewSet): + + def get_queryset(self, *args, **kwargs): + serializer = self.serializer_class(data=self.request.query_params) + serializer.is_valid(raise_exception=True) + + serializerlist = serializers.ListSerializer(data=self.request.query_params) + serializerlist.is_valid(raise_exception=True) + q = Q(user=self.request.user) + if serializerlist.validated_data.get('section'): + q &= Q(created__range=serializerlist.validated_data.get('section')) + + return self.model.objects.filter( + q, **serializer.validated_data + ).order_by(self.order_by)[0:100] + + +class UserTokensView(ListViewSet): + model = AccessToken + serializer_class = serializers.UserTokensSerializer + order_by = '-created' + + def destroy(self, request, *args, **kwargs): + token = get_object_or_404(self.model, id=self.kwargs['pk'], user=request.user) + token.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + + +class UserAccountPasswordView(ListViewSet): + + def update(self, request, *args, **kwargs): + if settings.LDAP_ENDPOINT: + raise DryccException("You cannot change user info when ldap is enabled.") + if not request.data.get('new_password'): + raise DryccException("new_password is a required field") + if not request.data.get('password'): + raise DryccException("password is a required field") + if len(request.data.get('new_password')) < 8: + raise DryccException("password must be 8 or more characters. ") + if not request.user.check_password(request.data['password']): + raise AuthenticationFailed('Current password does not match') + request.user.set_password(request.data['new_password']) + request.user.save() + auth.logout(request) + return HttpResponse(status=204) diff --git a/rootfs/api/views/web.py b/rootfs/api/views/web.py new file mode 100644 index 0000000..952f29c --- /dev/null +++ b/rootfs/api/views/web.py @@ -0,0 +1,259 @@ +from django.conf import settings +from django.contrib import messages +from django.contrib.auth import get_user_model, login, views +from django.shortcuts import get_object_or_404, redirect, render +from django.utils.encoding import force_str +from django.utils.http import urlsafe_base64_decode +from django.views.generic import View +from django.views.generic.base import TemplateView +from django.views.generic.edit import CreateView +from django.urls import reverse_lazy +from django.utils.translation import gettext_lazy as _ + +from rest_framework.exceptions import ValidationError +from social_django.models import UserSocialAuth + +from api import serializers +from api.forms import AuthenticationForm, RegistrationForm +from api.utils import get_oauth_callback, send_activation_email, token_generator + + +User = get_user_model() + + +class RegistrationView(CreateView): + form_class = RegistrationForm + template_name = 'user/registration.html' + success_url = reverse_lazy('user_registration_done') + + def get(self, request, *args, **kwargs): + if settings.LDAP_ENDPOINT or not settings.REGISTRATION_ENABLED: + return render(request, template_name='user/registration_disable.html') + return super().get(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + if settings.LDAP_ENDPOINT or not settings.REGISTRATION_ENABLED: + return render(request, template_name='user/registration_disable.html') + form = self.form_class(request.POST) + self.object = None + if form.is_valid(): + user = form.save(commit=False) + if settings.EMAIL_HOST: + user.is_active = False + user.save() + send_activation_email(request, user) + messages.success(request, 'Please Confirm your email to complete registration.') + else: + user.is_active = True + user.save() + return self.form_valid(form) + return self.form_invalid(form) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["h_captcha_key"] = settings.H_CAPTCHA_KEY + return context + + +class RegistrationDoneView(TemplateView): + template_name = 'user/registration_done.html' + title = _('Activate email sent') + + +class ActivateAccount(View): + + def get(self, request, uidb64, token, *args, **kwargs): + try: + uid = force_str(urlsafe_base64_decode(uidb64)) + user = User.objects.get(pk=uid) + except (TypeError, ValueError, OverflowError, User.DoesNotExist): + user = None + if user is not None and token_generator.check_token(user, token): + user.is_active = True + user.save() + login(request, user, backend='django.contrib.auth.backends.ModelBackend') + messages.success(request, 'Your account have been confirmed.') + return redirect('/user/activate/done/') + + messages.warning( + request, + 'The confirmation link was invalid, possibly because it has already been used.', + ) + return redirect('/user/activate/fail/') + + +class ActivateAccountDoneView(TemplateView): + template_name = 'user/account_activation_done.html' + title = _('Activate account done') + + +class ActivateAccountFailView(TemplateView): + template_name = 'user/account_activation_fail.html' + title = _('Activate account fail') + + +class UserLoginView(views.LoginView): + form_class = AuthenticationForm + template_name = 'user/login.html' + + def _get_identity_linking(self): + identity_linking = self.request.POST.get('identity_linking') + if identity_linking is None: + identity_linking = self.request.GET.get('identity_linking') + return identity_linking == '1' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + identity_linking = self._get_identity_linking() + form = kwargs.get('form') + context.update({ + 'identity_linking': identity_linking, + 'registration_enabled': settings.REGISTRATION_ENABLED, + 'password_reset_enabled': True if settings.EMAIL_HOST else False, + 'identity_linking_error': ( + _('Identity linking login failed. Please try again.') + if identity_linking and form is not None and form.errors else None + ), + }) + return context + + def form_valid(self, form): + response = super().form_valid(form) + pending = self.request.session.get('oauth_pending') + if not pending: + return response + + provider = pending.get('provider') + uid = pending.get('uid') + extra_data = pending.get('extra_data') or {} + if not provider or not uid: + self.request.session.pop('oauth_pending', None) + raise ValidationError('invalid oauth pending data') + + existing = UserSocialAuth.objects.filter( + provider=provider, + uid=uid, + ).select_related('user').first() + if existing and existing.user_id != self.request.user.id: + self.request.session.pop('oauth_pending', None) + return redirect(get_oauth_callback(self.request, 'conflict', provider)) + + if not existing: + UserSocialAuth.objects.create( + user=self.request.user, + provider=provider, + uid=uid, + extra_data=extra_data, + ) + + self.request.session.pop('oauth_pending', None) + return redirect(get_oauth_callback(self.request, 'linked', provider)) + + +class OAuthCallbackTemplateView(TemplateView): + template_name = 'user/oauth_callback.html' + + def _build_context(self, request, status_value=None, error=None): + pending = request.session.get('oauth_pending') + provider = request.GET.get('provider') + email = None + display_name = None + + if pending: + provider = pending.get('provider') or provider + email = pending.get('email') + + if provider: + display_name = provider.title() + + status_value = status_value or request.GET.get('status') or 'error' + if status_value == 'pending' and not pending: + status_value = 'error' + error = error or 'No pending OAuth request' + + return { + 'status': status_value, + 'provider': provider, + 'display_name': display_name, + 'email': email, + 'error': error, + } + + def get(self, request, *args, **kwargs): + context = self._build_context(request) + return render(request, self.template_name, context) + + def post(self, request, *args, **kwargs): + username = request.POST.get('username') + password = request.POST.get('password') + confirm_password = request.POST.get('confirm_password') + + if password != confirm_password: + context = self._build_context( + request, + status_value='pending', + error='Password confirmation does not match', + ) + return render(request, self.template_name, context) + + from api.views.api import OAuthCreateUserView + + try: + OAuthCreateUserView()._create_oauth_user(request, username, password) + except ValidationError as exc: + error_text = exc.detail + if isinstance(error_text, (list, tuple)): + error_text = error_text[0] + context = self._build_context(request, status_value='pending', error=error_text) + return render(request, self.template_name, context) + + return redirect('/account-setting') + + +class UpdateAccount(View): + fail_template_name = 'user/account_update_fail.html' + success_template_name = 'user/account_update_done.html' + + def get(self, request, uidb64, token, *args, **kwargs): + user = get_object_or_404(User, pk=force_str(urlsafe_base64_decode(uidb64))) + if user is not None and token_generator.check_token(user, token): + cache_key = "user:serializer:%s" % user.pk + from django.core.cache import cache + data = cache.get(cache_key, None) + if data: + user_serializer = serializers.UserSerializer( + data=data, instance=user, partial=True + ) + if user_serializer.is_valid(): + user_serializer.save() + login(request, user, backend='django.contrib.auth.backends.ModelBackend') + cache.delete(cache_key) + return render(request, template_name=self.success_template_name) + return render(request, template_name=self.fail_template_name) + + +class LoginDoneView(TemplateView): + template_name = 'user/login_done.html' + + +class UserPasswordResetView(views.PasswordResetView): + email_template_name = 'user/password_reset_email.html' + success_url = reverse_lazy('user_password_reset_done') + template_name = 'user/password_reset_form.html' + + +class UserPasswordResetDoneView(views.PasswordResetDoneView): + template_name = 'user/password_reset_done.html' + + +class UserPasswordResetConfirmView(views.PasswordResetConfirmView): + success_url = reverse_lazy('user_password_reset_complete') + template_name = 'user/password_reset_confirm.html' + + +class UserPasswordResetCompleteView(views.PasswordResetCompleteView): + template_name = 'user/password_reset_complete.html' + + +class UserLogoutView(views.LogoutView): + template_name = 'user/logout.html' diff --git a/rootfs/api/viewset.py b/rootfs/api/viewset.py deleted file mode 100644 index 9ccba36..0000000 --- a/rootfs/api/viewset.py +++ /dev/null @@ -1,12 +0,0 @@ -from rest_framework import viewsets -from rest_framework.permissions import IsAuthenticated - - -class NormalUserViewSet(viewsets.ModelViewSet): - """ - A simple ViewSet for objects filtered by their 'owner' attribute. - - To use it, at minimum you'll need to provide the `serializer_class` attribute and - the `model` attribute shortcut. - """ - permission_classes = [IsAuthenticated] diff --git a/rootfs/bin/test-unit b/rootfs/bin/test-unit index b1f9263..de37e50 100755 --- a/rootfs/bin/test-unit +++ b/rootfs/bin/test-unit @@ -6,12 +6,19 @@ # fail hard and fast even on pipelines set -eou pipefail +function start_valkey() { + cd /tmp + nohup valkey-server > /var/log/valkey.log 2>&1 & + cd - +} + function creating_rsa_key() { mkdir -p /var/run/secrets/drycc/passport/ \ && openssl genrsa -out /var/run/secrets/drycc/passport/oidc-rsa-private-key 4096 } gosu postgres pg_ctl -D "$PGDATA" start && ln -s /tmp/.s.PGSQL.5432 /var/run/postgresql/.s.PGSQL.5432 +start_valkey creating_rsa_key python3 manage.py check coverage run manage.py test --settings=api.settings.testing --noinput api diff --git a/rootfs/passport/urls.py b/rootfs/passport/urls.py index 6740132..a3a0dbf 100644 --- a/rootfs/passport/urls.py +++ b/rootfs/passport/urls.py @@ -18,7 +18,6 @@ from django.contrib import admin from django.views.generic.base import TemplateView from api.views import LivenessCheckView, ReadinessCheckView -from . import views if settings.ADMIN_ENABLED: urlpatterns = [path('admin/', admin.site.urls)] @@ -28,9 +27,9 @@ urlpatterns += [ re_path(r'^healthz$', LivenessCheckView.as_view()), re_path(r'^readiness$', ReadinessCheckView.as_view()), - re_path(r"settings/?$", views.SettingsViewSet.as_view({'get': 'retrieve'})), - re_path(r"^user/", include('api.urls')), + re_path(r"^", include('api.urls')), re_path(r'^oauth/', include('oauth2_provider.urls', namespace='oauth2_provider')), re_path(r'^accounts/', include('django.contrib.auth.urls')), + re_path(r'^auth/', include('social_django.urls', namespace='social')), re_path(r'.*', TemplateView.as_view(template_name="index.html")), ] diff --git a/rootfs/requirements.txt b/rootfs/requirements.txt index a8d7f47..bfab3a3 100644 --- a/rootfs/requirements.txt +++ b/rootfs/requirements.txt @@ -1,17 +1,18 @@ # Drycc passport requirements -django==5.2.8 -pytz==2025.2 -django-auth-ldap==5.2.0 +django==5.2.12 +pytz==2026.1 +django-auth-ldap==5.3.0 django-cors-headers==4.9.0 -djangorestframework==3.16.1 -gunicorn==23.0.0 -uvicorn==0.37.0 -asgiref==3.10.0 -psycopg[binary]==3.2.10 +djangorestframework==3.17.0 +gunicorn==25.1.0 +uvicorn==0.42.0 +asgiref==3.11.1 +psycopg[binary]==3.3.3 requests==2.32.5 requests-toolbelt==1.0.0 -redis==6.4.0 -hiredis==3.2.1 -dj-database-url==3.0.1 -django-oauth-toolkit==3.1.0 -whitenoise==6.11.0 +redis==7.4.0 +hiredis==3.3.1 +dj-database-url==3.1.2 +django-oauth-toolkit==3.2.0 +social-auth-app-django==5.7.0 +whitenoise==6.12.0 diff --git a/rootfs/web/README.md b/rootfs/web/README.md new file mode 100644 index 0000000..3d51350 --- /dev/null +++ b/rootfs/web/README.md @@ -0,0 +1,83 @@ +# Passport Web Frontend + +This is the web frontend for the Passport authentication system, built with Vue.js and Vite. + +## Prerequisites + +Before running the web frontend, ensure you have the following installed: +- Node.js (v23 or higher) +- npm or yarn +- Python environment with Django backend + +## Setup Instructions + +### 1. Backend Setup + +First, ensure the Django backend is properly set up: + +```bash +# Install Django and dependencies +pip install -r requirements.txt + +# Set environment variables +export DRYCC_DATABASE_URL=postgres://postgres:@127.0.0.1:5432/passport +export VUE_APP_BASE_URL=http://localhost:8000/ +export CSRF_TRUSTED_ORIGINS=http://localhost:5173 + +# Start the Django development server +python manage.py runserver +``` + +### 2. Frontend Setup + +Navigate to the web directory and install dependencies: + +```bash +cd web +npm install +``` + +### 3. Development Server + +Start the development server: + +```bash +npm run dev -- --port 5173 +``` + +The application will be available at `http://localhost:5173`. + +## Available Scripts + +- `npm run dev` - Start the development server +- `npm run build` - Build the application for production +- `npm run preview` - Preview the production build +- `npm run lint` - Run ESLint + +## Environment Variables + +The following environment variables are required: + +- `VUE_APP_BASE_URL` - The base URL of the Django backend API +- `CSRF_TRUSTED_ORIGINS` - Trusted origins for CSRF protection + +## Project Structure + +``` +web/ +├── public/ # Static assets +├── src/ +│ ├── assets/ # Images and other assets +│ ├── components/ # Vue components +│ ├── views/ # Page components +│ ├── services/ # API service modules +│ ├── router/ # Vue Router configuration +│ ├── utils/ # Utility functions +│ └── lang/ # Internationalization +├── package.json # Project dependencies +└── vite.config.js # Vite configuration +``` + +## Contributing + +Please refer to the main project documentation for contribution guidelines. diff --git a/rootfs/web/index.html b/rootfs/web/index.html index 7c24d84..52ae093 100644 --- a/rootfs/web/index.html +++ b/rootfs/web/index.html @@ -2,15 +2,9 @@ - Drycc Passport -
    diff --git a/rootfs/web/package-lock.json b/rootfs/web/package-lock.json index c8ac336..c112d7a 100644 --- a/rootfs/web/package-lock.json +++ b/rootfs/web/package-lock.json @@ -1,7 +1,7 @@ { "name": "web", "version": "0.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -9,736 +9,1095 @@ "version": "0.0.0", "license": "Apache-2.0", "dependencies": { - "@icon-park/vue-next": "^1.3.6", - "axios": "^0.30.2", - "vant": "^3.4.5", - "vue": "^3.2.31", - "vue-i18n": "^9.1.9", - "vue-router": "^4.0.14", - "yarn": "^1.22.17" + "@element-plus/icons-vue": "^2.3.2", + "axios": "^1.13.6", + "element-plus": "^2.13.6", + "vant": "^4.9.22", + "vue": "^3.5.30", + "vue-i18n": "^11.3.0", + "vue-router": "^5.0.4", + "yarn": "^1.22.22" }, "devDependencies": { - "@vitejs/plugin-vue": "^2.2.4", - "@vue/compiler-sfc": "^3.2.31", - "vite": "^2.8.6" + "@vitejs/plugin-vue": "^6.0.5", + "@vue/compiler-sfc": "^3.5.30", + "vite": "^8.0.2" } }, - "node_modules/@babel/parser": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz", - "integrity": "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==", - "bin": { - "parser": "bin/babel-parser.js" + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, - "node_modules/@icon-park/vue-next": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@icon-park/vue-next/-/vue-next-1.3.6.tgz", - "integrity": "sha512-AZaCcjRPU9vTNVfcrG03CYJM+uv0SXx5lC4njanlRorFo+TV/x0ZTYGYGpTR/l6ek6QmFu9THmrgqKl7i/8yHg==", + "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==", + "license": "MIT", "engines": { - "node": ">= 8.0.0", - "npm": ">= 5.0.0" - }, - "peerDependencies": { - "vue": "3.x" + "node": ">=6.9.0" } }, - "node_modules/@intlify/core-base": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.9.tgz", - "integrity": "sha512-x5T0p/Ja0S8hs5xs+ImKyYckVkL4CzcEXykVYYV6rcbXxJTe2o58IquSqX9bdncVKbRZP7GlBU1EcRaQEEJ+vw==", - "dependencies": { - "@intlify/devtools-if": "9.1.9", - "@intlify/message-compiler": "9.1.9", - "@intlify/message-resolver": "9.1.9", - "@intlify/runtime": "9.1.9", - "@intlify/shared": "9.1.9", - "@intlify/vue-devtools": "9.1.9" - }, + "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==", + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=6.9.0" } }, - "node_modules/@intlify/devtools-if": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.9.tgz", - "integrity": "sha512-oKSMKjttG3Ut/1UGEZjSdghuP3fwA15zpDPcjkf/1FjlOIm6uIBGMNS5jXzsZy593u+P/YcnrZD6cD3IVFz9vQ==", + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "license": "MIT", "dependencies": { - "@intlify/shared": "9.1.9" + "@babel/types": "^7.29.0" }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@intlify/message-compiler": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.9.tgz", - "integrity": "sha512-6YgCMF46Xd0IH2hMRLCssZI3gFG4aywidoWQ3QP4RGYQXQYYfFC54DxhSgfIPpVoPLQ+4AD29eoYmhiHZ+qLFQ==", - "dependencies": { - "@intlify/message-resolver": "9.1.9", - "@intlify/shared": "9.1.9", - "source-map": "0.6.1" + "bin": { + "parser": "bin/babel-parser.js" }, "engines": { - "node": ">= 10" - } - }, - "node_modules/@intlify/message-resolver": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.9.tgz", - "integrity": "sha512-Lx/DBpigeK0sz2BBbzv5mu9/dAlt98HxwbG7xLawC3O2xMF9MNWU5FtOziwYG6TDIjNq0O/3ZbOJAxwITIWXEA==", - "engines": { - "node": ">= 10" + "node": ">=6.0.0" } }, - "node_modules/@intlify/runtime": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.9.tgz", - "integrity": "sha512-XgPw8+UlHCiie3fI41HPVa/VDJb3/aSH7bLhY1hJvlvNV713PFtb4p4Jo+rlE0gAoMsMCGcsiT982fImolSltg==", + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", "dependencies": { - "@intlify/message-compiler": "9.1.9", - "@intlify/message-resolver": "9.1.9", - "@intlify/shared": "9.1.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { - "node": ">= 10" - } - }, - "node_modules/@intlify/shared": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.9.tgz", - "integrity": "sha512-xKGM1d0EAxdDFCWedcYXOm6V5Pfw/TMudd6/qCdEb4tv0hk9EKeg7lwQF1azE0dP2phvx0yXxrt7UQK+IZjNdw==", - "engines": { - "node": ">= 10" + "node": ">=6.9.0" } }, - "node_modules/@intlify/vue-devtools": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.9.tgz", - "integrity": "sha512-YPehH9uL4vZcGXky4Ev5qQIITnHKIvsD2GKGXgqf+05osMUI6WSEQHaN9USRa318Rs8RyyPCiDfmA0hRu3k7og==", - "dependencies": { - "@intlify/message-resolver": "9.1.9", - "@intlify/runtime": "9.1.9", - "@intlify/shared": "9.1.9" - }, + "node_modules/@ctrl/tinycolor": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", + "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==", + "license": "MIT", "engines": { - "node": ">= 10" - } - }, - "node_modules/@popperjs/core": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz", - "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@vant/icons": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@vant/icons/-/icons-1.7.3.tgz", - "integrity": "sha512-tW4EqzxN4kXw1rnlnQJQHofEifPbt/gECOWiibomht8QLyvoGuE4iUmDFS288dJ07ZjuTy0bhdABj0SENo2fmQ==" - }, - "node_modules/@vant/popperjs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vant/popperjs/-/popperjs-1.1.0.tgz", - "integrity": "sha512-8MD1gz146awV/uPxYjz4pet22f7a9YVKqk7T+gFkWFwT9mEcrIUEg/xPrdOnWKLP9puXyYtm7oVfSDSefZ/p/w==", - "dependencies": { - "@popperjs/core": "^2.9.2" + "node": ">=14" } }, - "node_modules/@vant/use": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@vant/use/-/use-1.3.6.tgz", - "integrity": "sha512-3z+nywPaV2F5BdJO7RQxWlgfzJeEOmViD2yHMb7Tg+R4NR/7iQskqW8v2Cnv9FWSJgTOSHlcr7UzeLpiTAP4HA==" - }, - "node_modules/@vitejs/plugin-vue": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.2.4.tgz", - "integrity": "sha512-ev9AOlp0ljCaDkFZF3JwC/pD2N4Hh+r5srl5JHM6BKg5+99jiiK0rE/XaRs3pVm1wzyKkjUy/StBSoXX5fFzcw==", - "dev": true, - "engines": { - "node": ">=12.0.0" - }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", + "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==", + "license": "MIT", "peerDependencies": { - "vite": "^2.5.10", - "vue": "^3.2.25" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.31.tgz", - "integrity": "sha512-aKno00qoA4o+V/kR6i/pE+aP+esng5siNAVQ422TkBNM6qA4veXiZbSe8OTXHXquEi/f6Akc+nLfB4JGfe4/WQ==", - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.31", - "estree-walker": "^2.0.2", - "source-map": "^0.6.1" + "vue": "^3.2.0" } }, - "node_modules/@vue/compiler-dom": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.31.tgz", - "integrity": "sha512-60zIlFfzIDf3u91cqfqy9KhCKIJgPeqxgveH2L+87RcGU/alT6BRrk5JtUso0OibH3O7NXuNOQ0cDc9beT0wrg==", + "node_modules/@emnapi/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", + "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "@vue/compiler-core": "3.2.31", - "@vue/shared": "3.2.31" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.31.tgz", - "integrity": "sha512-748adc9msSPGzXgibHiO6T7RWgfnDcVQD+VVwYgSsyyY8Ans64tALHZANrKtOzvkwznV/F4H7OAod/jIlp/dkQ==", - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.31", - "@vue/compiler-dom": "3.2.31", - "@vue/compiler-ssr": "3.2.31", - "@vue/reactivity-transform": "3.2.31", - "@vue/shared": "3.2.31", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7", - "postcss": "^8.1.10", - "source-map": "^0.6.1" + "@emnapi/wasi-threads": "1.2.0", + "tslib": "^2.4.0" } }, - "node_modules/@vue/compiler-ssr": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.31.tgz", - "integrity": "sha512-mjN0rqig+A8TVDnsGPYJM5dpbjlXeHUm2oZHZwGyMYiGT/F4fhJf/cXy8QpjnLQK4Y9Et4GWzHn9PS8AHUnSkw==", + "node_modules/@emnapi/runtime": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", + "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "@vue/compiler-dom": "3.2.31", - "@vue/shared": "3.2.31" + "tslib": "^2.4.0" } }, - "node_modules/@vue/devtools-api": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.13.tgz", - "integrity": "sha512-T34EjcArVqzANedEZe2kXQ+AZsld2z1ptJlkOGm87+blk+s6udnP4ze/NYqV8lz1o9AIivimN0xxteLlWiWQdg==" - }, - "node_modules/@vue/reactivity": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.31.tgz", - "integrity": "sha512-HVr0l211gbhpEKYr2hYe7hRsV91uIVGFYNHj73njbARVGHQvIojkImKMaZNDdoDZOIkMsBc9a1sMqR+WZwfSCw==", + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "@vue/shared": "3.2.31" + "tslib": "^2.4.0" } }, - "node_modules/@vue/reactivity-transform": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.31.tgz", - "integrity": "sha512-uS4l4z/W7wXdI+Va5pgVxBJ345wyGFKvpPYtdSgvfJfX/x2Ymm6ophQlXXB6acqGHtXuBqNyyO3zVp9b1r0MOA==", + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.31", - "@vue/shared": "3.2.31", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7" + "@floating-ui/utils": "^0.2.11" } }, - "node_modules/@vue/runtime-core": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.31.tgz", - "integrity": "sha512-Kcog5XmSY7VHFEMuk4+Gap8gUssYMZ2+w+cmGI6OpZWYOEIcbE0TPzzPHi+8XTzAgx1w/ZxDFcXhZeXN5eKWsA==", + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", "dependencies": { - "@vue/reactivity": "3.2.31", - "@vue/shared": "3.2.31" + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" } }, - "node_modules/@vue/runtime-dom": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.31.tgz", - "integrity": "sha512-N+o0sICVLScUjfLG7u9u5XCjvmsexAiPt17GNnaWHJUfsKed5e85/A3SWgKxzlxx2SW/Hw7RQxzxbXez9PtY3g==", - "dependencies": { - "@vue/runtime-core": "3.2.31", - "@vue/shared": "3.2.31", - "csstype": "^2.6.8" - } + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" }, - "node_modules/@vue/server-renderer": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.31.tgz", - "integrity": "sha512-8CN3Zj2HyR2LQQBHZ61HexF5NReqngLT3oahyiVRfSSvak+oAvVmu8iNLSu6XR77Ili2AOpnAt1y8ywjjqtmkg==", + "node_modules/@intlify/core-base": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.3.0.tgz", + "integrity": "sha512-NNX5jIwF4TJBe7RtSKDMOA6JD9mp2mRcBHAwt2X+Q8PvnZub0yj5YYXlFu2AcESdgQpEv/5Yx2uOCV/yh7YkZg==", + "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.2.31", - "@vue/shared": "3.2.31" + "@intlify/devtools-types": "11.3.0", + "@intlify/message-compiler": "11.3.0", + "@intlify/shared": "11.3.0" }, - "peerDependencies": { - "vue": "3.2.31" - } - }, - "node_modules/@vue/shared": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.31.tgz", - "integrity": "sha512-ymN2pj6zEjiKJZbrf98UM2pfDd6F2H7ksKw7NDt/ZZ1fh5Ei39X5tABugtT03ZRlWd9imccoK0hE8hpjpU7irQ==" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/axios": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.30.2.tgz", - "integrity": "sha512-0pE4RQ4UQi1jKY6p7u6i1Tkzqmu+d+/tHS7Q7rKunWLB9WyilBTpHHpXzPNMDj5hTbK0B0PTLSz07yqMBiF6xg==", - "dependencies": { - "follow-redirects": "^1.15.4", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" } }, - "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==", + "node_modules/@intlify/devtools-types": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@intlify/devtools-types/-/devtools-types-11.3.0.tgz", + "integrity": "sha512-G9CNL4WpANWVdUjubOIIS7/D2j/0j+1KJmhBJxHilWNKr9mmt3IjFV3Hq4JoBP23uOoC5ynxz/FHZ42M+YxfGw==", + "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" + "@intlify/core-base": "11.3.0", + "@intlify/shared": "11.3.0" }, "engines": { - "node": ">= 0.4" + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" } }, - "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==", + "node_modules/@intlify/message-compiler": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.3.0.tgz", + "integrity": "sha512-RAJp3TMsqohg/Wa7bVF3cChRhecSYBLrTCQSj7j0UtWVFLP+6iEJoE2zb7GU5fp+fmG5kCbUdzhmlAUCWXiUJw==", + "license": "MIT", "dependencies": { - "delayed-stream": "~1.0.0" + "@intlify/shared": "11.3.0", + "source-map-js": "^1.0.2" }, "engines": { - "node": ">= 0.8" + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" } }, - "node_modules/csstype": { - "version": "2.6.20", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", - "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "node_modules/@intlify/shared": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.3.0.tgz", + "integrity": "sha512-LC6P/uay7rXL5zZ5+5iRJfLs/iUN8apu9tm8YqQVmW3Uq3X4A0dOFUIDuAmB7gAC29wTHOS3EiN/IosNSz0eNQ==", + "license": "MIT", "engines": { - "node": ">=0.4.0" + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" } }, - "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==", + "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==", + "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "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==", - "engines": { - "node": ">= 0.4" + "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==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "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==", + "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==", + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=6.0.0" } }, - "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==", + "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==", + "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==", + "license": "MIT", "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "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==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" }, - "engines": { - "node": ">= 0.4" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/esbuild": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.25.tgz", - "integrity": "sha512-4JHEIOMNFvK09ziiL+iVmldIhLbn49V4NAVo888tcGFKedEZY/Y8YapfStJ6zSE23tzYPKxqKwQBnQoIO0BI/Q==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "esbuild-android-64": "0.14.25", - "esbuild-android-arm64": "0.14.25", - "esbuild-darwin-64": "0.14.25", - "esbuild-darwin-arm64": "0.14.25", - "esbuild-freebsd-64": "0.14.25", - "esbuild-freebsd-arm64": "0.14.25", - "esbuild-linux-32": "0.14.25", - "esbuild-linux-64": "0.14.25", - "esbuild-linux-arm": "0.14.25", - "esbuild-linux-arm64": "0.14.25", - "esbuild-linux-mips64le": "0.14.25", - "esbuild-linux-ppc64le": "0.14.25", - "esbuild-linux-riscv64": "0.14.25", - "esbuild-linux-s390x": "0.14.25", - "esbuild-netbsd-64": "0.14.25", - "esbuild-openbsd-64": "0.14.25", - "esbuild-sunos-64": "0.14.25", - "esbuild-windows-32": "0.14.25", - "esbuild-windows-64": "0.14.25", - "esbuild-windows-arm64": "0.14.25" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.25.tgz", - "integrity": "sha512-L5vCUk7TzFbBnoESNoXjU3x9+/+7TDIE/1mTfy/erAfvZAqC+S3sp/Qa9wkypFMcFvN9FzvESkTlpeQDolREtQ==", - "cpu": [ - "x64" - ], + "node_modules/@oxc-project/types": { + "version": "0.122.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz", + "integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==", "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.8.tgz", + "integrity": "sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" } }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.25.tgz", - "integrity": "sha512-4jv5xPjM/qNm27T5j3ZEck0PvjgQtoMHnz4FzwF5zNP56PvY2CT0WStcAIl6jNlsuDdN63rk2HRBIsO6xFbcFw==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.11.tgz", + "integrity": "sha512-SJ+/g+xNnOh6NqYxD0V3uVN4W3VfnrGsC9/hoglicgTNfABFG9JjISvkkU0dNY84MNHLWyOgxP9v9Y9pX4S7+A==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-darwin-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.25.tgz", - "integrity": "sha512-TGp8tuudIxOyWd1+8aYPxQmC1ZQyvij/AfNBa35RubixD0zJ1vkKHVAzo0Zao1zcG6pNqiSyzfPto8vmg0s7oA==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.11.tgz", + "integrity": "sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==", "cpu": [ - "x64" + "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.25.tgz", - "integrity": "sha512-oTcDgdm0MDVEmw2DWu8BV68pYuImpFgvWREPErBZmNA4MYKGuBRaCiJqq6jZmBR1x+3y1DWCjez+5uLtuAm6mw==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.11.tgz", + "integrity": "sha512-39Ks6UvIHq4rEogIfQBoBRusj0Q0nPVWIvqmwBLaT6aqQGIakHdESBVOPRRLacy4WwUPIx4ZKzfZ9PMW+IeyUQ==", "cpu": [ - "arm64" + "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.25.tgz", - "integrity": "sha512-ueAqbnMZ8arnuLH8tHwTCQYeptnHOUV7vA6px6j4zjjQwDx7TdP7kACPf3TLZLdJQ3CAD1XCvQ2sPhX+8tacvQ==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.11.tgz", + "integrity": "sha512-jfsm0ZHfhiqrvWjJAmzsqiIFPz5e7mAoCOPBNTcNgkiid/LaFKiq92+0ojH+nmJmKYkre4t71BWXUZDNp7vsag==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.25.tgz", - "integrity": "sha512-+ZVWud2HKh+Ob6k/qiJWjBtUg4KmJGGmbvEXXW1SNKS7hW7HU+Zq2ZCcE1akFxOPkVB+EhOty/sSek30tkCYug==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.11.tgz", + "integrity": "sha512-zjQaUtSyq1nVe3nxmlSCuR96T1LPlpvmJ0SZy0WJFEsV4kFbXcq2u68L4E6O0XeFj4aex9bEauqjW8UQBeAvfQ==", "cpu": [ - "arm64" + "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "freebsd" + "linux" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-linux-32": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.25.tgz", - "integrity": "sha512-3OP/lwV3kCzEz45tobH9nj+uE4ubhGsfx+tn0L26WAGtUbmmcRpqy7XRG/qK7h1mClZ+eguIANcQntYMdYklfw==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==", "cpu": [ - "ia32" + "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-linux-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.25.tgz", - "integrity": "sha512-+aKHdHZmX9qwVlQmu5xYXh7GsBFf4TWrePgeJTalhXHOG7NNuUwoHmketGiZEoNsWyyqwH9rE5BC+iwcLY30Ug==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.11.tgz", + "integrity": "sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==", "cpu": [ - "x64" + "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.25.tgz", - "integrity": "sha512-aTLcE2VBoLydL943REcAcgnDi3bHtmULSXWLbjtBdtykRatJVSxKMjK9YlBXUZC4/YcNQfH7AxwVeQr9fNxPhw==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-ZlFgw46NOAGMgcdvdYwAGu2Q+SLFA9LzbJLW+iyMOJyhj5wk6P3KEE9Gct4xWwSzFoPI7JCdYmYMzVtlgQ+zfw==", "cpu": [ - "arm" + "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.25.tgz", - "integrity": "sha512-UxfenPx/wSZx55gScCImPtXekvZQLI2GW3qe5dtlmU7luiqhp5GWPzGeQEbD3yN3xg/pHc671m5bma5Ns7lBHw==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-hIOYmuT6ofM4K04XAZd3OzMySEO4K0/nc9+jmNcxNAxRi6c5UWpqfw3KMFV4MVFWL+jQsSh+bGw2VqmaPMTLyw==", "cpu": [ - "arm64" + "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.25.tgz", - "integrity": "sha512-wLWYyqVfYx9Ur6eU5RT92yJVsaBGi5RdkoWqRHOqcJ38Kn60QMlcghsKeWfe9jcYut8LangYZ98xO1LxIoSXrQ==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.11.tgz", + "integrity": "sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==", "cpu": [ - "mips64el" + "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.25.tgz", - "integrity": "sha512-0dR6Csl6Zas3g4p9ULckEl8Mo8IInJh33VCJ3eaV1hj9+MHGdmDOakYMN8MZP9/5nl+NU/0ygpd14cWgy8uqRw==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.11.tgz", + "integrity": "sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==", "cpu": [ - "ppc64" + "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.25.tgz", - "integrity": "sha512-J4d20HDmTrgvhR0bdkDhvvJGaikH3LzXQnNaseo8rcw9Yqby9A90gKUmWpfwqLVNRILvNnAmKLfBjCKU9ajg8w==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.11.tgz", + "integrity": "sha512-mcp3Rio2w72IvdZG0oQ4bM2c2oumtwHfUfKncUM6zGgz0KgPz4YmDPQfnXEiY5t3+KD/i8HG2rOB/LxdmieK2g==", "cpu": [ - "riscv64" + "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "openharmony" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-linux-s390x": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.25.tgz", - "integrity": "sha512-YI2d5V6nTE73ZnhEKQD7MtsPs1EtUZJ3obS21oxQxGbbRw1G+PtJKjNyur+3t6nzHP9oTg6GHQ3S3hOLLmbDIQ==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.11.tgz", + "integrity": "sha512-LXk5Hii1Ph9asuGRjBuz8TUxdc1lWzB7nyfdoRgI0WGPZKmCxvlKk8KfYysqtr4MfGElu/f/pEQRh8fcEgkrWw==", "cpu": [ - "s390x" + "wasm32" ], "dev": true, + "license": "MIT", "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, "engines": { - "node": ">=12" + "node": ">=14.0.0" } }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.25.tgz", - "integrity": "sha512-TKIVgNWLUOkr+Exrye70XTEE1lJjdQXdM4tAXRzfHE9iBA7LXWcNtVIuSnphTqpanPzTDFarF0yqq4kpbC6miA==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.11.tgz", + "integrity": "sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==", "cpu": [ - "x64" + "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "netbsd" + "win32" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.25.tgz", - "integrity": "sha512-QgFJ37A15D7NIXBTYEqz29+uw3nNBOIyog+3kFidANn6kjw0GHZ0lEYQn+cwjyzu94WobR+fes7cTl/ZYlHb1A==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.11.tgz", + "integrity": "sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "openbsd" + "win32" ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.25.tgz", - "integrity": "sha512-rmWfjUItYIVlqr5EnTH1+GCxXiBOC42WBZ3w++qh7n2cS9Xo0lO5pGSG2N+huOU2fX5L+6YUuJ78/vOYvefeFw==", - "cpu": [ - "x64" - ], + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", + "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } + "license": "MIT" }, - "node_modules/esbuild-windows-32": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.25.tgz", - "integrity": "sha512-HGAxVUofl3iUIz9W10Y9XKtD0bNsK9fBXv1D55N/ljNvkrAYcGB8YCm0v7DjlwtyS6ws3dkdQyXadbxkbzaKOA==", - "cpu": [ - "ia32" - ], + "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, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/esbuild-windows-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.25.tgz", - "integrity": "sha512-TirEohRkfWU9hXLgoDxzhMQD1g8I2mOqvdQF2RS9E/wbkORTAqJHyh7wqGRCQAwNzdNXdg3JAyhQ9/177AadWA==", - "cpu": [ - "x64" - ], + "node_modules/@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "license": "MIT" + }, + "node_modules/@vant/popperjs": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@vant/popperjs/-/popperjs-1.3.0.tgz", + "integrity": "sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==", + "license": "MIT" + }, + "node_modules/@vant/use": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vant/use/-/use-1.6.0.tgz", + "integrity": "sha512-PHHxeAASgiOpSmMjceweIrv2AxDZIkWXyaczksMoWvKV2YAYEhoizRuk/xFnKF+emUIi46TsQ+rvlm/t2BBCfA==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.5.tgz", + "integrity": "sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.2" + }, "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "vue": "^3.2.25" } }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.25.tgz", - "integrity": "sha512-4ype9ERiI45rSh+R8qUoBtaj6kJvUOI7oVLhKqPEpcF4Pa5PpT3hm/mXAyotJHREkHpM87PAJcA442mLnbtlNA==", - "cpu": [ - "arm64" - ], + "node_modules/@vue-macros/common": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.2.tgz", + "integrity": "sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==", + "license": "MIT", + "dependencies": { + "@vue/compiler-sfc": "^3.5.22", + "ast-kit": "^2.1.2", + "local-pkg": "^1.1.2", + "magic-string-ast": "^1.0.2", + "unplugin-utils": "^0.3.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/vue-macros" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.2.25" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", + "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/shared": "3.5.30", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", + "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", + "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/compiler-core": "3.5.30", + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.8", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", + "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/devtools-kit": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.1.tgz", + "integrity": "sha512-gVBaBv++i+adg4JpH71k9ppl4soyR7Y2McEqO5YNgv0BI1kMZ7BDX5gnwkZ5COYgiCyhejZG+yGNrBAjj6Coqg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^8.1.1", + "birpc": "^2.6.1", + "hookable": "^5.5.3", + "perfect-debounce": "^2.0.0" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.1.tgz", + "integrity": "sha512-+h4ttmJYl/txpxHKaoZcaKpC+pvckgLzIDiSQlaQ7kKthKh8KuwoLW2D8hPJEnqKzXOvu15UHEoGyngAXCz0EQ==", + "license": "MIT" + }, + "node_modules/@vue/reactivity": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", + "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", + "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", + "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.30", + "@vue/runtime-core": "3.5.30", + "@vue/shared": "3.5.30", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", + "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30" + }, + "peerDependencies": { + "vue": "3.5.30" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", + "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.0.0.tgz", + "integrity": "sha512-C12RukhXiJCbx4MGhjmd/gH52TjJsc3G0E0kQj/kb19H3Nt6n1CA4DRWuTdWWcaFRdlTe0npWDS942mvacvNBw==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "12.0.0", + "@vueuse/shared": "12.0.0", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.0.0.tgz", + "integrity": "sha512-Yzimd1D3sjxTDOlF05HekU5aSGdKjxhuhRFHA7gDWLn57PRbBIh+SF5NmjhJ0WRgF3my7T8LBucyxdFJjIfRJQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.0.0.tgz", + "integrity": "sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==", + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ast-kit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", + "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/ast-walker-scope": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.3.tgz", + "integrity": "sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.4", + "ast-kit": "^2.1.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "license": "MIT" + }, + "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.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "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/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.20", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz", + "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==", + "license": "MIT" + }, + "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/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": ">=8" + } + }, + "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/element-plus": { + "version": "2.13.6", + "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.13.6.tgz", + "integrity": "sha512-XHgwXr8Fjz6i+6BaqFhAbae/dJbG7bBAAlHrY3pWL7dpj+JcqcOyKYt4Oy5KP86FQwS1k4uIZDjCx2FyUR5lDg==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^4.2.0", + "@element-plus/icons-vue": "^2.3.2", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.17.20", + "@types/lodash-es": "^4.17.12", + "@vueuse/core": "12.0.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.19", + "lodash": "^4.17.23", + "lodash-es": "^4.17.23", + "lodash-unified": "^1.0.3", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0", + "vue-component-type-helpers": "^3.2.4" + }, + "peerDependencies": { + "vue": "^3.3.0" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "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/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } }, "node_modules/follow-redirects": { "version": "1.15.11", @@ -750,6 +1109,7 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -760,9 +1120,10 @@ } }, "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "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", @@ -775,11 +1136,12 @@ } }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -792,6 +1154,7 @@ "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" } @@ -800,6 +1163,7 @@ "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", @@ -823,6 +1187,7 @@ "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" @@ -835,6 +1200,7 @@ "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" }, @@ -842,22 +1208,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "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" }, @@ -869,6 +1224,7 @@ "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" }, @@ -883,6 +1239,7 @@ "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" }, @@ -890,985 +1247,904 @@ "node": ">= 0.4" } }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, - "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==", - "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==", - "engines": { - "node": ">= 0.6" - } + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">= 0.6" + "node": ">=6" } }, - "node_modules/nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", "bin": { - "nanoid": "bin/nanoid.cjs" + "json5": "lib/cli.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=6" } }, - "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 - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/postcss": { - "version": "8.4.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.8.tgz", - "integrity": "sha512-2tXEqGxrjvAO6U+CJzDL2Fk2kPHTv1jQsYkSoMeOis2SsYaXRO2COxTdQp99cYvif9JTXaAk9lYGc3VhJt7JPQ==", + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", "dependencies": { - "nanoid": "^3.3.1", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "detect-libc": "^2.0.3" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://opencollective.com/parcel" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/rollup": { - "version": "2.63.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.63.0.tgz", - "integrity": "sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ==", + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=10.0.0" + "node": ">= 12.0.0" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=0.10.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.10.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - }, - "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==", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vant": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/vant/-/vant-3.4.5.tgz", - "integrity": "sha512-3an2v6ejW9pijKmaDbSCW7Hs1R45tqtTIcedfI8hEAA5zC2Bp8cXU6Z4gUCK6/RAGOJsB+vcyLINLb1cGS/SzQ==", - "dependencies": { - "@vant/icons": "^1.7.1", - "@vant/popperjs": "^1.1.0", - "@vant/use": "^1.3.5" + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, - "peerDependencies": { - "vue": "^3.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vite": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-2.8.6.tgz", - "integrity": "sha512-e4H0QpludOVKkmOsRyqQ7LTcMUDF3mcgyNU4lmi0B5JUbe0ZxeBBl8VoZ8Y6Rfn9eFKYtdXNPcYK97ZwH+K2ug==", + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "esbuild": "^0.14.14", - "postcss": "^8.4.6", - "resolve": "^1.22.0", - "rollup": "^2.59.0" - }, - "bin": { - "vite": "bin/vite.js" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12.2.0" + "node": ">= 12.0.0" }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "less": "*", - "sass": "*", - "stylus": "*" - }, - "peerDependenciesMeta": { - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vue": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.31.tgz", - "integrity": "sha512-odT3W2tcffTiQCy57nOT93INw1auq5lYLLYtWpPYQQYQOOdHiqFct9Xhna6GJ+pJQaF67yZABraH47oywkJgFw==", - "dependencies": { - "@vue/compiler-dom": "3.2.31", - "@vue/compiler-sfc": "3.2.31", - "@vue/runtime-dom": "3.2.31", - "@vue/server-renderer": "3.2.31", - "@vue/shared": "3.2.31" + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "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/vue-i18n": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.9.tgz", - "integrity": "sha512-JeRdNVxS2OGp1E+pye5XB6+M6BBkHwAv9C80Q7+kzoMdUDGRna06tjC0vCB/jDX9aWrl5swxOMFcyAr7or8XTA==", - "dependencies": { - "@intlify/core-base": "9.1.9", - "@intlify/shared": "9.1.9", - "@intlify/vue-devtools": "9.1.9", - "@vue/devtools-api": "^6.0.0-beta.7" - }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 10" + "node": ">= 12.0.0" }, - "peerDependencies": { - "vue": "^3.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/vue-router": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.14.tgz", - "integrity": "sha512-wAO6zF9zxA3u+7AkMPqw9LjoUCjSxfFvINQj3E/DceTt6uEz1XZLraDhdg2EYmvVwTBSGlLYsUw8bDmx0754Mw==", - "dependencies": { - "@vue/devtools-api": "^6.0.0" + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/posva" - }, - "peerDependencies": { - "vue": "^3.2.0" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/yarn": { - "version": "1.22.17", - "resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.17.tgz", - "integrity": "sha512-H0p241BXaH0UN9IeH//RT82tl5PfNraVpSpEoW+ET7lmopNC61eZ+A+IDvU8FM6Go5vx162SncDL8J1ZjRBriQ==", - "hasInstallScript": true, - "bin": { - "yarn": "bin/yarn.js", - "yarnpkg": "bin/yarn.js" + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" }, "engines": { - "node": ">=4.0.0" - } - } - }, - "dependencies": { - "@babel/parser": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz", - "integrity": "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==" - }, - "@icon-park/vue-next": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@icon-park/vue-next/-/vue-next-1.3.6.tgz", - "integrity": "sha512-AZaCcjRPU9vTNVfcrG03CYJM+uv0SXx5lC4njanlRorFo+TV/x0ZTYGYGpTR/l6ek6QmFu9THmrgqKl7i/8yHg==", - "requires": {} - }, - "@intlify/core-base": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.9.tgz", - "integrity": "sha512-x5T0p/Ja0S8hs5xs+ImKyYckVkL4CzcEXykVYYV6rcbXxJTe2o58IquSqX9bdncVKbRZP7GlBU1EcRaQEEJ+vw==", - "requires": { - "@intlify/devtools-if": "9.1.9", - "@intlify/message-compiler": "9.1.9", - "@intlify/message-resolver": "9.1.9", - "@intlify/runtime": "9.1.9", - "@intlify/shared": "9.1.9", - "@intlify/vue-devtools": "9.1.9" - } - }, - "@intlify/devtools-if": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.9.tgz", - "integrity": "sha512-oKSMKjttG3Ut/1UGEZjSdghuP3fwA15zpDPcjkf/1FjlOIm6uIBGMNS5jXzsZy593u+P/YcnrZD6cD3IVFz9vQ==", - "requires": { - "@intlify/shared": "9.1.9" - } - }, - "@intlify/message-compiler": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.9.tgz", - "integrity": "sha512-6YgCMF46Xd0IH2hMRLCssZI3gFG4aywidoWQ3QP4RGYQXQYYfFC54DxhSgfIPpVoPLQ+4AD29eoYmhiHZ+qLFQ==", - "requires": { - "@intlify/message-resolver": "9.1.9", - "@intlify/shared": "9.1.9", - "source-map": "0.6.1" - } - }, - "@intlify/message-resolver": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.9.tgz", - "integrity": "sha512-Lx/DBpigeK0sz2BBbzv5mu9/dAlt98HxwbG7xLawC3O2xMF9MNWU5FtOziwYG6TDIjNq0O/3ZbOJAxwITIWXEA==" - }, - "@intlify/runtime": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.9.tgz", - "integrity": "sha512-XgPw8+UlHCiie3fI41HPVa/VDJb3/aSH7bLhY1hJvlvNV713PFtb4p4Jo+rlE0gAoMsMCGcsiT982fImolSltg==", - "requires": { - "@intlify/message-compiler": "9.1.9", - "@intlify/message-resolver": "9.1.9", - "@intlify/shared": "9.1.9" - } - }, - "@intlify/shared": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.9.tgz", - "integrity": "sha512-xKGM1d0EAxdDFCWedcYXOm6V5Pfw/TMudd6/qCdEb4tv0hk9EKeg7lwQF1azE0dP2phvx0yXxrt7UQK+IZjNdw==" - }, - "@intlify/vue-devtools": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.9.tgz", - "integrity": "sha512-YPehH9uL4vZcGXky4Ev5qQIITnHKIvsD2GKGXgqf+05osMUI6WSEQHaN9USRa318Rs8RyyPCiDfmA0hRu3k7og==", - "requires": { - "@intlify/message-resolver": "9.1.9", - "@intlify/runtime": "9.1.9", - "@intlify/shared": "9.1.9" - } - }, - "@popperjs/core": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz", - "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==" - }, - "@vant/icons": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@vant/icons/-/icons-1.7.3.tgz", - "integrity": "sha512-tW4EqzxN4kXw1rnlnQJQHofEifPbt/gECOWiibomht8QLyvoGuE4iUmDFS288dJ07ZjuTy0bhdABj0SENo2fmQ==" - }, - "@vant/popperjs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vant/popperjs/-/popperjs-1.1.0.tgz", - "integrity": "sha512-8MD1gz146awV/uPxYjz4pet22f7a9YVKqk7T+gFkWFwT9mEcrIUEg/xPrdOnWKLP9puXyYtm7oVfSDSefZ/p/w==", - "requires": { - "@popperjs/core": "^2.9.2" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "@vant/use": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@vant/use/-/use-1.3.6.tgz", - "integrity": "sha512-3z+nywPaV2F5BdJO7RQxWlgfzJeEOmViD2yHMb7Tg+R4NR/7iQskqW8v2Cnv9FWSJgTOSHlcr7UzeLpiTAP4HA==" + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" }, - "@vitejs/plugin-vue": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.2.4.tgz", - "integrity": "sha512-ev9AOlp0ljCaDkFZF3JwC/pD2N4Hh+r5srl5JHM6BKg5+99jiiK0rE/XaRs3pVm1wzyKkjUy/StBSoXX5fFzcw==", - "dev": true, - "requires": {} - }, - "@vue/compiler-core": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.31.tgz", - "integrity": "sha512-aKno00qoA4o+V/kR6i/pE+aP+esng5siNAVQ422TkBNM6qA4veXiZbSe8OTXHXquEi/f6Akc+nLfB4JGfe4/WQ==", - "requires": { - "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.31", - "estree-walker": "^2.0.2", - "source-map": "^0.6.1" - } - }, - "@vue/compiler-dom": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.31.tgz", - "integrity": "sha512-60zIlFfzIDf3u91cqfqy9KhCKIJgPeqxgveH2L+87RcGU/alT6BRrk5JtUso0OibH3O7NXuNOQ0cDc9beT0wrg==", - "requires": { - "@vue/compiler-core": "3.2.31", - "@vue/shared": "3.2.31" - } - }, - "@vue/compiler-sfc": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.31.tgz", - "integrity": "sha512-748adc9msSPGzXgibHiO6T7RWgfnDcVQD+VVwYgSsyyY8Ans64tALHZANrKtOzvkwznV/F4H7OAod/jIlp/dkQ==", - "requires": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.31", - "@vue/compiler-dom": "3.2.31", - "@vue/compiler-ssr": "3.2.31", - "@vue/reactivity-transform": "3.2.31", - "@vue/shared": "3.2.31", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7", - "postcss": "^8.1.10", - "source-map": "^0.6.1" - } - }, - "@vue/compiler-ssr": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.31.tgz", - "integrity": "sha512-mjN0rqig+A8TVDnsGPYJM5dpbjlXeHUm2oZHZwGyMYiGT/F4fhJf/cXy8QpjnLQK4Y9Et4GWzHn9PS8AHUnSkw==", - "requires": { - "@vue/compiler-dom": "3.2.31", - "@vue/shared": "3.2.31" - } - }, - "@vue/devtools-api": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.13.tgz", - "integrity": "sha512-T34EjcArVqzANedEZe2kXQ+AZsld2z1ptJlkOGm87+blk+s6udnP4ze/NYqV8lz1o9AIivimN0xxteLlWiWQdg==" - }, - "@vue/reactivity": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.31.tgz", - "integrity": "sha512-HVr0l211gbhpEKYr2hYe7hRsV91uIVGFYNHj73njbARVGHQvIojkImKMaZNDdoDZOIkMsBc9a1sMqR+WZwfSCw==", - "requires": { - "@vue/shared": "3.2.31" - } - }, - "@vue/reactivity-transform": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.31.tgz", - "integrity": "sha512-uS4l4z/W7wXdI+Va5pgVxBJ345wyGFKvpPYtdSgvfJfX/x2Ymm6ophQlXXB6acqGHtXuBqNyyO3zVp9b1r0MOA==", - "requires": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.31", - "@vue/shared": "3.2.31", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7" + "node_modules/lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "license": "MIT" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "license": "MIT", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" } }, - "@vue/runtime-core": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.31.tgz", - "integrity": "sha512-Kcog5XmSY7VHFEMuk4+Gap8gUssYMZ2+w+cmGI6OpZWYOEIcbE0TPzzPHi+8XTzAgx1w/ZxDFcXhZeXN5eKWsA==", - "requires": { - "@vue/reactivity": "3.2.31", - "@vue/shared": "3.2.31" + "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==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "@vue/runtime-dom": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.31.tgz", - "integrity": "sha512-N+o0sICVLScUjfLG7u9u5XCjvmsexAiPt17GNnaWHJUfsKed5e85/A3SWgKxzlxx2SW/Hw7RQxzxbXez9PtY3g==", - "requires": { - "@vue/runtime-core": "3.2.31", - "@vue/shared": "3.2.31", - "csstype": "^2.6.8" + "node_modules/magic-string-ast": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.3.tgz", + "integrity": "sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==", + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.19" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" } }, - "@vue/server-renderer": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.31.tgz", - "integrity": "sha512-8CN3Zj2HyR2LQQBHZ61HexF5NReqngLT3oahyiVRfSSvak+oAvVmu8iNLSu6XR77Ili2AOpnAt1y8ywjjqtmkg==", - "requires": { - "@vue/compiler-ssr": "3.2.31", - "@vue/shared": "3.2.31" + "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" } }, - "@vue/shared": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.31.tgz", - "integrity": "sha512-ymN2pj6zEjiKJZbrf98UM2pfDd6F2H7ksKw7NDt/ZZ1fh5Ei39X5tABugtT03ZRlWd9imccoK0hE8hpjpU7irQ==" + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "axios": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.30.2.tgz", - "integrity": "sha512-0pE4RQ4UQi1jKY6p7u6i1Tkzqmu+d+/tHS7Q7rKunWLB9WyilBTpHHpXzPNMDj5hTbK0B0PTLSz07yqMBiF6xg==", - "requires": { - "follow-redirects": "^1.15.4", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "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" } }, - "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==", - "requires": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" + "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" } }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" } }, - "csstype": { - "version": "2.6.20", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", - "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "license": "MIT" }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - }, - "dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "requires": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "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" } }, - "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==" - }, - "es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", + "license": "BSD-3-Clause" }, - "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==", - "requires": { - "es-errors": "^1.3.0" - } + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" }, - "es-set-tostringtag": { + "node_modules/perfect-debounce": { "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==", - "requires": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - } - }, - "esbuild": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.25.tgz", - "integrity": "sha512-4JHEIOMNFvK09ziiL+iVmldIhLbn49V4NAVo888tcGFKedEZY/Y8YapfStJ6zSE23tzYPKxqKwQBnQoIO0BI/Q==", - "dev": true, - "requires": { - "esbuild-android-64": "0.14.25", - "esbuild-android-arm64": "0.14.25", - "esbuild-darwin-64": "0.14.25", - "esbuild-darwin-arm64": "0.14.25", - "esbuild-freebsd-64": "0.14.25", - "esbuild-freebsd-arm64": "0.14.25", - "esbuild-linux-32": "0.14.25", - "esbuild-linux-64": "0.14.25", - "esbuild-linux-arm": "0.14.25", - "esbuild-linux-arm64": "0.14.25", - "esbuild-linux-mips64le": "0.14.25", - "esbuild-linux-ppc64le": "0.14.25", - "esbuild-linux-riscv64": "0.14.25", - "esbuild-linux-s390x": "0.14.25", - "esbuild-netbsd-64": "0.14.25", - "esbuild-openbsd-64": "0.14.25", - "esbuild-sunos-64": "0.14.25", - "esbuild-windows-32": "0.14.25", - "esbuild-windows-64": "0.14.25", - "esbuild-windows-arm64": "0.14.25" - } - }, - "esbuild-android-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.25.tgz", - "integrity": "sha512-L5vCUk7TzFbBnoESNoXjU3x9+/+7TDIE/1mTfy/erAfvZAqC+S3sp/Qa9wkypFMcFvN9FzvESkTlpeQDolREtQ==", - "dev": true, - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.25.tgz", - "integrity": "sha512-4jv5xPjM/qNm27T5j3ZEck0PvjgQtoMHnz4FzwF5zNP56PvY2CT0WStcAIl6jNlsuDdN63rk2HRBIsO6xFbcFw==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.25.tgz", - "integrity": "sha512-TGp8tuudIxOyWd1+8aYPxQmC1ZQyvij/AfNBa35RubixD0zJ1vkKHVAzo0Zao1zcG6pNqiSyzfPto8vmg0s7oA==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.25.tgz", - "integrity": "sha512-oTcDgdm0MDVEmw2DWu8BV68pYuImpFgvWREPErBZmNA4MYKGuBRaCiJqq6jZmBR1x+3y1DWCjez+5uLtuAm6mw==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.25.tgz", - "integrity": "sha512-ueAqbnMZ8arnuLH8tHwTCQYeptnHOUV7vA6px6j4zjjQwDx7TdP7kACPf3TLZLdJQ3CAD1XCvQ2sPhX+8tacvQ==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.25.tgz", - "integrity": "sha512-+ZVWud2HKh+Ob6k/qiJWjBtUg4KmJGGmbvEXXW1SNKS7hW7HU+Zq2ZCcE1akFxOPkVB+EhOty/sSek30tkCYug==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.25.tgz", - "integrity": "sha512-3OP/lwV3kCzEz45tobH9nj+uE4ubhGsfx+tn0L26WAGtUbmmcRpqy7XRG/qK7h1mClZ+eguIANcQntYMdYklfw==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.25.tgz", - "integrity": "sha512-+aKHdHZmX9qwVlQmu5xYXh7GsBFf4TWrePgeJTalhXHOG7NNuUwoHmketGiZEoNsWyyqwH9rE5BC+iwcLY30Ug==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.25.tgz", - "integrity": "sha512-aTLcE2VBoLydL943REcAcgnDi3bHtmULSXWLbjtBdtykRatJVSxKMjK9YlBXUZC4/YcNQfH7AxwVeQr9fNxPhw==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.25.tgz", - "integrity": "sha512-UxfenPx/wSZx55gScCImPtXekvZQLI2GW3qe5dtlmU7luiqhp5GWPzGeQEbD3yN3xg/pHc671m5bma5Ns7lBHw==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.25.tgz", - "integrity": "sha512-wLWYyqVfYx9Ur6eU5RT92yJVsaBGi5RdkoWqRHOqcJ38Kn60QMlcghsKeWfe9jcYut8LangYZ98xO1LxIoSXrQ==", - "dev": true, - "optional": true + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "license": "MIT" }, - "esbuild-linux-ppc64le": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.25.tgz", - "integrity": "sha512-0dR6Csl6Zas3g4p9ULckEl8Mo8IInJh33VCJ3eaV1hj9+MHGdmDOakYMN8MZP9/5nl+NU/0ygpd14cWgy8uqRw==", - "dev": true, - "optional": true + "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" }, - "esbuild-linux-riscv64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.25.tgz", - "integrity": "sha512-J4d20HDmTrgvhR0bdkDhvvJGaikH3LzXQnNaseo8rcw9Yqby9A90gKUmWpfwqLVNRILvNnAmKLfBjCKU9ajg8w==", - "dev": true, - "optional": true + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "esbuild-linux-s390x": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.25.tgz", - "integrity": "sha512-YI2d5V6nTE73ZnhEKQD7MtsPs1EtUZJ3obS21oxQxGbbRw1G+PtJKjNyur+3t6nzHP9oTg6GHQ3S3hOLLmbDIQ==", - "dev": true, - "optional": true + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } }, - "esbuild-netbsd-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.25.tgz", - "integrity": "sha512-TKIVgNWLUOkr+Exrye70XTEE1lJjdQXdM4tAXRzfHE9iBA7LXWcNtVIuSnphTqpanPzTDFarF0yqq4kpbC6miA==", - "dev": true, - "optional": true + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "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" + } }, - "esbuild-openbsd-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.25.tgz", - "integrity": "sha512-QgFJ37A15D7NIXBTYEqz29+uw3nNBOIyog+3kFidANn6kjw0GHZ0lEYQn+cwjyzu94WobR+fes7cTl/ZYlHb1A==", - "dev": true, - "optional": true + "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" }, - "esbuild-sunos-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.25.tgz", - "integrity": "sha512-rmWfjUItYIVlqr5EnTH1+GCxXiBOC42WBZ3w++qh7n2cS9Xo0lO5pGSG2N+huOU2fX5L+6YUuJ78/vOYvefeFw==", - "dev": true, - "optional": true + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" }, - "esbuild-windows-32": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.25.tgz", - "integrity": "sha512-HGAxVUofl3iUIz9W10Y9XKtD0bNsK9fBXv1D55N/ljNvkrAYcGB8YCm0v7DjlwtyS6ws3dkdQyXadbxkbzaKOA==", - "dev": true, - "optional": true + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } }, - "esbuild-windows-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.25.tgz", - "integrity": "sha512-TirEohRkfWU9hXLgoDxzhMQD1g8I2mOqvdQF2RS9E/wbkORTAqJHyh7wqGRCQAwNzdNXdg3JAyhQ9/177AadWA==", + "node_modules/rolldown": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.11.tgz", + "integrity": "sha512-NRjoKMusSjfRbSYiH3VSumlkgFe7kYAa3pzVOsVYVFY3zb5d7nS+a3KGQ7hJKXuYWbzJKPVQ9Wxq2UvyK+ENpw==", "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.25.tgz", - "integrity": "sha512-4ype9ERiI45rSh+R8qUoBtaj6kJvUOI7oVLhKqPEpcF4Pa5PpT3hm/mXAyotJHREkHpM87PAJcA442mLnbtlNA==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.122.0", + "@rolldown/pluginutils": "1.0.0-rc.11" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.11", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.11", + "@rolldown/binding-darwin-x64": "1.0.0-rc.11", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.11", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.11", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.11", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.11", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.11", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.11", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.11", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.11", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.11" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.11.tgz", + "integrity": "sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==", "dev": true, - "optional": true + "license": "MIT" }, - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "license": "MIT" }, - "follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==" + "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" + } }, - "form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "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==", "dev": true, + "license": "0BSD", "optional": true }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" - }, - "get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "requires": { - "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" - } - }, - "get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "requires": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - } - }, - "gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "license": "MIT" + }, + "node_modules/unplugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" - }, - "has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "requires": { - "has-symbols": "^1.0.3" + "node_modules/unplugin-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", + "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" } }, - "hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "requires": { - "function-bind": "^1.1.2" + "node_modules/vant": { + "version": "4.9.22", + "resolved": "https://registry.npmjs.org/vant/-/vant-4.9.22.tgz", + "integrity": "sha512-P2PDSj3oB6l3W1OpVlQpapeLmI6bXMSvPqPdrw5rutslC0Y6tSkrVB/iSD57weD7K92GsjGkvgDK0eZlOsXGqw==", + "license": "MIT", + "dependencies": { + "@vant/popperjs": "^1.3.0", + "@vant/use": "^1.6.0", + "@vue/shared": "^3.5.25" + }, + "peerDependencies": { + "vue": "^3.0.0" } }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "node_modules/vite": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.2.tgz", + "integrity": "sha512-1gFhNi+bHhRE/qKZOJXACm6tX4bA3Isy9KuKF15AgSRuRazNBOJfdDemPBU16/mpMxApDPrWvZ08DcLPEoRnuA==", "dev": true, - "requires": { - "has": "^1.0.3" + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.11", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "requires": { - "sourcemap-codec": "^1.4.8" + "node_modules/vue": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", + "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-sfc": "3.5.30", + "@vue/runtime-dom": "3.5.30", + "@vue/server-renderer": "3.5.30", + "@vue/shared": "3.5.30" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + "node_modules/vue-component-type-helpers": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-3.2.6.tgz", + "integrity": "sha512-O02tnvIfOQVmnvoWwuSydwRoHjZVt8UEBR+2p4rT35p8GAy5VTlWP8o5qXfJR/GWCN0nVZoYWsVUvx2jwgdBmQ==", + "license": "MIT" }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" + "node_modules/vue-i18n": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.3.0.tgz", + "integrity": "sha512-1J+xDfDJTLhDxElkd3+XUhT7FYSZd2b8pa7IRKGxhWH/8yt6PTvi3xmWhGwhYT5EaXdatui11pF2R6tL73/zPA==", + "license": "MIT", + "dependencies": { + "@intlify/core-base": "11.3.0", + "@intlify/devtools-types": "11.3.0", + "@intlify/shared": "11.3.0", + "@vue/devtools-api": "^6.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "vue": "^3.0.0" } }, - "nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==" - }, - "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 + "node_modules/vue-router": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.4.tgz", + "integrity": "sha512-lCqDLCI2+fKVRl2OzXuzdSWmxXFLQRxQbmHugnRpTMyYiT+hNaycV0faqG5FBHDXoYrZ6MQcX87BvbY8mQ20Bg==", + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.28.6", + "@vue-macros/common": "^3.1.1", + "@vue/devtools-api": "^8.0.6", + "ast-walker-scope": "^0.8.3", + "chokidar": "^5.0.0", + "json5": "^2.2.3", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "mlly": "^1.8.0", + "muggle-string": "^0.4.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "scule": "^1.3.0", + "tinyglobby": "^0.2.15", + "unplugin": "^3.0.0", + "unplugin-utils": "^0.3.1", + "yaml": "^2.8.2" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@pinia/colada": ">=0.21.2", + "@vue/compiler-sfc": "^3.5.17", + "pinia": "^3.0.4", + "vue": "^3.5.0" + }, + "peerDependenciesMeta": { + "@pinia/colada": { + "optional": true + }, + "@vue/compiler-sfc": { + "optional": true + }, + "pinia": { + "optional": true + } + } }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "postcss": { - "version": "8.4.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.8.tgz", - "integrity": "sha512-2tXEqGxrjvAO6U+CJzDL2Fk2kPHTv1jQsYkSoMeOis2SsYaXRO2COxTdQp99cYvif9JTXaAk9lYGc3VhJt7JPQ==", - "requires": { - "nanoid": "^3.3.1", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "node_modules/vue-router/node_modules/@vue/devtools-api": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.1.tgz", + "integrity": "sha512-bsDMJ07b3GN1puVwJb/fyFnj/U2imyswK5UQVLZwVl7O05jDrt6BHxeG5XffmOOdasOj/bOmIjxJvGPxU7pcqw==", + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^8.1.1" } }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "license": "MIT" }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, - "rollup": { - "version": "2.63.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.63.0.tgz", - "integrity": "sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" + "node_modules/yarn": { + "version": "1.22.22", + "resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.22.tgz", + "integrity": "sha512-prL3kGtyG7o9Z9Sv8IPfBNrWTDmXB4Qbes8A9rEzt6wkJV8mUvoirjU0Mp3GGAU06Y0XQyA3/2/RQFVuK7MTfg==", + "hasInstallScript": true, + "license": "BSD-2-Clause", + "bin": { + "yarn": "bin/yarn.js", + "yarnpkg": "bin/yarn.js" + }, + "engines": { + "node": ">=4.0.0" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - }, - "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 - }, - "vant": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/vant/-/vant-3.4.5.tgz", - "integrity": "sha512-3an2v6ejW9pijKmaDbSCW7Hs1R45tqtTIcedfI8hEAA5zC2Bp8cXU6Z4gUCK6/RAGOJsB+vcyLINLb1cGS/SzQ==", - "requires": { - "@vant/icons": "^1.7.1", - "@vant/popperjs": "^1.1.0", - "@vant/use": "^1.3.5" - } - }, - "vite": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-2.8.6.tgz", - "integrity": "sha512-e4H0QpludOVKkmOsRyqQ7LTcMUDF3mcgyNU4lmi0B5JUbe0ZxeBBl8VoZ8Y6Rfn9eFKYtdXNPcYK97ZwH+K2ug==", - "dev": true, - "requires": { - "esbuild": "^0.14.14", - "fsevents": "~2.3.2", - "postcss": "^8.4.6", - "resolve": "^1.22.0", - "rollup": "^2.59.0" - } - }, - "vue": { - "version": "3.2.31", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.31.tgz", - "integrity": "sha512-odT3W2tcffTiQCy57nOT93INw1auq5lYLLYtWpPYQQYQOOdHiqFct9Xhna6GJ+pJQaF67yZABraH47oywkJgFw==", - "requires": { - "@vue/compiler-dom": "3.2.31", - "@vue/compiler-sfc": "3.2.31", - "@vue/runtime-dom": "3.2.31", - "@vue/server-renderer": "3.2.31", - "@vue/shared": "3.2.31" - } - }, - "vue-i18n": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.9.tgz", - "integrity": "sha512-JeRdNVxS2OGp1E+pye5XB6+M6BBkHwAv9C80Q7+kzoMdUDGRna06tjC0vCB/jDX9aWrl5swxOMFcyAr7or8XTA==", - "requires": { - "@intlify/core-base": "9.1.9", - "@intlify/shared": "9.1.9", - "@intlify/vue-devtools": "9.1.9", - "@vue/devtools-api": "^6.0.0-beta.7" - } - }, - "vue-router": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.14.tgz", - "integrity": "sha512-wAO6zF9zxA3u+7AkMPqw9LjoUCjSxfFvINQj3E/DceTt6uEz1XZLraDhdg2EYmvVwTBSGlLYsUw8bDmx0754Mw==", - "requires": { - "@vue/devtools-api": "^6.0.0" - } - }, - "yarn": { - "version": "1.22.17", - "resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.17.tgz", - "integrity": "sha512-H0p241BXaH0UN9IeH//RT82tl5PfNraVpSpEoW+ET7lmopNC61eZ+A+IDvU8FM6Go5vx162SncDL8J1ZjRBriQ==" } } } diff --git a/rootfs/web/package.json b/rootfs/web/package.json index 178c079..f08aa64 100644 --- a/rootfs/web/package.json +++ b/rootfs/web/package.json @@ -8,17 +8,18 @@ "serve": "vite preview" }, "dependencies": { - "@icon-park/vue-next": "^1.3.6", - "axios": "^0.30.2", - "vant": "^3.4.5", - "vue": "^3.2.31", - "vue-i18n": "^9.1.9", - "vue-router": "^4.0.14", - "yarn": "^1.22.17" + "@element-plus/icons-vue": "^2.3.2", + "axios": "^1.13.6", + "element-plus": "^2.13.6", + "vant": "^4.9.22", + "vue": "^3.5.30", + "vue-i18n": "^11.3.0", + "vue-router": "^5.0.4", + "yarn": "^1.22.22" }, "devDependencies": { - "@vitejs/plugin-vue": "^2.2.4", - "@vue/compiler-sfc": "^3.2.31", - "vite": "^2.8.6" + "@vitejs/plugin-vue": "^6.0.5", + "@vue/compiler-sfc": "^3.5.30", + "vite": "^8.0.2" } } diff --git a/rootfs/web/src/.env b/rootfs/web/src/.env deleted file mode 100644 index cba474f..0000000 --- a/rootfs/web/src/.env +++ /dev/null @@ -1 +0,0 @@ -VITE_APP_BASE_API=/ \ No newline at end of file diff --git a/rootfs/web/src/assets/icons/drycc.svg b/rootfs/web/src/assets/icons/drycc.svg new file mode 100644 index 0000000..5a7cdca --- /dev/null +++ b/rootfs/web/src/assets/icons/drycc.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/rootfs/web/src/assets/icons/github.svg b/rootfs/web/src/assets/icons/github.svg new file mode 100644 index 0000000..dc2f59a --- /dev/null +++ b/rootfs/web/src/assets/icons/github.svg @@ -0,0 +1,8 @@ + + + + + GitHub icon + + + \ No newline at end of file diff --git a/rootfs/web/src/assets/icons/google.svg b/rootfs/web/src/assets/icons/google.svg new file mode 100644 index 0000000..e9f9e65 --- /dev/null +++ b/rootfs/web/src/assets/icons/google.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/rootfs/web/src/components/AccessTokenDelete.js b/rootfs/web/src/components/AccessTokenDelete.js index 0b1eb41..987cae4 100644 --- a/rootfs/web/src/components/AccessTokenDelete.js +++ b/rootfs/web/src/components/AccessTokenDelete.js @@ -1,5 +1,5 @@ import { reactive, toRefs } from 'vue' -import { Toast } from "vant"; +import { showSuccessToast } from "vant"; import {deleteAccessToken} from "../services/tokens"; export default { @@ -19,7 +19,7 @@ export default { const deleteToken = () => { deleteAccessToken(state.token.id).then(res=>{ if (res.status == 204) { - Toast.success("OK") + showSuccessToast("OK") context.emit('closeDelete', { hasAccessTokenDeleted: true }) } }) diff --git a/rootfs/web/src/components/AccessTokenDelete.vue b/rootfs/web/src/components/AccessTokenDelete.vue index 5420465..fe7c67d 100644 --- a/rootfs/web/src/components/AccessTokenDelete.vue +++ b/rootfs/web/src/components/AccessTokenDelete.vue @@ -1,31 +1,30 @@